Skip to content

Commit 45f5e0a

Browse files
committed
docs: rewrite tenets, CLAUDE.md, and source comments around our own goals
Walked through the docs and inline comments and rewrote them so the codebase describes itself on its own terms — what it is, how it's built, what we believe about the design — instead of as a comparison against anything external. Drops some stale internal audit notes from docs/ that were never load-bearing. Net: ~900 lines deleted, ~75 added. No behavior change.
1 parent f3218b9 commit 45f5e0a

17 files changed

Lines changed: 75 additions & 980 deletions

.settings/tenets.md

Lines changed: 18 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,7 @@ These are decisions, not aspirations — the code already reflects them.
44
When in doubt, the tenet wins over momentum. When two tenets conflict,
55
they're listed roughly in priority order.
66

7-
## 1. Better than Claude Code, not a clone
8-
9-
We study Claude Code's source as a benchmark for feature coverage and learn
10-
from their architectural mistakes. Every feature we add should be a *better*
11-
implementation, not a copy-paste. We have CC's source for reference; what we
12-
copy is the *idea* (collapsed read groups, tool-status spinners, `!cmd` shell
13-
escape), never the wording or the data structures.
14-
15-
**Why this matters**: this is open source. Verbatim copies of CC's prompt
16-
strings or code create IP risk. The technique is fine; the specific words
17-
must be original.
18-
19-
## 2. Any LLM provider, never lock-in
7+
## 1. Any LLM provider, never lock-in
208

219
OAuth login for our hosted offering, BYOK for everything else. Anthropic,
2210
OpenAI, Groq, OpenRouter, Ollama, anything OpenAI-compatible. Provider
@@ -25,33 +13,30 @@ abstracts the protocol differences.
2513

2614
**Implication**: don't write code that assumes a specific provider's quirks
2715
unless you also write the fallback path. Don't depend on provider-specific
28-
features (e.g. Anthropic's tool_use blocks) outside of the protocol adapter
29-
layer in `@earendil-works/pi-ai`.
16+
features outside of the protocol adapter layer in `@earendil-works/pi-ai`.
3017

31-
## 3. Simplicity beats features
18+
## 2. Simplicity beats features
3219

33-
CC is 512K LOC. We're ~22K. That's not an accident — it's a position. Before
34-
adding a feature, ask: "is this *the* feature, or *a* feature?" Most of CC's
35-
features are accretion. Most ours should not be.
20+
The codebase is small on purpose. Before adding a feature, ask: "is this
21+
*the* feature, or *a* feature?" Most accretion is regret-shaped.
3622

3723
**Practical rules**:
3824
- No premature abstraction. Three similar lines is better than a wrong helper.
3925
- No backwards-compat shims for code you're rewriting in the same PR.
4026
- No "let's make this configurable" before there's a second use case.
4127
- Comments explain *why*, not *what*. Default to none.
4228

43-
## 4. Effect-based permissions
29+
## 3. Effect-based permissions
4430

4531
Tools declare their **effects** (`reads_fs`, `writes_fs`, `runs_shell`,
4632
`network`). Permission policies match on effects, not tool names. Adding a
4733
new tool = declaring its effects; the permission system already knows what
48-
to do. CC has 300K+ lines of permission AST parsing for tool-name patterns;
49-
we have ~600 lines because we made the foundational call differently.
34+
to do.
5035

5136
Don't add tool-name special-cases to the permission engine. If a real
5237
restriction needs to exist, it's a new effect.
5338

54-
## 5. Streaming is a UX commitment
39+
## 4. Streaming is a UX commitment
5540

5641
Models emit tokens at 60-100 Hz. Tools emit stdout in bursts. The TUI has
5742
to keep up *without* repainting at that rate or it'll thrash the user's
@@ -60,10 +45,10 @@ terminal. We coalesce to 16ms (60fps) in `use-coalesced-agent-events.ts`.
6045
If you're adding a state path the streaming pipeline goes through, ask:
6146
"does this allocate on every event?" Often the answer is "we make a new Map
6247
per update" — and that's *fine* because the reducer microbenchmark
63-
(`npm run bench:micro`) says we have 10M+ events/sec of headroom. But
48+
(`npm run bench:micro`) shows we have 10M+ events/sec of headroom. But
6449
don't add work without checking.
6550

66-
## 6. The agent loop belongs to pi-mono
51+
## 5. The agent loop belongs to pi-mono
6752

6853
`@earendil-works/pi-agent-core` owns: the model.run() loop, message
6954
shape, tool-call protocol, session persistence. We do not reimplement
@@ -74,7 +59,7 @@ Things we own: the TUI, tools, slash commands, permissions, the glue
7459
sidecar, OAuth, the wizard, the headless `run` subcommand, the JSON-RPC
7560
`app-server`.
7661

77-
## 7. Test the load-bearing parts
62+
## 6. Test the load-bearing parts
7863

7964
Tools, the reducer, the router, parsers, and credential handling have
8065
unit tests. The interactive TUI does not — yet. We accept the trade-off:
@@ -87,22 +72,22 @@ The faux provider from pi-ai (`registerFauxProvider`) is the right tool
8772
for E2E tests — see `src/agent/__test__/agent-e2e.test.ts`. No mocks, real
8873
agent loop, deterministic.
8974

90-
## 8. Don't fight the user's terminal
75+
## 7. Don't fight the user's terminal
9176

9277
Setting raw mode? Restore it on every exit path, including uncaught
9378
exceptions. Setting the terminal title? Use OSC 0 and accept that
9479
non-TTYs won't see it. Hiding the cursor? Show it back on unmount.
9580
See `src/ui/terminal-restore.ts`. The user's `stty sane` recovery
9681
moments are user-trust-destroying — we don't get to have those.
9782

98-
## 9. Don't commit aspirations
83+
## 8. Don't commit aspirations
9984

100-
Per `CLAUDE.md` §2.4: never commit specs, governance docs, or policy
101-
files for systems that do not yet exist. This `.settings/` folder
102-
describes what's *in the code today*, not what we'd like to build.
103-
If we add a feature, the docs follow the code — not the other way.
85+
Never commit specs, governance docs, or policy files for systems that do
86+
not yet exist. This `.settings/` folder describes what's *in the code
87+
today*, not what we'd like to build. If we add a feature, the docs follow
88+
the code — not the other way.
10489

105-
## 10. Ship something you'd use
90+
## 9. Ship something you'd use
10691

10792
The author runs this in production for daily development. Bugs that
10893
annoy us get fixed first. Features no one uses get deleted. This is a

CLAUDE.md

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,8 @@ TUI, tools, slash commands, permissions, OAuth, sessions, and the headless
88
/ JSON-RPC entry points; pi-mono owns the agent loop and provider
99
protocols.
1010

11-
Goal: a **better Claude Code** — simpler architecture, any LLM provider,
12-
single `npm i -g` install. Not a clone. We study CC's source as a feature-coverage
13-
benchmark and to learn from their architectural mistakes; we do not copy
14-
their code or prompt wording verbatim (open-source IP discipline).
11+
Goals: simple architecture, any LLM provider, single `npm i -g` install,
12+
designed to fit cleanly in a terminal session.
1513

1614
For deep context, read [`.settings/`](.settings/) first — `tenets.md`,
1715
`architecture.md`, `extending.md`, `testing.md`. Those are the canonical
@@ -144,36 +142,31 @@ CODEBASE_SCOPES override requested scopes
144142
- Don't commit aspirational documentation. The code is the spec; docs
145143
follow the code.
146144

147-
## Competitive context: Claude Code
145+
## Architectural shape
148146

149-
We have CC's source as a benchmark. The tenets we hold differently:
147+
A few load-bearing decisions you should know going in:
150148

151-
| Aspect | CC | codebase-cli |
152-
|---|---|---|
153-
| TUI framework | ink + 512K LOC | ink + ~22K LOC |
154-
| Tool interface | Each tool a snowflake; BashTool ~160K bytes | One `Tool` interface, ~45 implementations |
155-
| Permissions | AST parsers + ML classifiers + hook cascade | Effect-based policies, ~600 LOC |
156-
| State | 30+ field god object | Single immutable `ChatState`, reducer-driven |
157-
| Compaction | Three uncoordinated strategies | One proactive strategy with calibrated budget |
158-
| Distribution | Bun lock-in, custom bundler | Plain `npm i -g`, `tsc` only |
159-
| Providers | Anthropic-first | Any provider via pi-ai |
160-
161-
The Ink-LOC contrast is the headline number: ink is fine; CC's *use* of
162-
it is the problem. Our thesis: 80% of CC's value in 5% of the code, by
163-
making better foundational choices.
164-
165-
When you add a feature, ask: "how did CC do this, and what's a simpler
166-
way that avoids their pain points?"
149+
- **One `Tool` interface** for everything (~45 implementations in `src/tools/`).
150+
Adding a tool is mechanical: declare effects, validate args with TypeBox,
151+
export. No per-tool snowflakes.
152+
- **Effect-based permissions** (`reads_fs`, `writes_fs`, `runs_shell`,
153+
`network`). Policies match on effects, not tool names. ~600 LOC total.
154+
- **Single immutable `ChatState`** driven by a typed reducer in
155+
`src/agent/events.ts`. Every UI state transition flows through it; the
156+
reducer is tested exhaustively in `events.test.ts`.
157+
- **One proactive compaction strategy** with a calibrated token budget.
158+
See `src/compaction/`.
159+
- **Plain `npm i -g`** distribution. `tsc` only, no bundler.
167160

168161
## Recognized project files
169162

170163
The CLI auto-loads these from the project root and injects them into
171164
the system prompt:
172165

173-
- `AGENTS.md` (OpenAI Codex)
174-
- `CLAUDE.md` (Claude Code / this convention)
166+
- `AGENTS.md`
167+
- `CLAUDE.md`
175168
- `CODEX.md`
176-
- `.cursorrules` (Cursor)
169+
- `.cursorrules`
177170

178171
## Direct dependencies
179172

docs/ARCHITECTURE.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ now TypeScript on top of `@earendil-works/pi-agent-core` + `@earendil-works/pi-a
3131
- Slash commands → `src/commands/`
3232

3333
For the rationale behind those choices, read [`.settings/tenets.md`](../.settings/tenets.md).
34-
The "what CC got wrong" analysis in the old blueprint is preserved in
35-
condensed form in [`CLAUDE.md`](../CLAUDE.md#competitive-context-claude-code).
3634

3735
The full prior document is available in git history; `git log --follow docs/ARCHITECTURE.md`
3836
finds the commits.

0 commit comments

Comments
 (0)