AGENTS.md · diff
git:20260913.1d0272e to git:20260916.7668e1e
93 added, 468 removed. Audit B to A.
# radin — Agent Reference
- > Read this before touch any file in repo.
-
- ---
-
- ## Project
-
- | Field | Value |
- | --- | --- |
- | What it is | Claude Code plugin: skills + one opt-in agent + install glue |
- | Runtime language | None — bash only |
- | Target OS | macOS and Linux |
- | Supported architectures | Arch-neutral through Homebrew. Works on macOS's `/opt/homebrew`/`/usr/local` and on Linuxbrew's `/home/linuxbrew/.linuxbrew`. No `uname -m` branching. Branch on `command -v` only where tool itself differs by OS (e.g. `md5` vs `md5sum`). |
- | Distribution | Git repo ([github.com/shortcuts/radin](https://github.com/shortcuts/radin), currently private). Install with `curl \| bash install.sh` — downloads latest release tarball, or `main` if no release exists, into `~/.claude/radin`. No `git clone` needed. Hack on radin itself: `git clone` + `./install.sh`. |
-
- radin gives solo dev on small Claude subscription one install for
- cost-optimized agentic workflow. Ships backlog-driven execution
- (`radin-execute`, `radin-plan`, `radin-review`) and installs every companion
- tool it delegates to (rtk, caveman, ponytail, codebase-memory-mcp, headroom,
- thermo-nuclear, mattpocock-skills). The stack is opinionated: no per-tool
- question, because every skill here delegates to tools it assumes exist.
- radin never vendors or forks them.
-
- ## Dev loop
-
- This repo source of truth. Any skill iteration must be done in `skills/*/SKILL.md`.
-
- Every entry point is a skill, so it runs in the user's own thread and can
- talk to them. Sub-agents exist only as leaf workers, dispatched by a skill,
- for work whose context is worth isolating. radin ships no agent — see
- "Why radin-execute is a skill" below before you add one.
-
- - **Editing radin's own skills:** edit `skills/*/SKILL.md` directly.
- `thermo-nuclear` one exception — not vendored here at all. `install.sh`
- downloads its `SKILL.md` straight from cursor/plugins at install time,
- same as any other companion tool. radin only vendors what it wrote
- itself.
- - **Editing `install.sh`, docs, or repo scaffolding:** edit directly, as
- normal.
- - **`install.sh`** installs from this repo into `~/.claude/skills` and
- `~/.claude/.radin/lib`. Only adds or updates files there — one direction,
- repo to consumer.
-
- ## Storage contract
-
- All backlog content and execution state live inside target repo itself,
- in one canonical directory at repo root:
-
- ```
- <repo-root>/.claude/.radin/
- backlog/
- index.jsonl # backlog index, source of truth: one JSON object per task
- tasks/
- <task-id>.md # one file per task: description + any **Plan:** lines
- state/
- BACKLOG_STEPS.json # radin-execute execution plan
- completed.json # radin-execute completed-task -> commit log
- session.json # radin-execute worktree/branch answers
- journal.jsonl # append-only log of every state transition
- facts/
- <task-id>.md # long-form evidence for one task, written only when a report won't fit inline
- plans/
- <task-id>.md # radin-plan output
- reviews/
- <review-name>.md # radin-review / thermo-nuclear output
- ```
-
- Outside any git repo, current directory takes repo root's place.
- This directory only thing radin ever writes into consumer's repo.
- radin never edits consumer's `.gitignore` — committing `.claude/.radin/`
- (shared backlog) or ignoring it (private backlog) is consumer's call.
-
- Every one of `skills/radin-execute/SKILL.md`, `skills/radin-plan/SKILL.md`,
- `skills/radin-review/SKILL.md`, `skills/radin-record/SKILL.md`, and
- `skills/radin-show/SKILL.md` goes through shared backlog CLI
- (`lib/radin-backlog.sh`) for namespace resolution and every deterministic
- backlog operation (locate, append, remove, plan pointers) — model
- never hand-edits `index.jsonl` or task file directly, never
- addresses backlog content by line number.
- Backlog lives only in `<repo-root>/.claude/.radin/`: no monolithic
- `BACKLOG.md`, no `~/.claude`-side per-project namespace, no `.shortcuts/*.json`
- assumption in any of these files.
-
- ## Backlog entry schema
-
- `docs/schemas/backlog-entry.schema.json` formal, repo-internal contract
- for backlog's structure: `$BACKLOG_INDEX` (`index.jsonl`, one JSON
- object per task) plus one file per task under `$BACKLOG_TASKS_DIR`. Each
- index line carries `id` (stable slug assigned at creation), `category`
- (`feat`/`fix`/`chore`/`refactor` — same vocabulary as
- conventional-commit type; no per-entry bracket tag beyond it),
- `title`, `file`. Matching task file holds exhaustive
- description, plus optional trailing `**Plan:**` line.
-
- Read schema (and matching section of `docs/domain-models.md`) before
- adding new category, or before writing new skill that writes to
- backlog. Schema reference only — never ships to consumers.
- `lib/radin-backlog.sh` (which does ship) enforces structural half (id
- slugging/dedup, index-line shape, task-file location); each entry-writing
- skill keeps only its body-content guidance inline in own `SKILL.md`.
-
- ## Why radin-execute is a skill
-
- `radin-execute` lives in `skills/radin-execute/SKILL.md` because two Claude
- Code capability limits rule out shipping it as an agent:
-
- - **`AskUserQuestion` is removed from every sub-agent**, foreground and
- background alike, even when the `tools` field lists it. radin-execute's
- Phase 2 gate must ask the user to confirm the execution order, which an
- agent can never do.
- - **Nobody picks foreground or background.** Fork mode removes
- `run_in_background` from the `Agent` tool, so no radin prompt may tell a
- model to set it. Background sub-agents do keep `Agent` itself — see
- `docs/technical-constraints.md`, where both tool-filter rules are settled.
-
- To run the backlog out of the way, use `claude agents` (agent view) — radin
- installs nothing for it: full background sessions, whole tool pool, working
- `AskUserQuestion`, and `/radin-execute` runs unchanged in one. As a skill, radin-execute's body sits in the
- user's own context for the rest of the session, so keep `SKILL.md` to the
- loop and the gates; anything a run needs only sometimes goes in `lib/` and
- gets read on demand (`radin-execute-prompts.md` at Phase 4,
- `radin-execute-recovery.md` only when `radin state stuck` finds something,
- `radin-execute-reporting.md` at Phase 5).
-
- ## Adding new radin skill
-
- Skim existing one first — `skills/radin-review/SKILL.md` shortest
- complete example. Shared conventions below easy to drift from if you
- reinvent from scratch.
-
- 0. **Make it a skill.** See "Why radin-execute is a skill" above: a
- sub-agent cannot ask the user anything.
- 1. **Namespace resolution and backlog I/O.** Go through
- the `radin backlog` CLI (dispatcher `bin/radin`; see
- `docs/architecture.md`'s "Namespace resolution and backlog CLI"
- section): `env` for `REPO_ROOT`/`NAMESPACE_DIR`/`BACKLOG_INDEX`/
- `BACKLOG_TASKS_DIR`, and `find`/`add`/`add-plan`/`remove` for entry
- operations. Don't re-embed path resolution or index/task-file surgery
- inline — CLI single source of truth for both.
- 2. **Backlog writes.** If new skill appends entries, use CLI's
- `add` and classify into existing category
- (feat/fix/chore/refactor) — don't invent fifth. If shape genuinely
- needs to change, update `lib/radin-backlog.sh`,
- `docs/schemas/backlog-entry.schema.json`, and `docs/domain-models.md` in
- same change.
- 3. **Docs.** Run doc-maintenance checklist below. `docs/architecture.md`'s
- plugin repo layout and namespace-resolution sentence both need new
- file's name added. README's "Tools you get" table needs new row too —
- drifts silently otherwise, since nothing else forces match to
- `skills/`.
- 4. **`install.sh`.** New skills need `cp -r` line, or `install.sh` never
- distributes them — skill living only in `skills/` in this repo isn't
- installed anywhere yet. If new skill should be verified by
- `radin-doctor`, also add to `lib/radin-doctor.sh`'s expected-file
- list — not derived automatically from `install.sh`'s cp lines.
-
- ## What radin delegates, and why it never reimplements it
-
- Every companion tool installs, so a radin skill may assume one is there and
- delegate to it. The rule is one owner per job: if a shipped tool already does
- the job, radin names it instead of writing its own version.
-
- | Job | Owner | Named in |
- | --- | --- | --- |
- | Interview the user until a decision is settled | `/mattpocock-skills:grilling` | `radin-record`, `radin-plan`, `radin-review` |
- | Check third-party API/library behavior | `/mattpocock-skills:research` | `radin-plan` (interactive only) |
- | Place a module boundary / shape an interface | `/mattpocock-skills:codebase-design` | `radin-plan` |
- | Diagnose a failed attempt | `/mattpocock-skills:diagnosing-bugs` | Debug prompt |
- | Keep the change minimal | `/ponytail:ponytail` | `radin-plan`, `radin-execute`, Execution prompt |
- | Over-engineering review | `/ponytail:ponytail-review`, `/ponytail:ponytail-audit` | `radin-plan`, `radin-review` |
- | Deliberate-shortcut ledger | `/ponytail:ponytail-debt` | `radin-review` (directory scope), `radin-stats` |
- | Maintainability review | `/thermo-nuclear` | `radin-plan`, `radin-review` |
- | Per-category implementation discipline | `/caveman:surgical-patch` (fix), `/caveman:safe-refactor` (refactor), `/caveman:lean-build` (feat) | Execution prompt |
- | Commit message | `/caveman:caveman-commit` | Execution prompt |
- | Code structure questions | codebase-memory-mcp's MCP tools | see the code-graph section below |
- | Command output compression | `rtk` | every prompt that runs a command |
- | Structural search/diff/repo shape | `headroom sg` / `diff` / `loc` | Execution + refuter prompts, `radin-plan` |
- | Measured savings | `caveman-stats`, `rtk gain`, `headroom savings`, `ponytail-gain` | `radin-stats` |
-
- Two constraints bound this. A sub-agent cannot be sent into a skill that asks
- the user or spawns its own agent (see "Sub-agent capability limits"), so
- every prompt that names one of these carries the escape clause: drop the
- skill, never wait on it. And each delegation is a `command -v` or
- availability check away from being skipped, because a companion install is
- advisory and may have failed.
-
- Adding a delegation: put the tool name in exactly one of the files above, and
- add the row here. A second copy of the same delegation drifts silently.
-
- ## radin-execute session preferences
-
- `skills/radin-execute/SKILL.md` Phase 0.5 asks two questions once per backlog run,
- via `AskUserQuestion`: use a git worktree per task (default yes), and create a
- branch per task (default no). Answers persist to `state/session.json`
- (`radin-state.sh session-set`), so resumed run reuses them instead of asking
- again.
-
- No prompt carries the answers, and no model reads them to decide anything.
- `radin-state.sh prepare <namespace-dir> <id>` is the only place they become
- git commands: each execution sub-agent runs it, gets one path back, and works
- there. The two answers are not independent: a worktree cannot share the
- checkout's branch, so `worktree: yes` always creates `radin/<task-id>` and the
- `branch` answer changes nothing. `branch` decides only what happens under
- `worktree: no`. `skills/radin-execute/SKILL.md` Phase 0.5 states this and tells the
- skill to say so when it asks. Keep it that way — a model that is handed the two answers eventually
- overrides a `no`. `prepare` pins worktree path to `<repo>-<task-id>` and
- branch to `radin/<task-id>`; `task-dir` and `triage` derive the same names from
- task id to find dead sub-agent's leftovers, so keep all three in sync.
-
- ## Sub-agent capability limits
-
- Every sub-agent radin spawns can't reach user in prose, can't call
- `AskUserQuestion`, and can't be notified about background task. All three show
- up as hang with task uncommitted. Rules and reasoning in
- `docs/technical-constraints.md` -- read before you point any radin prompt at
- new skill, and check that skill doesn't ask user anything or spawn own agent.
- The skill itself is under no such limit: it runs in the user's thread.
-
- ## Per-task verification in radin-execute
-
- An execution sub-agent's `STATUS: SUCCESS` is a claim, and radin can check it
- before recording it. `skills/radin-execute/SKILL.md` carries one
- `<!-- radin:refute -->` marker line in Step 4b; `install.sh` asks (default no,
- since it costs one sub-agent per successful task) and its awk swaps that line
- for `$REFUTE_ON_RULE` or `$REFUTE_OFF_RULE`. Same contract as the concurrency
- marker: the marker stays alone on its line, both rule texts live only in
- `install.sh`, and `set_refute` exits non-zero if the marker survives.
-
- The refuter never sees the execution sub-agent's report — only the diff, the
- task file, the plan(s), and the checks it reruns itself. That asymmetry is the
- whole point: a summary of a diff is where a wrong "done" hides. Correctness
- belongs in its `VERDICT:` line; structure and taste go to the `/radin-review`
- pass it invokes, which logs its own backlog entries and blocks nothing.
-
- A `STATUS: FAILED` gets the **Debug prompt** instead, once per task per
- session: a retry with no new information fails identically and burns an
- attempt. It diagnoses read-only, the router appends the cause to the task
- file, and Step 4b runs again.
-
- Everything either one learns stays on that one task: a `**Fact:**`,
- `**Root cause:**` or `**Rework:**` line in its task file, with the long form
- in `state/facts/<task-id>.md`. Don't add a shared notes file, a cross-task
- memory, or an `agent-memory` store — a sub-agent's context holds its own task
- and nothing else, which is what keeps it cheap and on-scope. (Claude Code's
- native `memory:` frontmatter field would need radin's leaf roles to ship as
- agent definition files, which the "one agent" rule above rules out.)
-
- ## Concurrency variants in radin-execute
-
- `skills/radin-execute/SKILL.md` states no concurrency rule. It carries one
- `<!-- radin:concurrency -->` marker line in Core Constraints. `install.sh`
- asks at install time and its awk swaps that line for `$SEQUENTIAL_RULE` or
- `$PARALLEL_RULE` — both defined in `install.sh`, the only place either text
- lives. Keep the marker alone on its line, and edit the rule wording in
- `install.sh`, never in the skill file. `set_concurrency` exits non-zero if
- the marker survives the swap — a skill that ships with neither variant
- invents its own rule.
-
- Sub-agent prompts carry no variant. `lib/radin-execute-prompts.md` states
- the flat rule instead (a sub-agent never spawns a sub-agent), so the
- install-time answer lives in exactly one file.
-
- The answer covers execution sub-agents only. Planning, refuting, debugging
- and fact-finding dispatches write no repo code, so Core Constraints allows
- them in parallel unconditionally, and both rule texts in `install.sh` say so.
- Don't let either variant grow into a rule about those.
-
- ## The radin CLI and its token
-
- Skills never hardcode how the CLI is invoked. Every CLI call in
- `skills/*/SKILL.md` and the shipped `lib/*.md` prompt files is written as
- `RADIN_CLI <backlog|state|scope|cbm-hooks|cbm-config|update|doctor|uninstall> ...`; `install.sh`'s
- `set_cli` resolves the token to bare `radin` (when the `~/.local/bin` symlink
- exists and that directory is on PATH) or to the full dispatcher path
- (`"$HOME/.claude/.radin/bin/radin"`) otherwise. Same contract as the model
- tokens: don't write either literal form into a skill, and `set_cli` exits
- non-zero if a token survives. The dispatcher itself is `bin/radin`.
-
- ## Install, update, uninstall belong to the CLI
-
- Anything deterministic enough to need no model is a CLI subcommand, never a
- skill's job: `radin doctor`, `radin uninstall`, `radin cbm-config`, and
- `radin update`. A skill exists on top of one only as the slash-command
- surface, and it delegates instead of reimplementing.
-
- `radin update` (`lib/radin-update.sh`) refreshes radin plus every companion
- tool in one run. It reads `~/.claude/.radin/install_root` (written by
- `install.sh` each run), `git pull --ff-only`s a dev clone — refusing a dirty
- tree — or downloads the newest `install.sh` from `main`, then re-runs it with
- `--update`.
-
- `--update` implies `--force` and `--yes`, and `install.sh` reads its own
- previous `manifest.json` for `parallel_execution`, `refuter_pass` and the six
- `model_<role>` keys, so an update keeps the recorded answers rather than
- re-asking or silently resetting to defaults. The manifest is the only state
- that survives, so any new install-time question must be recorded there too —
- otherwise the next update resets it. Models are read all-or-nothing: a
- manifest missing one key falls through to the pickers.
-
- ## Sub-agent models in radin-execute
-
- No radin file names a model. Each sub-agent role carries a
- `RADIN_MODEL_<ROLE>` token instead — `PLANNING`, `EXECUTION`, `REFUTE`,
- `DEBUG`, `FACTFIND` in `lib/radin-execute-prompts.md`, `REVIEW` in
- `skills/radin-execute/SKILL.md`. `install.sh` asks — one pick for every
- role by default, or per role (only for roles the install enabled: a declined
- refuter pass gets no refuter-model question) — and its `set_role_models` sed
- writes the answers in.
- Defaults are sonnet,
- except fact-finding: it retrieves a checkable fact and its prompt already
- demands the evidence that establishes it, so haiku is enough and the router
- can reject a wrong answer.
-
- Don't hardcode a model name back into any of those files, and don't add a role
- without a token — `set_role_models` exits non-zero if a token survives, but it
- cannot notice a literal that was never a token. New role: add the token, a
- `MODEL_<ROLE>` default, a picker, and a `-e` clause in `set_role_models`.
-
- ## The code-graph companion (codebase-memory-mcp)
+ Read before touch any file here. radin be Claude Code plugin: skills, CLI, install glue. Bash, plus two C file (TUI and JSON helper). macOS and Linux.
- `codebase-memory-mcp` is radin's only code-intelligence companion: one MCP
- server, no second graph tool, no fallback to another one. These rules hold it
- in place:
+ ## Hard rules
- - **Install it whole or not at all.** `install.sh` installs the binary with
- `--skip-config`, sets `auto_index true`, then runs `radin cbm-config install`
- — upstream's own `codebase-memory-mcp install -y`, which writes its skill,
- three graph agents, the user-scope MCP entry and the
- `SessionStart`/`SubagentStart`/`PreToolUse` hooks that route Grep/Glob to the
- graph. Half a tool is not a choice worth offering, and the user-scope MCP
- entry is what makes every repo work with no per-project step.
- - **`lib/radin-cbm-config.sh` makes that write non-destructive.** Upstream
- [#1200](https://github.com/DeusData/codebase-memory-mcp/issues/1200) (open,
- maintainer-confirmed, unfixed through v0.10.8) replaces the whole
- `SessionStart` array in `~/.claude/settings.json` instead of merging, so it
- drops caveman's and ponytail's hooks. The script snapshots `settings.json`
- and `~/.claude.json` into `~/.claude/.radin/backups/`, runs their installer,
- then puts back every hook entry and `mcpServers` key that was there before
- and is now gone — pre-existing entries first, upstream's after, deep-equal
- entries never duplicated, so it is idempotent. `radin cbm-config repair` is
- the same restore against the newest snapshot, for after
- `codebase-memory-mcp update` reruns the write. Drop the snapshot step and the
- next machine loses hooks silently; that is the whole reason this file exists.
- When #1200 closes, the restore becomes a no-op that reports `INTACT` — leave
- it in, don't celebrate by deleting the safety net. The same script forces
- upstream to rewrite what it would otherwise keep from another machine: it
- stashes `<config-dir>/hooks/cbm-*`, prunes hook entries whose command path is
- gone, and replaces a dead `mcpServers` command. Reinstalling has to be able
- to fix a wrong path, or a shared `~/.claude` stays broken on every machine
- but the first.
- - **A symlinked `~/.claude` needs `CLAUDE_CONFIG_DIR`.** Upstream refuses
- every write under a symlinked config directory and then drops Claude Code
- from its target list while still exiting 0
- ([#1722](https://github.com/DeusData/codebase-memory-mcp/issues/1722),
- closed unresolved through v0.10.8) — no skill, no agents, no hooks, and
- `install.sh` printing that the tool is wired. `lib/radin-cbm-config.sh`
- resolves the link (`cd` + `pwd -P`; stock macOS has neither `realpath` nor
- `readlink -f`) and passes it as `CLAUDE_CONFIG_DIR`, which upstream honours.
- That override also moves upstream's MCP entry to
- `$CLAUDE_CONFIG_DIR/.claude.json`, so `adopt_staged_mcp` merges that one key
- into `~/.claude.json` — the file Claude Code reads when the user's own
- environment sets no `CLAUDE_CONFIG_DIR`. Never pass the variable empty:
- upstream treats it as set.
- - **`cbm_wired` is the install's exit status, not a message.** Upstream exits
- 0 whether or not it configured Claude Code, so `cmd_install` ends non-zero
- when neither the hooks nor the MCP entry are there, and `install.sh`'s
- existing fallback branch runs. Don't turn that back into a printed line: a
- false "wired" line is how a machine ends up with half a tool and nobody
- noticing.
- - **`python3` is the one hard dependency of that path**, since the restore is
- JSON surgery. Without it `install.sh` skips upstream's configuration
- entirely and falls back to `radin cbm-hooks claude-md`, because running the
- destructive write with no way to undo it is worse than a smaller install.
- - **The bracket's limits are written down** in
- `docs/technical-constraints.md`'s "What radin's codebase-memory-mcp bracket
- does and does not cover" (two files and one client only, restore is not
- rollback, newest snapshot wins, snapshots are user data, uninstall is
- asymmetric, `.mcp.json` path is machine-specific). Read it before you tell a
- user they are covered, and before changing `lib/radin-cbm-config.sh`. The
- user-facing half of the same list is README's "Caveats worth knowing".
- - **`lib/radin-cbm-hooks.sh` is the fallback wiring**, merge-only: the
- CLAUDE.md section and a repo's `.mcp.json` entry, for the no-`python3` path
- and for anyone who ran `codebase-memory-mcp uninstall` but kept radin. It
- writes no hook — `auto_index` plus the tool's own watcher keep the graph
- current, so a reindex hook buys nothing. Extend that script rather than
- writing a second one.
- - **Tool names live in four places only**: `skills/radin-plan/SKILL.md`
- (exploration), `skills/radin-review/SKILL.md` (`detect_changes` first),
- `lib/radin-execute-prompts.md` (execution, refuter, debug, fact-finding),
- and the
- CLAUDE.md section inside `lib/radin-cbm-hooks.sh`. Between them they name
- `index_repository`, `list_projects`, `search_graph`, `search_code`,
- `trace_path`, `detect_changes`, `query_graph`, `get_graph_schema`,
- `get_code_snippet` and `get_architecture` — every one from upstream's [MCP
- Tools](https://github.com/DeusData/codebase-memory-mcp#mcp-tools) table.
- Check a name against that table before you write it: a name that isn't
- there costs a failed call plus a fallback in every sub-agent that reads the
- prompt. Each mention also says a graph hit is a pointer — read the file
- before editing, never claim absence from an empty result.
+ - **bash 3.2** (macOS ship it): no associative array, no `mapfile`, no
+ `${var,,}`. No `uname` branch — resolve through `command -v` /
+ `brew shellenv`, branch only where tool differ (`md5` vs `md5sum`).
+ Call out every script edit explicitly.
+ - **`~/.claude` not ours.** `install.sh` only `cp` radin own named
+ files and `mkdir -p`. Never `rm`, never wildcard-delete, never overwrite
+ file radin not ship. Two exception: the
+ `<!-- radin:begin -->`…`<!-- radin:end -->` block in `~/.claude/CLAUDE.md`,
+ and `lib/radin-cbm-config.sh` snapshot/restore of `settings.json` +
+ `~/.claude.json`. Call out every `install.sh` edit explicitly.
+ - **Companion install be advisory.** Failure warn, run continue.
+ Not optional, and nothing asked about them.
- ## Constraints
+ ## Where to edit what
- **Never touch anything in `~/.claude` (`~/.config/.claude`) besides what
- radin itself added.** `~/.claude/skills` shared directory — consumer's other
- skills/tools live there too.
- `~/.claude/.radin/lib` radin's own global tool directory (distinct from
- per-repo `<repo-root>/.claude/.radin/` backlog namespace — same `.radin`
- name, different scope: this one holds shared scripts like
- `radin-backlog.sh`, not backlog state). `install.sh` may only `cp`/`cp -r`
- radin's own named files (radin's own `skills/<name>/`, `lib/*` into
- `~/.claude/.radin/lib/`) and `mkdir -p`. Two exceptions:
+ | Change | Edit |
+ | --- | --- |
+ | A skill's behavior | `skills/<name>/SKILL.md` — truth source, never installed copy |
+ | Anything deterministic (install, update, doctor, uninstall, backlog, state, TUI) | a `bin/radin` subcommand in `lib/`, never skill |
+ | Rare-need part of `radin-execute` | `lib/radin-execute-*.md`, read on demand |
+ | Concurrency rule, sub-agent model, how CLI invoked | none — write token, `install.sh` resolve it ([how](docs/architecture.md#install-time-substitution)) |
- 1. It rewrites the block between `<!-- radin:begin -->` and
- `<!-- radin:end -->` in `~/.claude/CLAUDE.md` (agent guidance on when to
- use radin). Only that block — everything outside the markers passes
- through untouched, which is what makes writing it unconditionally safe on
- a file radin doesn't own.
- 2. `lib/radin-cbm-config.sh` copies `~/.claude/settings.json` and
- `~/.claude.json` into `~/.claude/.radin/backups/` before handing `~/.claude`
- to `codebase-memory-mcp install`, then writes those two files again to put
- back what that install dropped (upstream #1200). It only ever restores an
- entry that was in the snapshot and is now missing, never adds an entry of
- radin's own, and never deletes a snapshot. It does drop what it can see is
- dead: a hook entry whose command is a path that does not exist, and an
- `mcpServers` command likewise — a `~/.claude` shared between machines
- carries the other machine's `$HOME`. It also moves
- `<config-dir>/hooks/cbm-*` into `~/.claude/.radin/backups/hooks.<stamp>/`
- before that install, because upstream bakes an absolute `$HOME` into each
- hook script and leaves an existing one alone. Moved, never removed.
+ `install.sh` go one way, repo to `~/.claude`. New skill need
+ `cp -r` line there, `lib/radin-doctor.sh` entry, README row and
+ `docs/architecture.md` mention, or it ship nowhere.
- Never `rm`. Never wildcard-delete directory. Never overwrite
- file radin didn't ship. Call out explicitly on any edit to `install.sh`.
+ ## Storage
- **macOS ships `/bin/bash` 3.2.** Apple froze it before GPLv3 switch.
- Since scripts run on both macOS and Linux, every script in this repo
- (`install.sh`, any future script) must stay bash-3.2-compatible: no
- associative arrays, no `mapfile`, no `${var,,}` case conversion. Call
- out explicitly on any script edit — easy to reach for bash-4+ syntax
- without noticing on machine with newer bash on `PATH`.
+ `<repo-root>/.claude/.radin/` (outside repo, `$PWD`): `backlog/`
+ (`index.jsonl` + `tasks/<id>.md`), `state/`, `plans/`, `reviews/`. Format in
+ [docs/domain-models.md](docs/domain-models.md), schema in
+ `docs/schemas/backlog-entry.schema.json`. Only thing radin write
+ into consumer repo, and radin never touch their `.gitignore`.
- **Arch/OS neutrality.** No `uname -m` branching anywhere. Resolve through
- `$(command -v brew)` / `brew shellenv` and let brew/npm/cargo pick right
- prefix for machine (macOS ARM/Intel, or Linux via Linuxbrew). Where
- command itself differs by OS — e.g. BSD `md5` on macOS vs GNU `md5sum` on
- Linux — branch on `command -v <tool>`, never on `uname`.
+ Read and write it only through CLI (`radin backlog …`, `radin state …`).
+ Nothing parse `index.jsonl` or `completed.json`, or grab task by line
+ number. Data view need but no subcommand give mean add one.
- **Companion-tool installs advisory only.** `install.sh` delegates to each
- tool's own installer and never guarantees it succeeds: a failure warns and
- the run continues. Installs are not optional. Only concurrency, the refuter
- pass, and sub-agent models are asked about.
+ ## Skills, agents, sub-agents
- **rtk available for both user and sub-agent command execution.** When
- installed, both sub-agents and users can wrap commands with `rtk` for
- token-saving. Sub-agent prompts include guidance to use `rtk` when available
- (`command -v rtk` succeeds); fallback when absent transparent.
+ Every entry point be skill, because it run in user thread and can
+ talk to them. Sub-agent cannot: no prose to user, no `AskUserQuestion`,
+ no background-task notification — all three look like hang. Sub-agent be
+ leaf worker skill dispatch, so before point prompt at skill check
+ it ask user nothing and spawn no agent
+ ([constraints](docs/technical-constraints.md)). Every prompt that name
+ companion gate on `command -v` and carry escape clause: drop skill,
+ never wait on it.
- ## Doc-maintenance policy
+ ## Delegation: one owner per job
- Change isn't done until affected docs updated in same commit.
+ If shipped tool do job, name it; never write radin own version. Each
+ delegation named in exactly one file — second copy drift silent, and
+ [test pin every name](docs/architecture.md#delegation-is-pinned-by-a-test).
- | File | Update when |
+ | Job | Owner |
| --- | --- |
- | `docs/architecture.md` | Storage scheme, namespace resolution, or plugin file layout changes |
- | `docs/domain-models.md` | Backlog entry format, plan-file format, or state-JSON schema changes |
- | `install.sh` companion-tool table (README) | Companion tool added, removed, or renamed |
- | "Tools you get" table (README) | radin-built skill added, removed, or renamed |
- | `CHANGELOG.md` | Any user-facing change, on every release |
-
- ## Pre-commit checklist
-
- - `make lint` clean (or documented exceptions only)
- - `make test` clean
- - Docs updated per table above
-
- ## Code Style & Testing
-
- → See `CONTRIBUTING.md`
+ | Settle a decision · API facts · module boundaries · diagnose a failure | `/mattpocock-skills:grilling` · `:research` · `:codebase-design` · `:diagnosing-bugs` |
+ | Minimal change · over-engineering · debt ledger | `/ponytail:ponytail` · `-review`/`-audit` · `-debt` |
+ | Maintainability review · commit message | `/thermo-nuclear` · `/caveman:caveman-commit` |
+ | Implementation discipline | `/caveman:surgical-patch` (fix), `safe-refactor`, `lean-build` (feat) |
+ | Code structure questions | codebase-memory-mcp's MCP tools |
+ | Output compression · structural search/diff | `rtk` · `headroom sg`/`diff`/`loc` |
- ## Architecture
+ Graph tool name live in four files only and must exist in upstream table —
+ wrong one cost failed call in every sub-agent
+ ([which files, and the pointer rule](docs/architecture.md#code-graph-wiring-codebase-memory-mcp)).
- → See `docs/architecture.md`
+ ## Decisions that look like bugs
- ## Domain Models
+ - **No per-task verification in `radin-execute`**, and `FAILED` task get
+ Debug prompt once per session ([why](docs/architecture.md#verification-in-radin-execute)).
+ - **What sub-agent learn stay on its task** — a `**Fact:**` or
+ `**Root cause:**` line, long form in `state/facts/<id>.md`. No shared note
+ file, no cross-task memory.
+ - **`radin-execute` worktree/branch answer never reach prompt**;
+ `radin-state.sh prepare` be only place they become git command. Model
+ handed them eventually override a `no`.
+ - **`lib/radin-cbm-config.sh` snapshot before upstream write**, because that
+ installer replace whole hook array instead of merge; drop it and
+ machine lose hooks silent ([limits](docs/technical-constraints.md)).
+ - **Two C file only: TUI (`lib/radin-tui.c`) and JSON helper
+ (`lib/radin-cbm-json.c`).** TUI draw and dispatch keys only — raw ANSI,
+ `termios`, every mutation shell out to `radin-backlog.sh`. Helper hold every
+ JSON rule `radin cbm-config` and `radin cbm-hooks mcp` need; those script
+ keep none, and radin need no python of own. `install.sh` build
+ both with `cc`, advisory: no compiler mean no `radin tui`, no
+ `radin cbm-config`, and `radin cbm-hooks mcp` print entry to paste by hand,
+ rest still install
+ ([rules](docs/architecture.md#the-human-tui)).
+ - **TUI load `backlog list --order created`**, so mutation reorder nothing and
+ row stay put. `Shift-A`/`Shift-P`/`Shift-C`/`Shift-T` be only reorder,
+ session-only, active one in header. CLI default stay `priority` — that be
+ ordering contract `radin-prioritization.md` read.
- → See `docs/domain-models.md`
+ ## Before committing
- ## Technical Constraints
+ - `make lint` and `make test` clean, and `make test` stay under 20s. Keep it
+ there: one recorded `install.sh` run every tree-only test replay, live run
+ only for install-time behaviour, mock command be `tests/helpers/mock.c` (one
+ compiled binary, not a shell stub per command — `/bin/sh` startup cost 20ms
+ a call), and no test make network request.
+ - Docs updated in same commit: `docs/architecture.md` (layout, namespace
+ resolution), `docs/domain-models.md` (format), README (new skill or
+ companion), `CHANGELOG.md` (user-facing change).
- → See `docs/technical-constraints.md`
+ Details: [architecture](docs/architecture.md) ·
+ [domain models](docs/domain-models.md) ·
+ [constraints](docs/technical-constraints.md) · [contributing](CONTRIBUTING.md)