<feed xmlns='http://www.w3.org/2005/Atom'>
<title>rulesets/docs/design, branch main</title>
<subtitle>Claude Code skills, rules, and language bundles
</subtitle>
<id>https://git.cjennings.net/rulesets/atom?h=main</id>
<link rel='self' href='https://git.cjennings.net/rulesets/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/'/>
<updated>2026-07-20T21:47:39+00:00</updated>
<entry>
<title>feat(notify): reserve "page me" for desktop, "text me" for Signal</title>
<updated>2026-07-20T21:47:39+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-20T21:47:39+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=61454894349e75b593ede5901a7b348ad580d3ce'/>
<id>urn:sha1:61454894349e75b593ede5901a7b348ad580d3ce</id>
<content type='text'>
"page me" and "text me" now name distinct channels: page is the desktop notification, text is the Signal phone push, and "text and page me" fires both. Before, "page me" defaulted to desktop and the phone was an unnamed "on my phone" variant, so you couldn't name the phone without naming the machine.

I renamed the Signal tool agent-page to agent-text to match, with a deprecated agent-page shim delegating to it so callers and other machines don't break before their next install. The dispatch and tests are otherwise unchanged. I rewrote protocols.org "Reaching Craig", page-me.org, and work-the-backlog's away-run logic around the three phrasings, and updated the runbook.
</content>
</entry>
<entry>
<title>feat(pager): document the Signal pager and add the receive timer</title>
<updated>2026-07-20T21:03:08+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-20T21:03:08+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=302b062680c8fbd9743d4e083154ac5fc314955a'/>
<id>urn:sha1:302b062680c8fbd9743d4e083154ac5fc314955a</id>
<content type='text'>
The pager worked but was undocumented and drifting stale: signal-cli warned the account had gone 47 days without a receive, and no runbook existed to hand a future session or a non-Claude runtime.

I added the runbook under docs/design/ and a roam-sync-shaped receive timer that drains the queue every 15 minutes, keeping the account warm and surfacing reply messages. I also generalized agent-page: it now sends directly from any machine holding the pager account and relays to velox only when it doesn't. ratio is linked as a device of the account, so a page lands even when velox is down.

The receive script no-ops cleanly where the account isn't registered, since the units stow onto every machine via the shared common package.
</content>
</entry>
<entry>
<title>chore: file inbox-zero-phase-e source artifacts into docs/design/</title>
<updated>2026-07-20T13:52:48+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-20T13:52:48+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=93a2e6dd2968e46e77704e01123a836a5cc1513b'/>
<id>urn:sha1:93a2e6dd2968e46e77704e01123a836a5cc1513b</id>
<content type='text'>
The autonomous-batch spec's three source artifacts (the Phase E proposal, its diff, the sender note) moved from working/inbox-zero-phase-e/ into docs/design/ under dated names, with the spec's inbound links repointed. The spec is IMPLEMENTED, so the working dir was a filing candidate. Also removed the spent working/sentry-2026-07-19-working-files-ruling/ staging dir, whose proposal shipped in the working/-tracked-from-creation change. working/ is now empty and gone.
</content>
</entry>
<entry>
<title>docs: fix four dangling file: links in specs and design notes</title>
<updated>2026-07-20T13:49:52+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-20T13:49:52+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=70fbe011394523595974be311667db63425072ed'/>
<id>urn:sha1:70fbe011394523595974be311667db63425072ed</id>
<content type='text'>
Three pointed at artifacts that were folded in or processed away (a spec-review file merged into wrapup-routing-spec, a removed pearl inbox note, a home-side subprojects log with no rulesets file) — delinked to plain text so the reference survives without a dead link. The fourth repoints the autonomous-batch spec at inbox.org, since inbox-zero.org was renamed in the consolidation. Surfaced by the sentry link-integrity pass.
</content>
</entry>
<entry>
<title>chore(todo): file four backlog tasks from the inbox pass</title>
<updated>2026-07-19T00:55:43+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-19T00:55:43+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=bc1d81d835237343a4ced82a9025f2dc34f45865'/>
<id>urn:sha1:bc1d81d835237343a4ced82a9025f2dc34f45865</id>
<content type='text'>
Filed as [#B] work items with their origin proposals preserved under docs/design/: the todo-cleanup dated-seal archiving model, the dated-log planning-line strip plus its lint backstop, a hook to enforce the task-boundary inbox check, and home's colloquialisms / "the list" before-close-queue convention. The first two both touch todo-cleanup.el and are cross-linked to build as one batch. The last two carry the design worked out this session so they start warm.
</content>
</entry>
<entry>
<title>fix(install-lang): refuse a colliding second bundle instead of clobbering</title>
<updated>2026-07-16T18:42:53+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-16T18:42:53+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=c98fda556e9211573dab3e32eaa5c42c2dedbfcb'/>
<id>urn:sha1:c98fda556e9211573dab3e32eaa5c42c2dedbfcb</id>
<content type='text'>
Installing a second language bundle into a project silently replaced the first one's config. settings.json and githooks are copied with cp -rT (always overwrite), so installing bash over elisp rewired the validate hook to validate-bash.sh and dropped check-parens from pre-commit, leaving validate-el.sh orphaned on disk. The output said [ok] for both. A project could lose its paren check or secret scan and read the install as success.

The guard detects which bundles a project already has, by the same rule fingerprint sync-language-bundle uses, and refuses when the incoming bundle would overwrite a file another one ships. It names each file at risk. FORCE=1 still overrides, and the message says that also re-seeds CLAUDE.md, which is destructive on a customized project.

Only three of the five shared filenames actually collide. gitignore-add.txt is appended and deduped, and CLAUDE.md is seed-only, so both compose across bundles already.

This doesn't decide whether polyglot projects are supported, and the guard shouldn't be read as "no". A non-overlapping pair still installs: bash ships settings.json and githooks with no coverage fragment, python ships only a coverage fragment, so the two compose today. The real line is overlap, not polyglot, and nothing chose it. The open question, along with the identical coverage target names both fragments define, is filed.

home reported this after scaffolding clock-panel with python and typescript, which hit the coverage fragment. The settings.json and githooks cases are worse and hadn't been noticed. No project was damaged: the three bundles that collide aren't doubled up anywhere.
</content>
</entry>
<entry>
<title>docs(design): record the subproject-pattern proposal, defer promotion</title>
<updated>2026-07-16T18:24:24+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-16T18:24:24+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=125c1e9777d66645cf23b30b3d2de1c91fb492aa'/>
<id>urn:sha1:125c1e9777d66645cf23b30b3d2de1c91fb492aa</id>
<content type='text'>
home proposed promoting its subproject pattern (a folded-in standalone project living as a self-contained subdir under a parent's scope) into the rules layer. The pattern reads as sound. I deferred it on evidence rather than merit, and preserved both the proposal and home's worked instance here so the decision has its source.

Two findings drove the deferral. It's N=1: across all 27 agent scopes, home is the only project with subprojects, and all nine came from one fold. There's no second instance to say which parts are general and which are home-shaped. The placement also contradicts the proposal's own argument. Rules load into every session of every project, and the doc argues that layer is a tax paid whether or not it's relevant, with depth belonging one open away. At 282 lines it would be the third-largest rule and add ~11% to the layer, so every unrelated project would carry a one-project convention.

I want to scout which projects would actually get subprojects, and why, before shaping anything. That evidence decides whether the pattern gets dropped or adjusted.

Two things to fix if it ever promotes: the doc cites a privacy-model rule that doesn't exist (the real content is the gitignore-vs-track and public-reachability decision), and about half of it is home's instance rather than rule content.
</content>
</entry>
<entry>
<title>feat(spec): sentry supervisor workflow spec, review-complete</title>
<updated>2026-07-14T07:50:17+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-14T07:50:17+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=f14dd8798842dda026d2613791d77f44c258ade7'/>
<id>urn:sha1:f14dd8798842dda026d2613791d77f44c258ade7</id>
<content type='text'>
Spec for the overnight hygiene supervisor: ten serialized passes, mkdir-atomic locks with heartbeat under the runtime dir, a host-suffixed unpushed branch, interactive entry gates with no report-only mode, and roam-sync kept as the roam repo's only committer. All 10 decisions and 12 adversarial-review findings are resolved in the file; status stays DRAFT pending a deep read. The build task and three deferrals are filed.
</content>
</entry>
<entry>
<title>docs(runtime): session plumbing assessed, no build needed</title>
<updated>2026-07-13T21:42:32+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-13T21:42:32+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=3ef55807a23f7dd447ecf9fc34d6512fb3893d6b'/>
<id>urn:sha1:3ef55807a23f7dd447ecf9fc34d6512fb3893d6b</id>
<content type='text'>
session-context-path already carries a runtime segment, the anchor cycle is plain files, and self-inject is harness-agnostic with only its payload Claude-shaped. A codex auto-flush is a documented payload variant whose second injected line carries the resume instruction, replacing the SessionStart hook. Wire it when a codex session first wants it.
</content>
</entry>
<entry>
<title>docs(runtime): skill parity resolves to one bootstrap resolution rule</title>
<updated>2026-07-13T19:54:03+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-13T19:54:03+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=0ee94abca7dde8356709d712b2dbf735b029f2b8'/>
<id>urn:sha1:0ee94abca7dde8356709d712b2dbf735b029f2b8</id>
<content type='text'>
All 29 skill and command bodies are markdown, so a single sentence in the future non-Claude entry file (a /name reference resolves to the skill or command file, read and follow it) carries the whole library. Auto-invocation degrades to by-name, which the publish flow already uses. flush stays Claude-only, owned by the session-plumbing child.
</content>
</entry>
</feed>
