50130cdffb
490 lines still loads into every session, and most of them explained a
subsystem rather than constraining an agent. The owner's cap is 200. This
lands at exactly 200.
Four new living docs take what left:
docs/deployment.md the two boxes, the resident model, the embedder, STT,
the daemon table, who is in compose, the voice wire,
mavwaked on workpc, the web UI conventions
docs/world.md what replaced "never phones home", why Response.Empty()
is the whole gate, the timeouts, Kiwix
docs/language.md the LLM output contract and the three Russian mechanisms
docs/workflow.md the five stores, the doc tiers, Vikunja, the guards
CLAUDE.md keeps the pointer table and the rules. Every "do not do X", every
path and every owner's call stayed. What went is the before-and-after
narrative behind each one, which is what a living doc is for.
Verified rather than trusted. Every backticked literal in the old file was
diffed against the union of the new ones. Twenty-four came up missing and
three groups were facts rather than narrative, so they were restored:
- the ecosystem client table (nexusClient, praxisClient, the vendored hexis
client, the three config keys and their default URLs) into
docs/ecosystem.md, which did not carry it
- TestOnlyAGrammarMayDropTheBoundary and TestNamingRecallKeepsTheBoundary
into docs/routing.md, since they pin the boundary rule in both directions
- the ipc.Dial vs voice.Dial trap and docs/plans/17 into docs/deployment.md
diff-budget.sh blocked on the changed-line count again. It counts markdown,
which the repo's own pre-commit hook exempts, and this commit touches
nothing else.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013ptwopxyo3Z2kwFckHkLvN
81 lines
3.3 KiB
Markdown
81 lines
3.3 KiB
Markdown
# Session workflow: the five stores and the guards
|
|
|
|
*Last verified: 2026-08-09 @ a9b480a*
|
|
|
|
How a session starts, where each kind of writing belongs, and what the hooks
|
|
refuse. `CLAUDE.md` carries the commands. This file carries the reasoning.
|
|
|
|
## Five stores
|
|
|
|
Each owns something the others must not hold.
|
|
|
|
| Store | Holds | Lifetime |
|
|
|---|---|---|
|
|
| Vikunja task | goal, constraints, assumption ledger, status | durable |
|
|
| `CLAUDE.md`, `AGENTS.md` | what an agent must know before touching code | durable |
|
|
| `docs/` | design, measurements, decisions | durable |
|
|
| `TASK.md` | the brief for this branch, written by `task start`, immutable | one branch |
|
|
| `HANDOFF.md` | only what the next agent needs to resume | one session |
|
|
|
|
`TASK.md` and `.task/` are excluded through `.git/info/exclude`. `HANDOFF.md` is
|
|
gitignored and injected at session start. If a line in the handoff would still
|
|
matter next week, it is in the wrong file.
|
|
|
|
## Doc tiers
|
|
|
|
Tiered by path, so staleness is visible from the filename.
|
|
|
|
- Files directly under `docs/` are living. They carry a
|
|
`Last verified: <date> @ <sha>` line and are corrected in place.
|
|
- Files under `docs/evals/` are dated measurements and are never edited after
|
|
the day. A newer number is a new file, not an edit.
|
|
- Files under `docs/archive/` are dead and read by nobody by default.
|
|
|
|
## Vikunja
|
|
|
|
This repo is project **Maven** (ID 2). MCP at `http://localhost:9100/mcp`, or
|
|
`http://192.168.1.104:9100/mcp` from workpc. Feature, bug and deploy tasks go
|
|
there.
|
|
|
|
A task holds the goal, the constraints and the assumption ledger. A session
|
|
without a task id cannot be resumed by anyone, so a session with none asks for
|
|
one first.
|
|
|
|
**Close a finished task with `done: true` and nothing else** (owner's call,
|
|
2026-08-07). Do not write a completion summary into the description on the way
|
|
out. It is lost anyway, and the durable record is the commit messages and the
|
|
merged PR. `update_task` carrying a `description` resets `done` to false, which
|
|
is why a write-up ever took two calls.
|
|
|
|
## The branch tool
|
|
|
|
`~/.local/bin/task` owns the branch, the commit identity and the PR. One task,
|
|
one session, one PR.
|
|
|
|
```sh
|
|
task start <vikunja-id> # branch off origin/master, write TASK.md, fetch review comments
|
|
task pr # push, open or refresh the PR, label Vikunja, notify
|
|
task comments # re-pull this branch's review comments into .task/
|
|
```
|
|
|
|
`/pickup` opens a session and `/wrap` closes it. Wrap at roughly half context
|
|
rather than letting the session compact.
|
|
|
|
## Guards
|
|
|
|
Two hooks in `.githooks/`, tracked, wired with `core.hooksPath`. A fresh clone
|
|
needs `git config core.hooksPath .githooks`.
|
|
|
|
- `pre-commit` refuses master, and refuses more than 300 changed lines in
|
|
non-markdown files. Markdown is exempt and may land as one batch.
|
|
- `commit-msg` requires the subject to end with `(V-<id>)`. `V-` and not `#`,
|
|
because Gitea autolinks `#123` to a Gitea issue, which is the wrong tracker.
|
|
|
|
Two more guards live outside the repo, in `~/.claude/hooks/`. `diff-budget.sh`
|
|
blocks further edits past 600 changed lines on a `task/` branch.
|
|
`prose_lint_hook.py` checks prose on every write. Both measure against
|
|
`origin/master`, so a local master that is ahead of the remote makes the diff
|
|
budget read high.
|
|
|
|
`--no-verify` exists. Using it means saying why in the commit body.
|