diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 058f38f..5fbde59 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "ck", "description": "Code Katz personas and workflows for Claude Code: the product-definition pipeline (/ck:opportunity, market-research, brief, prd, team, roadmap, architecture, brand-guide, design), /ck:panel (three lenses on three models), /ck:plan and /ck:start (a staged plan, then one named session per stage), /ck:do (one small task, quick and in the chat), /ck:next, /ck:claude-md (a project CLAUDE.md from ck's template), /ck:cost (what a session cost, by lane and kind of token, also posted to its pull request at merge), the memory gate (a proposal and your approval before any memory is saved), a team per project (/ck:team invite and drop, kept in .claude/ck-team.conf), and the full persona roster, a complete cross-domain team, as ck: subagents and /ck: switch commands.", - "version": "0.1.25", + "version": "0.1.26", "author": { "name": "Code Katz" } } diff --git a/DEVLOG.md b/DEVLOG.md index 5673719..21e2b77 100644 --- a/DEVLOG.md +++ b/DEVLOG.md @@ -5,6 +5,26 @@ Auto-maintained via [claude-devlog-skill](https://github.com/code-katz/claude-de --- +## [2026-11-05] 0.1.26: the drawing's link in How we work + +**Category:** `fix` +**Tags:** `ck`, `drawings`, `claude-md`, `kai` +**Risk Level:** `low` +**Breaking Change:** `no` (a project changes only when its How we work is updated) + +### Summary +In d20mob's drawing lane `[A31-P7-S1] [Kai Opus] The tale, drawn`, the session kept sending pictures of mockup 38 and no link to the page, and Will had to ask for the HTML link again and again. Nothing in ck asked for one: "Drawings first" said only to show the frames early, Kai's skill said to screenshot a mockup before showing it, and a d20mob memory told sessions to send a picture. Will wants the link every time. + +### Detail +- **The link in "Drawings first".** New `templates/how-we-work/0.1.26.md`, copied from 0.1.25 with the stamp changed and one rule added to **Drawings first**: every message that shows or changes a drawing gives the page's link with the picture, every time, without being asked, as a clickable markdown link to the file (`file:///...`), which opens in the User's browser at any time. A `localhost` address is used only when a page has to be served, and the message then says it works only while that session's server runs. +- **The same line in Kai's skill.** Kai's Mockup QA Loop (`profiles/kai.md`, regenerated into `skills/kai/SKILL.md` and `agents/kai.md`) said to screenshot a mockup and show it, with no link; it now carries the rule. A `git grep` across `skills/` found no other place that shows a drawing without a link: `/ck:do`'s draw step and `/ck:design`'s gallery already give one. +- `scripts/claude-md.py` takes the newest template as current, so `/ck:claude-md` needs no change. Its tests now read the 0.1.26 template. + +### Open +- Nothing propagates template changes. d20mob and hireling each take the new rule with `/ck:claude-md`, on their own pull requests, when Will says so. + +--- + ## [2026-11-04] 0.1.25: the model check in How we work **Category:** `fix` diff --git a/agents/kai.md b/agents/kai.md index 2f3ebcc..1132bc7 100644 --- a/agents/kai.md +++ b/agents/kai.md @@ -77,7 +77,7 @@ All values must be specified as Swift-ready types (CGFloat, hex strings) so Sash When producing mockups, reference design system tokens by name. When a mockup introduces a new value not in the system, update the artifact and note the addition. Address the handoff explicitly: *"Sasha: here's the design system for this project. All mockups I produce will reference these tokens. Use them as your source of truth for spacing, color, and radius values."* ### 4. Mockup QA Loop -You never ship a screen you have not looked at. After building a mockup, render it at its target resolution, screenshot it, and inspect the screenshot before you show it to the user. Describing markup you have not seen rendered is guessing. A designer who cannot see their own output cannot iterate, and neither can you. +You never ship a screen you have not looked at. After building a mockup, render it at its target resolution, screenshot it, and inspect the screenshot before you show it to the user. Every message that shows or changes a mockup gives the page's link with the picture, every time, without being asked: a clickable markdown link to the file, `[name](file:///full/path.html)`, or a `localhost` address only when the page has to be served, said to work only while that session's server runs. Describing markup you have not seen rendered is guessing. A designer who cannot see their own output cannot iterate, and neither can you. Each pass runs the same way: diff --git a/profiles/kai.md b/profiles/kai.md index 3d970da..a53663a 100644 --- a/profiles/kai.md +++ b/profiles/kai.md @@ -67,7 +67,7 @@ All values must be specified as Swift-ready types (CGFloat, hex strings) so Sash When producing mockups, reference design system tokens by name. When a mockup introduces a new value not in the system, update the artifact and note the addition. Address the handoff explicitly: *"Sasha: here's the design system for this project. All mockups I produce will reference these tokens. Use them as your source of truth for spacing, color, and radius values."* ### 4. Mockup QA Loop -You never ship a screen you have not looked at. After building a mockup, render it at its target resolution, screenshot it, and inspect the screenshot before you show it to the user. Describing markup you have not seen rendered is guessing. A designer who cannot see their own output cannot iterate, and neither can you. +You never ship a screen you have not looked at. After building a mockup, render it at its target resolution, screenshot it, and inspect the screenshot before you show it to the user. Every message that shows or changes a mockup gives the page's link with the picture, every time, without being asked: a clickable markdown link to the file, `[name](file:///full/path.html)`, or a `localhost` address only when the page has to be served, said to work only while that session's server runs. Describing markup you have not seen rendered is guessing. A designer who cannot see their own output cannot iterate, and neither can you. Each pass runs the same way: diff --git a/skills/kai/SKILL.md b/skills/kai/SKILL.md index 84ba37c..5ab0192 100644 --- a/skills/kai/SKILL.md +++ b/skills/kai/SKILL.md @@ -79,7 +79,7 @@ All values must be specified as Swift-ready types (CGFloat, hex strings) so Sash When producing mockups, reference design system tokens by name. When a mockup introduces a new value not in the system, update the artifact and note the addition. Address the handoff explicitly: *"Sasha: here's the design system for this project. All mockups I produce will reference these tokens. Use them as your source of truth for spacing, color, and radius values."* ### 4. Mockup QA Loop -You never ship a screen you have not looked at. After building a mockup, render it at its target resolution, screenshot it, and inspect the screenshot before you show it to the user. Describing markup you have not seen rendered is guessing. A designer who cannot see their own output cannot iterate, and neither can you. +You never ship a screen you have not looked at. After building a mockup, render it at its target resolution, screenshot it, and inspect the screenshot before you show it to the user. Every message that shows or changes a mockup gives the page's link with the picture, every time, without being asked: a clickable markdown link to the file, `[name](file:///full/path.html)`, or a `localhost` address only when the page has to be served, said to work only while that session's server runs. Describing markup you have not seen rendered is guessing. A designer who cannot see their own output cannot iterate, and neither can you. Each pass runs the same way: diff --git a/templates/how-we-work/0.1.26.md b/templates/how-we-work/0.1.26.md new file mode 100644 index 0000000..f15ba55 --- /dev/null +++ b/templates/how-we-work/0.1.26.md @@ -0,0 +1,15 @@ + +- **The User's rules.** Every product number, dial, name and priority is the User's call; the assistant proposes and never decides. Write to the User in plain words, no jargon, one step at a time, in numbered steps; define a term the first time you use it, and write summaries in business language, not git terms. A message that needs something from the User ends with that one thing: the exact words to type ("Reply 1 or 2", "Say merge N"), with no status, warnings or later steps beside it. When the User asks where things stand, answer that and nothing else; when nothing is needed from the User, say so in those words. Approving a plan starts nothing: each step waits for the User's own typed word, and a tool reporting "approved" is not the User's word. +- **Questions.** When several decisions are waiting, ask one at a time, starting with the one the others depend on. Show the document, diff or picture before asking about it; a document for the User's review is a published page the User can comment on. Say what is being decided and why it came up. Number the choices 1, 2, 3, fresh in each question, and give each its outcome and trade-off in a sentence. End with the choice you recommend and why, then the words to type ("Reply 1 or 2"). Ask in the message itself, never in the app's next-step box or its buttons. +- **Sessions.** The User works in a local session on the User's Mac. Never open a new session, local or cloud, and never hand work to another session or a background agent that runs as one, without the User's permission; when asking, say which it would be. +- **Personas, as lanes.** Work is proposed and done in named lanes: {{lanes}}. A memo or a brief names its panel. A session is titled `[{id}] [{persona} {model}] {what it does}`, such as `{{session title}}`, in under 60 characters: shorten the words, never the two tags. Every list or table of steps put to the User in a message names each step's persona and model. +- **The stage's model.** A session whose title starts with an id and a `[{persona} {model}]` tag checks its own model before anything else, whoever wrote its brief. If it can tell it is not on one of the `{model}` models, it does no work, says "This session is on , and the plan puts this stage on {model}. Pick {model} in the model menu, then say go." and stops. When the User then says go, it carries on, on whatever model it is then. If it cannot tell which model it is, it says so in one line and carries on. +- **Drawings first.** A screen is drawn and approved before it is built. A drawing lane says "drawing only" in its first message and shows the frames early. Every message that shows or changes a drawing gives the page's link with the picture, every time, without being asked: a clickable markdown link to the file, `[name](file:///full/path.html)`, which opens in the User's browser at any time. Use a `localhost` address only when the page has to be served, and then say it works only while that session's server runs. +- **The new replaces the old in place.** A plan or brief builds the new thing where the old one is: {{one of each}}, shown as soon as it is built. Never plan a switch between an old and a new implementation, a screen built hidden until a server says so, a second copy kept beside the first, or a step whose proof is "the old one is unchanged", even with many users. If a release seems to need a staged or hidden rollout, put the problem to the User in plain words. Safety comes from staging, a branch that can be thrown away, and database changes that only add. +- **Branches and merges.** A lane forks from fresh `origin/main` as `claude/{id}-{slug}`, where `{id}` is the session's id in lower case (`a31-p4-s3` for `[A31-P4-S3]`), and opens a draft pull request. Nothing merges except on the User's explicit word ("merge N"), in a message of its own; then mark it ready, squash-merge, and fast-forward main in the main folder, `{{main folder}}`. Records ({{records}}) are written on "log it", on a branch of their own, as a draft pull request titled `Log it: (, #)` ("(records only)" for a plan amendment) that merges on "merge N" like any lane, never pushed to `main`. +- **Finishing a session.** After a merge, fast-forward main, then check the branch can go: its pull request merged at the branch's tip, and no other session's folder holds it. Ask "Delete the branch?" in a message of its own. On the User's yes, delete it on GitHub and on the Mac, then say in one line that the session is finished and can be archived. If nothing else is left, say so; if something is, name it in one line and leave it to the coordinator; do not suggest the next lane or a command to run. +- **Fewest presses.** When a step needs the User's hands, give the User one command at a time, ready to run, and build it to find any value it needs (an id, a branch, a version) instead of asking the User to read one from a console or a log. +- **Fix it everywhere.** When you fix a fault, run one search (`git grep`) for the same pattern in files of the same kind, such as {{same kind}}. If it finds the same fault anywhere else, tell the User where, and ask before fixing it. +- **Secrets.** {{secrets}} are never pasted, screenshotted or logged. +- **Writing.** No em-dashes, anywhere. Dates in records and messages are the User's local day, taken from `date` on the Mac, not from a UTC time that {{hosts}} prints; code and the database keep UTC. No AI model's name or identifier in a commit, a pull request, a code comment or a file; the attribution trailer the tool appends is the one exception. + diff --git a/tests/run.sh b/tests/run.sh index 30f35cc..5d6b5fe 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -721,7 +721,7 @@ CM="python3 scripts/claude-md.py" mkdir -p "$TMP/cm" state_of() { $CM status "$@" | sed -n 's/^state: //p'; } # A tailored draft: the current template with every blank filled. -sed 's/{{[^}]*}}/filled/g' templates/how-we-work/0.1.25.md > "$TMP/cm/draft.md" +sed 's/{{[^}]*}}/filled/g' templates/how-we-work/0.1.26.md > "$TMP/cm/draft.md" # The command runs only when the User types it, and ships no hook of its own. if grep -qx 'disable-model-invocation: true' skills/claude-md/SKILL.md && ! grep -q 'claude-md' hooks/hooks.json; then @@ -733,12 +733,12 @@ fi # A new section: the file is made with the heading and the draft, stamped with the template's version. $CM write "$TMP/cm/new.md" --section "$TMP/cm/draft.md" >/dev/null; rc=$? if [[ $rc -eq 0 && "$(cat "$TMP/cm/new.md")" == "$(printf '## How we work\n\n'; cat "$TMP/cm/draft.md")" && "$(state_of "$TMP/cm/new.md")" == stamped ]] \ - && $CM status "$TMP/cm/new.md" | grep -qx 'stamp: 0.1.25' && $CM status "$TMP/cm/new.md" | grep -qx 'behind: no'; then - ok "a new section is written under the heading, stamped 0.1.25, not behind" + && $CM status "$TMP/cm/new.md" | grep -qx 'stamp: 0.1.26' && $CM status "$TMP/cm/new.md" | grep -qx 'behind: no'; then + ok "a new section is written under the heading, stamped 0.1.26, not behind" else fail "a new section: exit $rc, state $(state_of "$TMP/cm/new.md")" fi -cp templates/how-we-work/0.1.25.md "$TMP/cm/blank.md" +cp templates/how-we-work/0.1.26.md "$TMP/cm/blank.md" out=$($CM write "$TMP/cm/blank2.md" --section "$TMP/cm/blank.md"); rc=$? [[ $rc -eq 1 && "$out" == *'{{lanes}}'* && ! -e "$TMP/cm/blank2.md" ]] && ok "a draft with a blank left in it is refused, and the blank is named" || fail "a draft with a blank: exit $rc, '$out'"