<feed xmlns='http://www.w3.org/2005/Atom'>
<title>rulesets/docs, 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>feat: gate triage sources on a per-project :TRIAGE_SOURCES: declaration</title>
<updated>2026-07-20T18:44:11+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-20T18:44:11+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=4d87f35063e8430408178871cbf20b7268d7836a'/>
<id>urn:sha1:4d87f35063e8430408178871cbf20b7268d7836a</id>
<content type='text'>
The general triage plugins (personal Gmail, cmail, calendar, Telegram, GitHub PRs) are template-synced into every project, so the old "plugins present" probe self-activated triage everywhere. The sentry live trial caught it reaching personal inboxes from a project that isn't a triage target. Now a general plugin activates only when the project names its basename in a :TRIAGE_SOURCES: line in notes.org Workflow State. A project-specific plugin stays active by presence. The gate lives in triage-intake Phase 0, so it fixes the interactive over-pull too, and sentry's pass-3 probe reads the same signal.

Presence is capability, the declaration is activation. A project that declares nothing and owns no project plugin pulls nothing. Migration handoffs went to home and work. rulesets correctly declares nothing.
</content>
</entry>
<entry>
<title>feat: extend the silent-until-signal heartbeat to the two MCP monitor loops</title>
<updated>2026-07-20T18:39:29+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-20T18:39:29+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=0e9958abfbe97540b348b2118a863f7995e73b9e'/>
<id>urn:sha1:0e9958abfbe97540b348b2118a863f7995e73b9e</id>
<content type='text'>
Auto triage-intake and auto inbox-zero now collapse an empty check to a single "&lt;workflow&gt; at HH:MM: nothing" line, matching the sentry quiet-fire heartbeat from Phase 1. Detection stays in-session, so the MCP-auth sources are scanned in full and only the output collapses. Inbox already had an acknowledge-only-on-empty rule, now unified to the standard format; triage's three-section sweep output gains the empty-sweep collapse.

Completes the silent-until-signal spec (Phases 2-5): the spec is the shared-policy home the three workflows reference, and a manual-testing entry covers the live-loop verification. Spec flipped to IMPLEMENTED.
</content>
</entry>
<entry>
<title>feat(sentry): a quiet fire collapses to a one-line heartbeat</title>
<updated>2026-07-20T17:30:51+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-20T17:30:51+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=0767af804b980c23fdd759f65c0f50b499fb1bbe'/>
<id>urn:sha1:0767af804b980c23fdd759f65c0f50b499fb1bbe</id>
<content type='text'>
A sentry fire whose passes all probe-skip or no-op now writes a single "sentry at HH:MM: nothing" line instead of a full per-pass digest block. A fire that runs or queues anything writes the full digest as before. This is Phase 1 of the silent-until-signal policy. The live trial's fires 3-8 were walls of no-op digests, the noise this removes.

The "no silent skip" discipline is reconciled, not broken: inside a working fire every pass still writes its ran/skipped line, and a quiet fire's heartbeat is the explicit "nothing to do" record rather than a hidden skip.
</content>
</entry>
<entry>
<title>docs: spec the silent-until-signal monitor policy</title>
<updated>2026-07-20T17:16:33+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-20T17:16:33+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=986d6caeeaba6e4ab2f1e6f5e760ce841c922259'/>
<id>urn:sha1:986d6caeeaba6e4ab2f1e6f5e760ce841c922259</id>
<content type='text'>
An in-session monitor loop (sentry, auto triage-intake, auto inbox-zero) fires the model every interval and narrates a full turn even when nothing changed, so a session fills with quiet-fire noise. The spec settles the fix as a policy, not a watcher: detect first, and on an empty check collapse to one labelled heartbeat line, spending a full turn only on a real item. Keeping detection in-session dissolves the MCP-auth split (triage's sources need the session's auth, which a detached watcher can't reach), so it applies uniformly across all three loops. DRAFT, decisions resolved live. Links a [#B] build task.
</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>docs: spec the triage source-activation model</title>
<updated>2026-07-20T13:46:42+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-20T13:46:42+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=b02eadec9392a9978cd526e2798460a53b5b79c4'/>
<id>urn:sha1:b02eadec9392a9978cd526e2798460a53b5b79c4</id>
<content type='text'>
The sentry live trial surfaced that triage-intake self-activates in every project. The general personal-account plugins are template-synced everywhere, so its probe reads present-everywhere as active-everywhere. The spec captures the fix: general plugins gate on a per-project :TRIAGE_SOURCES: declaration, project-specific plugins stay active by presence, and the activation layer lives in triage-intake Phase 0 so it fixes interactive runs too. DRAFT, pending review. Links a [#B] build task.
</content>
</entry>
<entry>
<title>chore(sentry): flip spec to IMPLEMENTED and close the build task</title>
<updated>2026-07-19T10:05:33+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-19T10:05:33+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=8c0a56bf2d7e81e4876919f120004aa011365327'/>
<id>urn:sha1:8c0a56bf2d7e81e4876919f120004aa011365327</id>
<content type='text'>
Phase 4. All four phases shipped and the suite is green, so the spec keyword moves DOING to IMPLEMENTED with a dated history line and the Metadata Status mirrors it. The build task and its phase sub-tasks close (the sub-tasks become dated event-log entries per the depth rule).

The overnight live trial is the one piece an agent can't run, so it's filed as a structured manual-testing task: entry gates with Craig present, one fire observed end to end, the wrap-up guard and stop-sentry, and the morning branch review. Its findings become follow-up tasks rather than gating the flip.
</content>
</entry>
</feed>
