<feed xmlns='http://www.w3.org/2005/Atom'>
<title>rulesets/.claude, 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-06-12T07:33:46+00:00</updated>
<entry>
<title>chore: set opus as the machine-default model</title>
<updated>2026-06-12T07:33:46+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-06-12T07:33:46+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=5feaa94b3ba6c1ce52742a771d37e3186eb81230'/>
<id>urn:sha1:5feaa94b3ba6c1ce52742a771d37e3186eb81230</id>
<content type='text'>
</content>
</entry>
<entry>
<title>feat(commands): /update-skills syncs forks with upstream via 3-way merge</title>
<updated>2026-06-11T22:05:03+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-06-11T22:05:03+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=da93ffd91dea133963ffceaff24d41bc76b8ff93'/>
<id>urn:sha1:da93ffd91dea133963ffceaff24d41bc76b8ff93</id>
<content type='text'>
Upstream releases fixes worth pulling into the forks (arch-decide, playwright-js, playwright-py) without losing our local modifications. Each fork now has a manifest at upstreams/&lt;name&gt;/ plus a committed baseline snapshot that is the 3-way merge base. scripts/update-skills.py classifies each file's drift and merges to stdout. The command owns per-file confirmation, per-hunk conflict prompts, and every target write.

I centralized manifests under upstreams/ instead of per-skill dotfile dirs because arch-decide is now two flat files in commands/ and can't carry one. A "files" map in its manifest handles the upstream rename of SKILL.md to arch-decide.md.

I seeded baselines from today's upstream HEADs, so pre-existing local modifications classify as local-only from here on. git merge-file signals hard errors as exit 255, which subprocess reports as positive. The guard treats anything 128 and up as an error so a binary-file failure isn't misread as a conflict.
</content>
</entry>
<entry>
<title>feat(hooks): title sessions "host project" for the remote session list</title>
<updated>2026-06-11T18:23:13+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-06-11T18:23:13+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=bdc9a5d6e1320032770f54c747c210e4f465c399'/>
<id>urn:sha1:bdc9a5d6e1320032770f54c747c210e4f465c399</id>
<content type='text'>
Remote sessions showed up on claude.ai/code and mobile under auto-generated names, so picking the right one meant guessing. Claude Code 2.1.152+ lets a SessionStart hook set the title via hookSpecificOutput.sessionTitle.

hooks/session-title.sh emits "&lt;uname -n&gt; &lt;project&gt;" (ratio rulesets, velox work) on startup and resume. Project is the git-toplevel basename so a session started in a subdirectory still names the project, with the cwd basename as fallback. The hook stays silent when a title already exists, so a /rename or an earlier run isn't clobbered on resume. The harness ignores titles on clear and compact, so the settings matcher restricts to startup|resume.

Wired in settings.json and the install-hooks snippet. As a default hook it reaches every machine through make install on the next session start.
</content>
</entry>
<entry>
<title>feat(install): adopt the statusline script into the managed set</title>
<updated>2026-06-11T16:35:45+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-06-11T16:35:45+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=3df14fc985ddad041c290c732b5b5b8eae41f68e'/>
<id>urn:sha1:3df14fc985ddad041c290c732b5b5b8eae41f68e</id>
<content type='text'>
An archsetup session added a statusLine entry to the tracked settings.json on 2026-06-11 (Craig's request), pointing at ~/.claude/statusline-command.sh, but the script itself lived outside the repo on one machine. This commits the settings entry and brings the script into .claude/, linked by make install like the rest of the config, so it reaches every machine on the next session.

Two fixes over the original: uname -n instead of hostname (Arch doesn't ship hostname by default, so the host rendered empty with stderr noise), and the tilde replacement is escaped (unquoted, bash expands the replacement ~ straight back to $HOME, which defeated the abbreviation). scripts/tests/statusline-command.bats covers the format, branch handling, and the no-stderr contract.
</content>
</entry>
<entry>
<title>chore(ai): archive session record</title>
<updated>2026-06-11T06:37:55+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-06-11T06:37:55+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=cf957630668be9b8a51fba5a42aea5829ff4bcc4'/>
<id>urn:sha1:cf957630668be9b8a51fba5a42aea5829ff4bcc4</id>
<content type='text'>
</content>
</entry>
<entry>
<title>chore(claude): pin model to fable in settings</title>
<updated>2026-06-10T19:05:11+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-06-10T19:05:11+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=c6bd31f1650330d911de35e120f707eae8ca2baa'/>
<id>urn:sha1:c6bd31f1650330d911de35e120f707eae8ca2baa</id>
<content type='text'>
</content>
</entry>
<entry>
<title>docs(commands): trim two command descriptions under listing cap</title>
<updated>2026-06-03T18:21:15+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-06-03T18:21:15+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=586c8f69b2f1e0498be7f8abecfd348aae12e5dd'/>
<id>urn:sha1:586c8f69b2f1e0498be7f8abecfd348aae12e5dd</id>
<content type='text'>
Both descriptions ran past Claude Code's per-entry listing cap (~1536 chars), so the menu blurb got truncated. start-work was 1680, respond-to-cj-comments 1568. I trimmed them to 1513 and 1518, compressing only descriptive prose. Every "Use when" and "Do NOT use" routing trigger stays verbatim, so triggering is unchanged.
</content>
</entry>
<entry>
<title>feat(start-work): add a spec-prerequisite check to the Approach gate</title>
<updated>2026-06-03T02:21:11+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-06-03T02:21:11+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=2cff51e377c89e325ccbc10fae7c76b730a88571'/>
<id>urn:sha1:2cff51e377c89e325ccbc10fae7c76b730a88571</id>
<content type='text'>
The Approach gate planned tests, migration, and commits but never asked whether the work needs a design spec it does not yet have. Added item 5: a spec is warranted for large or wide-surface work, unresolved design questions, or a new interface others build on. For a big task it is never a silent skip — the approach summary must state why no spec is needed, so the call is visible and challengeable at the gate. Small contained tasks pass without comment.
</content>
</entry>
<entry>
<title>feat(start-work): add "reasons not to do this" to the Justify gate</title>
<updated>2026-06-03T02:20:07+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-06-03T02:20:07+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=8ab5ec135a3846972f9eaad5ab67104b2ff19232'/>
<id>urn:sha1:8ab5ec135a3846972f9eaad5ab67104b2ff19232</id>
<content type='text'>
The Justify gate covered Downsides and Alternatives but had no forced verdict on whether the work should happen at all. Added item 9: surface the top three objections when real ones exist, or say so in one line when none rise to a genuine objection, rather than manufacturing three. Building the case against the work is cheapest at this gate.
</content>
</entry>
<entry>
<title>feat(flush): add /flush skill and SessionStart(clear) resume hook</title>
<updated>2026-06-03T01:36:18+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-06-03T01:36:18+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/rulesets/commit/?id=526df6dd7872890e525b9af33917169cfdf705d8'/>
<id>urn:sha1:526df6dd7872890e525b9af33917169cfdf705d8</id>
<content type='text'>
Flush is the checkpoint half of the wrap/restart rhythm. It refreshes the session-context anchor in place, the user runs /clear, and the session resumes from the anchor instead of starting cold. One logical session stays alive across a /clear boundary without the archive-and-commit of wrap-it-up or the full cold boot of startup, which buys cheaper tokens and a sharper context window.

The mechanism splits into two halves around /clear, which wipes the conversation so nothing runs straight through it. The /flush skill is the pre-clear half: dump live state, refresh the anchor's Summary, append a dated flush marker, verify the write landed, then prompt the user to /clear. The agent can initiate at a clean task boundary on its own judgment, but /clear is user-only, so the agent does the work and the user supplies the single keystroke. The session-clear-resume.sh hook is the post-clear half, a SessionStart matcher=clear hook that points the fresh session at the anchor to resume, or at startup when no anchor exists.

I packaged the pre-clear half as a skill rather than a project-workflow doc so both halves are global. The hook was already global, so /flush is now callable by name from any project with no per-project sync.

The hook is canonicalized under hooks/ and symlinked into ~/.claude/hooks/, matching precompact-priorities.sh. settings.json wires the SessionStart entry, and settings-snippet.json carries it so a fresh machine wires the hook on make install-hooks.
</content>
</entry>
</feed>
