diff options
Diffstat (limited to 'claude-rules')
| -rw-r--r-- | claude-rules/cross-project.md | 2 | ||||
| -rw-r--r-- | claude-rules/docs-lifecycle.md | 75 | ||||
| -rw-r--r-- | claude-rules/host-identity.md | 20 | ||||
| -rw-r--r-- | claude-rules/todo-format.md | 33 |
4 files changed, 130 insertions, 0 deletions
diff --git a/claude-rules/cross-project.md b/claude-rules/cross-project.md index caceec9..73c0e1b 100644 --- a/claude-rules/cross-project.md +++ b/claude-rules/cross-project.md @@ -35,6 +35,8 @@ Two acceptable outcomes: ``` Output filenames follow `YYYY-MM-DD-HHMM-from-<this-project>-<slug>.<ext>` automatically, so the target's next session sees the source + timestamp at a glance without you having to construct the name. Fall back to `Write`/`Edit` only when the script isn't available (e.g. a freshly-cloned project before the first startup-rsync). + + The wrap-up cross-project router rides this same sanctioned path: at wrap time, `wrap-it-up.org`'s router step delivers `:ROUTE_CANDIDATE:`-tagged keeper tasks to their home projects' inboxes via `route-batch` → `inbox-send` (never a direct foreign `todo.org` write), and the destination's own inbox processing files each task per its conventions. 2. **"Switch projects"** — stop. Let the user reopen the agent session in the right cwd. Don't assume which one was meant. Either guess is wrong half the time and the cost of asking once is one short turn. diff --git a/claude-rules/docs-lifecycle.md b/claude-rules/docs-lifecycle.md new file mode 100644 index 0000000..3906d86 --- /dev/null +++ b/claude-rules/docs-lifecycle.md @@ -0,0 +1,75 @@ +# Docs Lifecycle + +Applies to: `**/*` (any project carrying a `docs/` tree) + +How formal documents are separated from working notes, and how a document's +lifecycle state stays visible without opening the file. Specs are the first +instance of the shape; the pattern is reusable for any growing collection of +processed artifacts. Full design: the docs-lifecycle spec in rulesets +`docs/specs/`. + +## The shape (reusable) + +1. **Separate formal artifacts from working notes by location.** A formal + artifact proposes a buildable change and carries the full spine; everything + else is a note. +2. **Lifecycle state lives in the artifact**, on a scannable, greppable + carrier — an org TODO keyword on a top-level status heading — with a dated + history of every transition. +3. **Links use rename-safe identifiers** so a move or rename never orphans + inbound references. +4. A collection **earns this treatment when "which of these are live?" starts + requiring a file-by-file read.** + +## The spec instance + +- `docs/specs/` holds formal specs only — a doc with both a `Decisions` + section and an `Implementation phases` section (the spec-create spine). + `docs/design/` holds everything else: brainstorms, proposals, inventories, + research notes, frozen source material. Spec filenames end `-spec.org` + (spec-review's precondition keys on it); no status suffixes ever. +- Every spec opens with a top-level status heading directly after the file + header, carrying the lifecycle keyword, an `:ID:` UUID, and dated history + lines (newest first). The keyword header is two sequences, and both lines + are required: + + #+TODO: TODO | DONE + #+TODO: DRAFT READY DOING | IMPLEMENTED SUPERSEDED CANCELLED + + The first drives `Decisions` / `Review findings` tasks and their `[/]` + cookies; the second is the lifecycle. They share no keyword — never merge + them into one line, and never drop the first (that silently breaks the + cookies that gate readiness). +- **The heading keyword is authoritative.** The Metadata table's `Status` + field mirrors it in lowercase; on disagreement the heading wins. A + transition is three lines in one file — keyword, history line, mirror — and + never a rename or a link edit. +- **Every flip has a named owner:** spec-create stamps `DRAFT`; spec-review + flips `DRAFT` → `READY` on a passing gate; spec-response flips `READY` → + `DOING` when it decomposes phases into build tasks (stamping the spec's + UUID as a `:SPEC_ID:` property on the build parent, and always emitting a + final "flip the spec to IMPLEMENTED" task); task-audit flags any `DOING` + spec whose `:SPEC_ID:`-bound parent is closed, archived, or missing. + Terminal states (`IMPLEMENTED` / `SUPERSEDED` / `CANCELLED`) always carry a + stated reason in the history line. +- **The status board is one grep:** + + rg -H '^\* (DRAFT|READY|DOING|IMPLEMENTED|SUPERSEDED|CANCELLED) ' docs/specs/ + +- **Legacy compatibility:** projects that haven't run the one-time `spec-sort` + retrofit (no `:LAST_SPEC_SORT:` marker in `.ai/notes.org` Workflow State) + keep their legacy spec locations reviewable; the `docs/specs/` requirement + hardens only after the sort runs. +- **Cross-doc links to specs are `file:` links for now.** Specs carry `:ID:` + UUIDs, but conversion to `[[id:...]]` is a gated follow-up (the Emacs id + index has to know about project docs first) — don't convert links ad hoc. + +## Watch for + +- Editing the `#+TODO:` header down to one sequence — the `[/]` cookies stop + computing and readiness gates go vacuous. +- Bare `[N/N]` tokens in prose or list items — org's cookie updater rewrites + them; spell counts out in words outside real cookie positions. +- A "done" spec whose keyword still says `DOING` — that's the failure this + convention exists to prevent; flip it with a history line rather than + leaving it for the audit to catch. diff --git a/claude-rules/host-identity.md b/claude-rules/host-identity.md new file mode 100644 index 0000000..9f58392 --- /dev/null +++ b/claude-rules/host-identity.md @@ -0,0 +1,20 @@ +# Host-Identity Guard + +Applies to: `**/*` (any tracked or synced project file) + +Never assert mutable environment identity as a fixed fact in a file that git tracks or the template sync distributes. A `CLAUDE.md` or notes file claiming "This machine is ratio", a current OS version, an IP, or "the laptop" lands identical on every machine, so the claim is false everywhere but its origin — and an agent that trusts it reasons backwards the whole session. + +## The Rule + +- **Don't write fixed identity claims** — "this machine is X", "the current host is X", "we're on the laptop" — in `CLAUDE.md`, `notes.org`, rules files, or any other tracked/synced doc. +- **Derive identity at runtime and name the command.** The correct phrasing in a doc is an instruction, not a fact: "run `uname -n` to find the hostname." (`uname -n` is the source of truth — the `hostname` binary is often absent, and `uname -r` is the kernel release, not the host.) +- **Describing the fleet is fine; claiming the current member is not.** "The fleet is ratio (workstation) and velox (laptop)" is a durable fact and belongs in a doc (see `daily-drivers.md`). "This machine is ratio" is a snapshot that rots the moment the file syncs. +- The same applies to any mutable environment fact: current OS release, current IP, current display topology. State how to derive it, not what it was when the file was written. + +## Worked failure + +archsetup, 2026-06-21: its `CLAUDE.md` asserted "This machine is **ratio**" as a fixed fact. A session running on velox reasoned from that line all session — skipping velox-only reminders as "not applicable, we're on ratio" — exactly backwards. The fix replaced the claim with the `uname -n` instruction. + +## Enforcement + +The startup workflow runs a read-only probe that greps `CLAUDE.md` and `.ai/notes.org` for fixed-identity phrasing and surfaces any hit as a startup finding. The probe flags for human judgment; it never blocks. When it fires, replace the claim with the runtime derivation, not a fresher snapshot. diff --git a/claude-rules/todo-format.md b/claude-rules/todo-format.md index 55530de..5e9ca32 100644 --- a/claude-rules/todo-format.md +++ b/claude-rules/todo-format.md @@ -33,6 +33,37 @@ When a project's `todo.org` lacks the section, add it before filing or grading further tasks — propose the priority semantics and tag set from the project's existing usage, and confirm with Craig. +### Hard definitions: `:solo:` and `:quick:` (fixed across projects) + +A project's scheme may add or rename its other tags, but these two carry +fixed definitions everywhere, because autonomous execution +(work-the-backlog / the no-approvals speedrun) reads `:solo:` as its +eligibility gate and trusts the author's tag rather than re-deriving +autonomy at run time. + +- **`:solo:` — autonomy.** The task can be completed *and verified* without + Craig's involvement beyond at most one or two quick decisions that can be + stated and answered before work starts. No open design question, no + "weigh these approaches," no waiting on Craig mid-task. Three gates, all + must hold: *buildable* (the agent has the capability and access), + *verifiable by the agent* (an objective or local check it can run itself — + handing off a residual human-in-the-loop confirmation as a structured + manual-testing reminder does not disqualify), and *no deliberation* (a + quick, upfront-answerable factual question is allowed — it gets batched + into the speedrun's pre-flight Q&A; a genuine design or preference call + is not). A wrong `:solo:` is worse than none: it tells Craig he can hand + the task off and walk away when he can't. +- **`:quick:` — effort hint only.** Likely 30 minutes or less from start + through verification. Informational, for batching and estimating a run's + duration; never an eligibility gate. `:quick:` and `:solo:` are + orthogonal — a bounded refactor can be `:solo:` but slow; a five-minute + change hinging on a preference call is `:quick:` but not `:solo:`. + +Both tags are applied at task creation and **re-checked as a mandatory +step** in the task-review and task-audit workflows, so the run-time gate +can trust the tag. A review or audit that skips the `:solo:`/`:quick:` +assessment is incomplete. + ### Bug priority from severity × frequency (mandatory where a codebase exists) Some projects carry a codebase — source the project maintains under version @@ -172,6 +203,8 @@ becomes *** 2026-05-15 Fri @ 12:58:08 -0500 Wired yasnippet for universal availability +**Enforcement.** This is applied at close time by whoever closes the task, but an interactive org close (`org-log-done` flips the keyword to `DONE` and stamps `CLOSED:`) never applies the dated rewrite, so level-3+ closes accumulate as `DONE` keywords. `todo-cleanup.el --convert-subtasks` (run in the `clean-todo` and wrap-up cleanup passes) normalizes them mechanically: it rewrites any level-3+ `DONE`/`CANCELLED`/`FAILED` heading into the dated form above, pulling the timestamp from the `CLOSED` cookie and keeping the heading text verbatim (a batch tool can't reliably past-tense a title — polish wording by hand where it matters). `lint-org.el` flags any that slip through (checker `subtask-done-not-dated`). So the depth rule holds even when tasks are closed interactively rather than by an agent applying this section. + ### Why depth-based The agenda view (`org-agenda`) shows entries at the section + top-task level. Letting `**` tasks stay task-shaped preserves their visibility as "things that recently shipped." Letting `***+` sub-tasks flip to dated entries keeps the agenda from being clogged with a long list of completed sub-tasks at every depth — those become history within their parent instead. |
