Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ reading it could predict its subject's take on a new topic.**
or [`STYLE.template.md`](../STYLE.template.md), improve a `_GUIDE.md`, fix a
factual error or broken link.

Build your soul first with the [soul-builder skill](../SKILL.md) (`/soul-builder`)
or by hand from the templates. See [`examples/_GUIDE.md`](../examples/_GUIDE.md)
for what goes in the calibration files.
Build your soul first with the [soul-builder skill](../BUILD.md) (`/soul-builder`)
or by hand from the templates — [`BUILD.md`](../BUILD.md) is the full spec for
what a soul folder must contain. See [`examples/_GUIDE.md`](../examples/_GUIDE.md)
for what goes in the calibration files, and [`data/_GUIDE.md`](../data/_GUIDE.md)
for what belongs in `data/`.

## Before you start

Expand Down
16 changes: 8 additions & 8 deletions .github/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,14 @@ Soul files are plain markdown — if an agent can read files, it can embody you.
| Framework | Language | Stars |
|-----------|----------|-------|
| [Aeon](https://github.com/aeonfun/aeon) | YAML/Markdown | — |
| [OpenClaw](https://github.com/openclaw/openclaw) | TypeScript | 322k |
| [Nanobot](https://github.com/HKUDS/nanobot) | Python | 34.6k |
| [ZeroClaw](https://github.com/zeroclaw-labs/zeroclaw) | Rust | 27.8k |
| [PicoClaw](https://github.com/sipeed/picoclaw) | Go | 25.3k |
| [NanoClaw](https://github.com/qwibitai/nanoclaw) | TypeScript | 24k |
| [OpenFang](https://github.com/RightNow-AI/openfang) | Rust | 14.9k |
| [IronClaw](https://github.com/nearai/ironclaw) | Rust | 10.4k |
| [Hermes Agent](https://github.com/NousResearch/hermes-agent) | Python | 8.7k |
| [OpenClaw](https://github.com/openclaw/openclaw) | TypeScript | 383k |
| [Hermes Agent](https://github.com/NousResearch/hermes-agent) | Python | 218k |
| [Nanobot](https://github.com/HKUDS/nanobot) | Python | 46k |
| [ZeroClaw](https://github.com/zeroclaw-labs/zeroclaw) | Rust | 32.3k |
| [NanoClaw](https://github.com/qwibitai/nanoclaw) | TypeScript | 30.3k |
| [PicoClaw](https://github.com/sipeed/picoclaw) | Go | 29.7k |
| [OpenFang](https://github.com/RightNow-AI/openfang) | Rust | 18k |
| [IronClaw](https://github.com/nearai/ironclaw) | Rust | 12.5k |
| Claude Code · OpenCode · Codex · Goose | various | — |

Also works with any model via system prompt — see [Using With Other Tools](#using-with-other-tools).
Expand Down
3 changes: 2 additions & 1 deletion .github/SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ that part isn't a secret and we'd rather act on it fast.

Please include what you can:

- The file or component affected — `SKILL.md` (the builder), a `scripts/*.mjs`
- The file or component affected — `BUILD.md` (the builder), `SKILL.md` (the
embodier), a `scripts/*.mjs`
helper, a template, or a specific `examples/<name>/` soul.
- A minimal reproduction (for injection: the source text that triggers it).
- The impact you can demonstrate.
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
.DS_Store
__pycache__/
*.pyc
3 changes: 1 addition & 2 deletions .markdownlint-cli2.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,5 @@
"MD053": true, // every link/image reference definition must be used
"MD054": true // disallowed malformed link/image styles
},
"globs": ["**/*.md"],
"ignores": ["node_modules"]
"globs": ["**/*.md"]
}
1 change: 1 addition & 0 deletions BUILD.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ When done, you should have created:
- `STYLE.md` — Their voice
- `MEMORY.md` — Empty memory log
- `examples/good-outputs.md` — Calibration examples
- `examples/bad-outputs.md` — Negative calibration examples
- Optionally: `data/influences.md` if built from interview

The user can then invoke `/soul` to embody their digital identity.
19 changes: 10 additions & 9 deletions examples/garry-tan/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,17 @@

A `soul.md` identity distillation for Garry Tan — co-founder of Posterous, founding partner of Initialized Capital, president and CEO of Y Combinator.

This folder is structured to be dropped into `aeonfun/soul.md` at `examples/garry-tan/`.

## What's in here

```
garrytan/
garry-tan/
├── SOUL.md ← Identity, worldview, opinions
├── STYLE.md ← Voice mechanics
├── MEMORY.md ← Empty session log
├── data/
│ ├── influences.md
│ ├── x/ ← Twitter archive target (see scripts/)
│ ├── writing/ ← YC blog + personal essays
│ └── yt/ ← YouTube transcripts
│ └── influences.md
│ ← x/, writing/, yt/ are created by scripts/ on first run
├── examples/
│ ├── good-outputs.md ← 12 calibration samples
│ └── bad-outputs.md ← 10 anti-patterns
Expand All @@ -24,8 +21,12 @@ garrytan/
│ ├── fetch_writing.py ← YC blog + personal posts → data/writing/
│ └── fetch_yt.py ← YouTube transcripts → data/yt/*.md
└── tests/
├── prediction_test.md ← 10 unseen prompts + expected takes
└── weak_model_test.md ← gpt-4o-mini run + verdict
├── prediction_test.md ← 10 unseen prompts + expected takes
├── platform_tests.md ← 3 platform-shape prompts
├── weak_model_test.md ← protocol + verdict
├── run_weak_model.py ← the harness
├── results_gpt-4o-mini.md ← full transcript
└── scores_gpt-4o-mini.md ← per-prompt grades (38.5/48 PASS)
```

## How to rebuild the corpus
Expand All @@ -46,7 +47,7 @@ python scripts/fetch_yt.py

```bash
# From a project root, copy into a /soul directory and invoke
claude --skill soul "write a tweet reacting to the latest OpenAI announcement"
/soul write a tweet reacting to the latest OpenAI announcement
```

The SKILL.md from the parent `soul.md` repo handles the embodiment logic.
Expand Down
6 changes: 0 additions & 6 deletions examples/garry-tan/scripts/fetch_x.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,16 @@
import json
import os
import pathlib
import re
import sys
import time
import urllib.parse
import urllib.request

HANDLE = "garrytan"
USER_ID = "19301828" # @garrytan, stable numeric id
OUT = pathlib.Path(__file__).parent.parent / "data" / "x"
OUT.mkdir(parents=True, exist_ok=True)


def _slug(s: str, n: int = 40) -> str:
return re.sub(r"[^a-z0-9]+", "-", s.lower()).strip("-")[:n]


def _write(tweet_id: str, date: str, text: str, source: str, reply_to: str | None) -> None:
safe_date = date.split("T", 1)[0]
path = OUT / f"{safe_date}_{tweet_id}.md"
Expand Down
17 changes: 5 additions & 12 deletions examples/garry-tan/tests/run_weak_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
"""
Run the soul file against a weak model via OpenRouter.

Reads OPENROUTER_API_KEY from env (or from ~/.hermes/.env as a fallback).
Reads OPENROUTER_API_KEY from env.
Writes a markdown transcript with one section per prompt.

Requires `certifi` (pip install certifi).

Usage:
python tests/run_weak_model.py \
--model openai/gpt-4o-mini \
Expand All @@ -21,7 +23,6 @@
import pathlib
import sys
import ssl
import urllib.error
import urllib.request

import certifi
Expand Down Expand Up @@ -89,11 +90,6 @@ def load_api_key() -> str:
key = os.environ.get("OPENROUTER_API_KEY")
if key:
return key
fallback = pathlib.Path.home() / ".hermes" / ".env"
if fallback.exists():
for line in fallback.read_text().splitlines():
if line.startswith("OPENROUTER_API_KEY="):
return line.split("=", 1)[1].strip()
sys.exit("OPENROUTER_API_KEY not found")


Expand All @@ -119,11 +115,8 @@ def call_model(api_key: str, model: str, system: str, user: str) -> str:
"X-Title": "soul-garrytan weak-model test",
},
)
try:
with urllib.request.urlopen(req, timeout=90, context=_SSL_CTX) as resp:
data = json.loads(resp.read())
except urllib.error.HTTPError as e:
return f"[ERROR {e.code}: {e.read().decode(errors='replace')}]"
with urllib.request.urlopen(req, timeout=90, context=_SSL_CTX) as resp:
data = json.loads(resp.read())
return data["choices"][0]["message"]["content"]


Expand Down
65 changes: 15 additions & 50 deletions examples/garry-tan/tests/weak_model_test.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,20 @@ For each response, grade:
- **Stance match**: 0–2 (opinion aligned with SOUL.md)
- **Anti-pattern hits**: subtract 1 per `bad-outputs.md` tell that appears (e.g., "that's a great question," emoji spam, hedging stack).

Formula: `score = (voice + stance) - anti_pattern_hits`. Max 4 per prompt. Pass threshold: **average ≥ 3.0 across 13 prompts**.
Formula: `score = (voice + stance) - anti_pattern_hits`. Max 4 per prompt. Pass threshold: **average ≥ 3.0 across 12 prompts**.

### 5. Run script

```bash
# OPENAI_API_KEY required
python tests/run_weak_model.py \
--model gpt-4o-mini \
--prompts tests/prediction_test.md,tests/platform_tests.md \
--soul /tmp/garry_prompt.md \
OPENROUTER_API_KEY=... python3 tests/run_weak_model.py \
--model openai/gpt-4o-mini \
--soul SOUL.md --style STYLE.md \
--good examples/good-outputs.md --bad examples/bad-outputs.md \
--out tests/results_gpt-4o-mini.md
```

`run_weak_model.py` is a 30-line stub below.
The prompts are defined in `run_weak_model.py` itself; `--style`, `--good`, and
`--bad` are required.

---

Expand Down Expand Up @@ -107,55 +107,20 @@ The three things that usually break weak-model adherence:

---

## Run script (reference implementation)

```python
# tests/run_weak_model.py
import argparse, json, os, re, sys
from openai import OpenAI

ap = argparse.ArgumentParser()
ap.add_argument("--model", default="gpt-4o-mini")
ap.add_argument("--soul", required=True)
ap.add_argument("--prompts", required=True) # comma-sep .md files
ap.add_argument("--out", required=True)
args = ap.parse_args()

client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
soul = open(args.soul).read()
prompts = []
for f in args.prompts.split(","):
prompts += re.findall(r"^## \d+\..*?\n(.*?)(?=\n---|\Z)", open(f).read(), re.S|re.M)

system = (
"You are Garry Tan. Embody the identity below. Never break character. "
"Match the voice in good-outputs.md, avoid bad-outputs.md.\n\n"
f"<IDENTITY>\n{soul}\n</IDENTITY>"
)

with open(args.out, "w") as out:
for i, p in enumerate(prompts, 1):
resp = client.chat.completions.create(
model=args.model,
messages=[
{"role": "system", "content": system},
{"role": "user", "content": p.strip()},
],
temperature=0.7,
)
out.write(f"## Prompt {i}\n\n{p.strip()}\n\n**Response:**\n\n{resp.choices[0].message.content}\n\n---\n\n")
print(f"wrote → {args.out}", file=sys.stderr)
```
## Run script

Run it, grade it, commit the result. A passing run is part of the deliverable.
The harness is [`run_weak_model.py`](run_weak_model.py) — argparse CLI, OpenRouter
via `urllib`, prompts defined in the script. Run it, grade it, commit the result.

---

## Status

- ✅ Protocol defined
- ✅ Prompts authored (prediction_test.md + platform_tests.md)
- ✅ Run script reference implementation (above — saveable as-is)
- ⏳ Live run pending: requires `OPENAI_API_KEY`. Grading is manual until we add an LLM-judge step.
- ✅ Run script shipped: `tests/run_weak_model.py`
- ✅ Live run 2026-04-14 on `openai/gpt-4o-mini`: 38.5/48 (PASS). Full transcript
in [`results_gpt-4o-mini.md`](results_gpt-4o-mini.md), per-prompt grades in
[`scores_gpt-4o-mini.md`](scores_gpt-4o-mini.md).

When run live, append actual transcript + scores below.
Grading is manual until we add an LLM-judge step.
4 changes: 2 additions & 2 deletions examples/karpathy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ Karpathy writes like a teacher who builds. Short sentences. Specific technical a
- **Identity** — who he is, the throughline (build from scratch to understand, teach by building)
- **12 worldview items** — using his own language and phrasing, with tweet-style direct quotes
- **5 modes** — The Teacher, The Hacker/Builder, The ML Philosopher, The Industry Insider, The Nerd
- **Tensions & contradictions (8)** — the self-aware paradoxes: safety-concerned but anti-pause, YC-world-adjacent but not a founder personality, demystifier who calls neural nets "magical," etc. (This is the "range" the task brief asked for.)
- **Tensions & contradictions (8)** — the self-aware paradoxes: safety-concerned but anti-pause, YC-world-adjacent but not a founder personality, demystifier who calls neural nets "magical," etc.
- **Boundaries** — what he won't do (partisan politics, doomer takes, hype)
- **Pet peeves** — frameworks that hide the code, "it's just X" dismissals, confident timelines

Expand Down Expand Up @@ -115,7 +115,7 @@ Re-run the pipeline to refresh:

```bash
bash scripts/fetch-data.sh # blogs + YouTube + GitHub
SURF_API_KEY=sk-surf-... node ../../pull-x.mjs # X refresh (see data/x/README.md)
SURF_API_KEY=sk-surf-... node ../steipete/scripts/pull-x.mjs # X refresh (see data/x/README.md)
```

---
Expand Down
Loading