diff options
Diffstat (limited to 'claude-rules')
| -rw-r--r-- | claude-rules/cross-project.md | 2 | ||||
| -rw-r--r-- | claude-rules/daily-drivers.md | 35 | ||||
| -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 | ||||
| -rw-r--r-- | claude-rules/verification.md | 12 |
6 files changed, 168 insertions, 9 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/daily-drivers.md b/claude-rules/daily-drivers.md index eeda33f..7ee5f06 100644 --- a/claude-rules/daily-drivers.md +++ b/claude-rules/daily-drivers.md @@ -14,9 +14,17 @@ config, a systemd unit, a credential, a one-time bootstrap step — consider whether the *other* daily driver needs the same change, and flag it. Don't assume a change made on the current machine is live everywhere. -This is a prompt to think, not a script to run. The agent can't reach the other -machine; the point is to surface "the other daily driver may need this too" at -the moment the change lands, so it doesn't silently drift to one box. +Both machines are on the same tailnet, so the agent can usually reach the other +one directly over tailscale ssh — it can sync, verify, or repair the other daily +driver, not just flag the drift. Reach for that when a change needs to land on +both boxes now. (This session repaired ratio's dotfiles and verified the fix +over tailscale; the .emacs.d side has driven ratio the same way — `git fetch` + +`reset --hard` and an `scp` across.) + +When tailscale is down or the other machine is offline, fall back to the +original discipline: this is a prompt to think, and the point is to surface "the +other daily driver may need this too" at the moment the change lands, so it +doesn't silently drift to one box. ## How the sync actually happens @@ -34,16 +42,25 @@ The mechanism depends on what changed: When the change is the one-time kind, say so explicitly: name the manual step the other machine still needs. +## Reaching the other machine over tailscale + +`tailscale status` lists every node with its tailscale IP and online state. +Connect by tailscale IP (e.g. `100.71.182.1`) or MagicDNS name (e.g. +`ratio.tailf3bb8c.ts.net`) — both always resolve and connect. A bare hostname +(`ssh ratio`) works only when MagicDNS is configured on the local machine; +without it the bare name can fail to resolve, which makes the box look +unreachable when it isn't. Prefer the IP or the full MagicDNS name when in +doubt. The first connection from a new address fails host-key verification under +`BatchMode`; add `-o StrictHostKeyChecking=accept-new` to clear it. + ## Knowing which machine you're on `uname -n` returns the hostname (`ratio` or `velox`). Use it when a reminder is machine-specific ("on ratio, you still need to …") so the note is actionable -rather than abstract. +rather than abstract — and after an ssh hop, to confirm which machine you landed +on. ## Current open instance -The org-roam knowledge-base clone — `git@cjennings.net:roam.git` — plus its -`roam-sync` systemd timer is confirmed set up on **velox**. It still needs -verifying (clone + timer) on **ratio**. This is the last piece before the -"memory sync across machines" work closes (tracked in the rulesets `todo.org`). -Clear this line once ratio is confirmed. +None. (The org-roam knowledge-base clone + `roam-sync` timer is confirmed on +both daily drivers, velox and ratio, as of 2026-06-30.) 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. diff --git a/claude-rules/verification.md b/claude-rules/verification.md index 388e0b5..26d05b5 100644 --- a/claude-rules/verification.md +++ b/claude-rules/verification.md @@ -13,6 +13,18 @@ This applies to every completion claim: - "Bug is fixed" → Run the reproduction steps. Confirm the bug is gone. - "No regressions" → Run the full test suite, not just the tests you added. +## Green Baseline Before Starting Work + +Run the test suite before you start work, not only before you finish. A clean run at the start confirms the tree is in the known-good state you assume it is, so the baseline you build on and measure your changes against is actually green. + +If the suite is red before you touch anything, fix or explicitly triage the failure first. A pre-existing failure left in place poisons every later "did I break this?" check: you can't separate your own regressions from the noise, and the end-of-work run stops being readable as pass/fail at a glance. Work that assumes a known-good base may also be built on a broken assumption you never saw. + +When a pre-existing failure genuinely can't be fixed before the work begins (out of scope, or it needs a decision), record it as a tracked task with the diagnosis and carry its name forward. The green bar for the rest of the work is then explicitly "only this known failure remains," not a silent tolerance for red. + +Two cases are not failures of this rule. A project with no suite has nothing to baseline — note that and proceed. A suite that can't run (no network, a missing dependency, a sandbox limit) is the "When You Cannot Verify" case below, not a work-blocker — record what you couldn't run and proceed with the risk named. + +This is the start-of-work counterpart to the Before Committing gate below: one confirms the ground is solid before you build, the other confirms you didn't crack it. + ## What Fresh Means - Run the verification command **now**, in the current session |
