TODO: archive landed items, empty Now/Next/Maintenance
This commit is contained in:
@@ -8,84 +8,19 @@ Longer-term direction lives in [ROADMAP.md](ROADMAP.md).
|
||||
|
||||
## Now
|
||||
|
||||
### Summarize the pruned span
|
||||
|
||||
Compaction now keeps the model's memory of a turn, but it still tells the model nothing about
|
||||
the messages it dropped, so a decision from forty messages ago can be contradicted with
|
||||
confidence.
|
||||
|
||||
- [x] Summarize the discarded messages before dropping them (`prune.droppedSpan` + `session.summarizeDiscarded`)
|
||||
- [x] Inject the summary in place of the count (`Note (retained from compacted history)` appended to history)
|
||||
- [x] Budget it: a summary that grows with the session defeats the point (6k excerpt + 3-6 lines, one call per compaction)
|
||||
- [x] Test: a pruned decision is still recoverable from the summary (`test/compact.test.ts` lossless suite)
|
||||
|
||||
### Hot-reload an installed entry
|
||||
|
||||
`/registry add` writes the file and says to restart. The skill catalogue and the guard chain
|
||||
are both assembled at boot, so a mid-session install does nothing until then.
|
||||
|
||||
- [x] Rebuild the skill list and plugin host after an install or removal (`Session.updateSkills/updatePlugins` + `cli.tsx` hot-reload)
|
||||
- [x] Leave a turn in flight alone: its rules must not change underneath it (`pendingSkills/pendingHost` + `drainPendingHotReload` at turn boundary)
|
||||
- [x] Test: a skill installed mid-session is callable in the next turn without a restart (`test/hot-reload.test.ts`)
|
||||
_Empty — pick from Known rough edges below._
|
||||
|
||||
---
|
||||
|
||||
## Next
|
||||
|
||||
### MCP without the schema tax
|
||||
|
||||
Every MCP tool's schema goes into the prompt today, so twenty tools from one server cost roughly
|
||||
2,750 tokens per request whether the model uses them or not. `toolSets` does not gate them.
|
||||
|
||||
phi solves this with three meta-tools — `mcp_list`, `mcp_inspect`, `mcp_call` — and a prompt that
|
||||
names only the servers. A hundred servers then cost almost nothing until one is called.
|
||||
|
||||
- [x] `mcp_list` / `mcp_inspect` / `mcp_call` replacing per-tool registration (`src/mcp.ts`: phi meta-tools, lazy list/inspect/call, `mcpExpose=phi`)
|
||||
- [x] The prompt lists server names, not schemas (`src/prompt.ts`: `mcpServers` names-only, direct schemas omitted under phi)
|
||||
- [x] Calls go through the same permission rules and guard as a built-in (`permission mcp_call` + `bindMcpGuard`, intra-turn suppressed, ask-to-approve otherwise)
|
||||
- [x] Keep per-tool registration as an option: a two-tool server is cheaper registered directly (`mcpExpose=direct` / `mcpExpose=auto`)
|
||||
- [x] Test: a configured server contributes no schema to the request until `mcp_call` (`test/mcp.test.ts` phi vs direct)
|
||||
|
||||
### Derive the tool-name lists
|
||||
|
||||
`TOOL_SETS` and `MUTATING_TOOLS` both list names by hand. A tool added to one and forgotten
|
||||
in the other is a silently ungated write, which is the worst kind of bug this codebase can
|
||||
have.
|
||||
|
||||
- [x] Mark each tool as mutating where it is defined, not in a list beside it (`src/tool-utils.ts` `withMeta({ set, mutating })`, each tool file wraps its `tool({` definitions — 41 tools across `tools.ts`/`tools-extra.ts`/`tools-git.ts`/`tools-net.ts`)
|
||||
- [x] `TOOL_SETS` covers every registered tool, checked rather than assumed (`setsFrom(tools)` derives from `_meta`, `TOOL_SETS`/`MUTATING_TOOLS` are derived, `DEFAULT_PERMISSIONS` covers all mutating)
|
||||
- [x] Test: a tool in no set, or a mutating tool outside `MUTATING_TOOLS`, fails the suite (`test/tool-derive.test.ts`: 5 tests — `_meta` present, `TOOL_SETS` derived + exact-once + coverage, `MUTATING_TOOLS` derived, permissions coverage, mutating consistency)
|
||||
|
||||
### Subagent parallelism
|
||||
|
||||
Two independent searches run sequentially. The panel already renders several agents; the loop
|
||||
does not fan out.
|
||||
|
||||
- [x] `task` accepts several investigations and runs them together (`src/subagent.ts`: `tasks: TaskSpec[]` union, `runOne` + `Promise.all` fan-out up to 8, panel emits start/step/result/end per subagent)
|
||||
- [x] Test: two delegated searches overlap in time rather than queueing (`test/subagent-parallel.test.ts`: delayed greps overlap < 2*delay, both headings in one tool result)
|
||||
|
||||
### Undo a turn
|
||||
|
||||
Every comparable CLI has this: opencode `/undo` and `/redo`, Claude Code `/rewind` with
|
||||
checkpoints. There is `/resume` here, which restores a session, and nothing that walks one back.
|
||||
|
||||
- [x] Snapshot files before each prompt, capped at the 100 most recent (`src/snapshot.ts` hook + `session.ts` per-turn capture, cap 100 via `SnapshotStack`)
|
||||
- [x] `/undo` restores files, conversation, or both; `/redo` reverses it (`src/commands.ts` + `src/session.ts` `undo()`/`redo()` + `src/ui/App.tsx` — files+messages together, redo replays tail)
|
||||
- [x] Say plainly what is not covered: a `bash` command's effects cannot be snapshotted (notice in undo/redo output + `src/snapshot.ts` doc)
|
||||
- [x] Test: an edit is reverted, and the model's own record of it goes with it (`test/undo.test.ts`: undo file+messages, redo file+messages, bash-not-snapshotted, cap 100)
|
||||
_Empty._
|
||||
|
||||
---
|
||||
|
||||
## Maintenance
|
||||
|
||||
- [x] Pricing table needs a source note and a date; rates drift and ours are hand-entered (`src/pricing.ts` `PRICING_VERIFIED_AT='2026-09-09'` + source URLs in doc, `/cost` shows `pricing verified: 2026-09-09 (est., verify before billing)`)
|
||||
- [x] `estimateTokens` divides JSON length by four. Good enough for a compaction threshold,
|
||||
wrong enough to mislead in `/cost`. Either label it an estimate everywhere or use a
|
||||
real tokenizer (`src/prune.ts` doc now says heuristic + `(est.)` label, `src/session.ts`/`src/ui/panel-bodies.ts`/`src/ui/App.tsx` all display `~N tokens (est.)` / `~N est. in context`)
|
||||
- [x] `listPaths` walks up to 5000 files once per session. Fine for a repo, wasteful in a
|
||||
monorepo, and it never notices a file created after the first `@` (`src/session.ts` `fileChangeSeq` bumped on `recordBeforeWrite` + `restoreFiles`, `src/ui/App.tsx` invalidates `paths` on seq change so next `@` re-walks)
|
||||
- [x] `MUTATING_TOOLS` is now only used by tests and docs; the permission defaults are what
|
||||
actually gate a write. Either delete it or make the defaults derive from it (`src/permission.ts` `BASE_PERMISSIONS` + `buildDefaults()` derives mutating entries from `tools.ts` `MUTATING_TOOLS` via `require('./tools')` — `_meta.mutating` single source, fallback list if require fails)
|
||||
_All caught up._
|
||||
|
||||
---
|
||||
|
||||
@@ -118,7 +53,9 @@ Not bugs exactly, but things that will bite someone.
|
||||
|
||||
## Done
|
||||
|
||||
Kept for one release, then deleted. The 1.0.0 release batch:
|
||||
Kept for one release, then deleted.
|
||||
|
||||
### 1.0.0 release batch
|
||||
|
||||
- [x] A spend ceiling (`maxSpendUsd`): checked before each turn, refused at 100% naming the
|
||||
ceiling, warns once at 80%, headless exits non-zero. Unpriced models are not enforced
|
||||
@@ -140,3 +77,18 @@ Kept for one release, then deleted. The 1.0.0 release batch:
|
||||
- [x] The system prompt advanced: a failure-recovery loop, a delegation policy, compaction awareness
|
||||
- [x] The release workflow's dead `dry_run` input wired: manual dispatch publishes only when
|
||||
unchecked, tag pushes always publish
|
||||
|
||||
### Post-1.0 — Now / Next / Maintenance (landed)
|
||||
|
||||
- [x] Summarize the pruned span — `prune.droppedSpan` + `session.summarizeDiscarded`, injected as `Note (retained from compacted history)`, budgeted 6k excerpt + 3–6 lines, one call per compaction (`test/compact.test.ts`)
|
||||
- [x] Hot-reload an installed entry — `Session.updateSkills/updatePlugins` + `cli.tsx` hot-reload, `pendingSkills/pendingHost` + `drainPendingHotReload` at turn boundary (`test/hot-reload.test.ts`)
|
||||
- [x] MCP without the schema tax — `mcp_list` / `mcp_inspect` / `mcp_call` phi meta-tools, prompt names-only, permission `mcp_call` + `bindMcpGuard`, `mcpExpose=phi|direct|auto` (`test/mcp.test.ts`)
|
||||
- [x] Derive the tool-name lists — `withMeta({ set, mutating })`, `setsFrom(tools)` derives `TOOL_SETS`/`MUTATING_TOOLS`/`DEFAULT_PERMISSIONS` (`test/tool-derive.test.ts`)
|
||||
- [x] Subagent parallelism — `task` fans out `tasks: TaskSpec[]` via `Promise.all` up to 8 (`test/subagent-parallel.test.ts`)
|
||||
- [x] Undo a turn — `src/snapshot.ts` per-turn capture cap 100, `/undo` + `/redo` files+messages (`test/undo.test.ts`)
|
||||
- [x] Pricing source + date — `PRICING_VERIFIED_AT='2026-09-09'` + source URLs, `/cost` shows `pricing verified: 2026-09-09 (est.)`
|
||||
- [x] `estimateTokens` labelling — heuristic doc + `(est.)` in `/cost` + `~N est. in context`
|
||||
- [x] `listPaths` stale walk — `fileChangeSeq` on `recordBeforeWrite`/`restoreFiles`, `@` invalidates `paths` on seq change
|
||||
- [x] `MUTATING_TOOLS` derivation — `BASE_PERMISSIONS` + `buildDefaults()` derives from `MUTATING_TOOLS` via `require('./tools')`
|
||||
- [x] Unknown `toolSets` silently dropped — `unknownToolSetNames()` + startup notice `unknown toolSets ignored: …` (`test/config-toolsets.test.ts`, `5028ea6`)
|
||||
- [x] `@` directories — `walk({ includeDirs: true })` yields `src/` with trailing `/`, `matchPaths` ranks dirs before files (`test/complete-dirs.test.ts`, `4b4ddd0`)
|
||||
|
||||
Reference in New Issue
Block a user