{"content": "rule 58 \u2014 The user tests a design's clickable prototype and approves it before\u2026 \u2014 Message 15725 (2026-10-05): 'ask Dieter to create an interactive prototype! I want to test it first and give feedback before giving it my go', and remove any fact or rule that conflicts. Replaces rule 53's 'the designer decides'. The designer still runs one critique round (messages 12800, 13475) and revises before showing the prototype; then the user clicks through it, gives feedback, and only the user's go starts the build.", "meta": {"from": "journal"}}
{"content": "that Bash call returned 31,871 characters, the largest this session \u2014 It stays in the context for good. If you were looking for one thing in it, the next read can be narrower: grep for the line, sed a range, head the file.", "meta": {"from": "journal"}}
{"content": "rule 48 \u2014 The viewer is built from its component library, and pages only\u2026 \u2014 Message 4258. Every visual piece the viewer shows more than once, or that a user would recognise as the same kind of thing (a dialog, a side panel or inspector, a dropdown, a list row, a switch, a button), is one component in web/src/kit, extracted aggressively, and every page composes those components instead of building its own copy. Before writing markup or styles in a page, look for the kit component that already does it and extend it with a prop; a second hand-built version is a bug. The side panel that animated in but not out, while a separate skill panel did both, is the example.", "meta": {"from": "journal"}}
{"content": "law L3 \u2014 Read narrowly - grep for the line, sed a range, head the file; never\u2026 \u2014 Everything a tool returns stays in the context for good and is paid for on every turn after it. Search before you read, read the range you need, and cap output with grep, head or tail. Read a whole file only when you need all of it.", "meta": {"from": "journal"}}
{"content": "fact 9 \u2014 Every public method on a controller becomes a journal command \u2014 The CLI is generated from the controllers: each public method of Controller, or of a typed controller, turns into journal <noun> <method>. A helper added to the base class therefore becomes a command on every type \u2014 which is how journal <type> handled and journal <type> refuse came to exist, from the CRUD funnel and the refusal funnel. An internal helper on a controller is named with a leading underscore, as _shaped and _status already are, or it ships as a command nobody meant.", "meta": {"from": "journal"}}
{"content": "the log tag does this in one step \u2014 [!log:N] makes the turn itself the log entry; it runs only when it opens the last text of your turn", "meta": {"from": "journal"}}
{"content": "rule 52 \u2014 A chat mark for something the user did sits on the user's side \u2014 Message 10960 (2026-09-25): marks for the user's own actions, such as answering a question, are right-aligned like the user's messages. A mark is put there by giving its card side=user.", "meta": {"from": "journal"}}
{"content": "fact 23 \u2014 Every upgrade brings system sequences and their triggers in line\u2026 \u2014 install.py runs ship_sequences after the migrations on each upgrade, so features/sequences/shipped.py is the whole source: change its wording and the next upgrade updates every journal, no migration needed. Shipped rows carry system=True and are read-only for everyone but SYSTEM (controllers/base.py _shipped).", "meta": {"from": "journal"}}
{"content": "rule 41 \u2014 Keep moving, run the whole suite before every commit, never wait \u2014 The full suite runs in about seven seconds: .venv/bin/python -m pytest -q --timeout=300 -n auto. Run it before every commit instead of picking tests by name. Group rows that sit in the same code into one sitting: write them all, test once, commit once. And never wait, not for a subagent, a build, or an answer you can carry on without. Dispatch it and keep working. If you truly are waiting on something, say so in the work log.", "meta": {"from": "journal"}}
{"content": "rule 42 \u2014 Every user-facing text passes the formatters before it leaves the\u2026 \u2014 Not only a brief. A title, an abstract, an outcome and every section body are read by a person, so each goes through the same formatters on its way to the viewer \u2014 chat turns, activity items, to-do rows, inspector pages, docs alike. One field formatted out of five is not a rule, it is an accident, and it is how a raw tag ended up in the activity list after the tags feature had been stripping them for weeks. When a new field carries words a person reads, it joins the list in the same place.; rule 49 \u2014 A dialog whose content grows keeps one fixed height, and its content\u2026 \u2014 Message 5361, after asking more than once: a dialog that shows output as it arrives (install, update, logs) opens at its final height and never jumps; only its content scrolls.", "meta": {"from": "journal"}}
{"content": "rule 44 \u2014 Release a new version after every significant change \u2014 The user, message 13219 (2026-10-01): 'Don't forget to release new versions every time you do something significant.' Bump VERSION, add a CHANGELOG entry, push main and the tag. Replaces message 5929's release-on-request.; rule 46 \u2014 Only commit and push once the whole journal is proven to boot \u2014 Messages 2178 and 2179. A release that has not been started for real can crash every project that installs it, as 2.78.3 did for Codex and 2.84.0 did to project records. Before every commit and push: the full suite passes, including tests/test_it_boots.py, which installs a packed copy into a fresh project, launches Claude and Codex from it, writes a project record, upgrades again and checks the record survives. When a change touches launching, installing or upgrading, also start a real journal in a scratch project and close it properly afterwards, leaving no process behind.; rule 51 \u2014 Every finished feature is committed, pushed and released with a new\u2026 \u2014 Message 9207 (2026-09-24): when a new feature is ready, commit, push and publish a new tag. This is the user's standing word for releasing, so rule 44's only-when-the-user-says is met by it for finished features; fixes in between wait for the next feature or a patch the user asks for.", "meta": {"from": "journal"}}
{"content": "rule 27 \u2014 Name a declaration with the word a reader already knows \u2014 An attribute, a variable or a field gets the ordinary programming word for what it holds, not an evocative one. was, heard and alone were poetry; aliases, notify_actions and urgent_actions are what they are. The test: could a reader who has never seen this codebase guess what it holds from the name alone? Prose belongs in the help text and the abstract, where it is read as prose. This does not license abbreviations \u2014 a plain word in full, not a short one.; rule 36 \u2014 Clean, DRY, idiomatic before it is committed, never after it is\u2026 \u2014 The user should never be the one who finds duplication, dead code, a clumsy name or a pattern the codebase does not use. Read the diff before every commit as a reviewer would, and fix what is not clean then, not in a follow-up after a complaint.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 the files changed since the last check (`NewTrigger.vue`, `\u2026 \u2014 Code Commandments \u2014 the files changed since the last check (`NewTrigger.vue`, `TriggerEditor.vue`, `TriggerSequences.vue`) breaks a rule. Fix it now, at its SOURCE, while the code is still in front of you: \u00b7 \u2022 control-flow-on-element at /Users/jessegall/projects/agent-journal/.claude/worktrees/main-massimo-wordwright/src/web/src/resource/TriggerEditor.vue:81; control-flow-on-element at /Users/jessegall/projects/agent-journal/.claude/worktrees/main-massimo-wordwright/src/web/src/resource/TriggerEditor.vue:82; index-as-key at /Users/jessegall/projects/agent-journal/.claude/worktrees/main-massimo-wordwright/src/web/src/resource/TriggerEditor.vue:80 \u00b7 LOAD the skill `commandments-frontend-vue-control-flow` before fixing \u2014 load it even if you believe you already have. \u00b7 Run `commandments info <sin>` if a rule is not one you recognise. This check reads a file at a time, so it is not the whole picture \u2014 `judge` still is.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 the files changed since the last check (`ResourceBody.vue`,\u2026 \u2014 Code Commandments \u2014 the files changed since the last check (`ResourceBody.vue`, `ResourceActions.vue`, `NewTrigger.vue`, `TriggerEditor.vue`, `spec.js`) breaks a rule. Fix it now, at its SOURCE, while the code is still in front of you: \u00b7 \u2022 control-flow-on-element at /Users/jessegall/projects/agent-journal/.claude/worktrees/main-massimo-wordwright/src/web/src/resource/TriggerEditor.vue:84; control-flow-on-element at /Users/jessegall/projects/agent-journal/.claude/worktrees/main-massimo-wordwright/src/web/src/resource/TriggerEditor.vue:85; index-as-key at /Users/jessegall/projects/agent-journal/.claude/worktrees/main-massimo-wordwright/src/web/src/resource/TriggerEditor.vue:83 \u00b7 LOAD the skill `commandments-frontend-vue-control-flow` before fixing \u2014 load it even if you believe you already have. \u00b7 Run `commandments info <sin>` if a rule is not one you recognise. This check reads a file at a time, so it is not the whole picture \u2014 `judge` still is.", "meta": {"from": "journal"}}
{"content": "fact 24 \u2014 An answer followed by tool calls can be missing from Claude's\u2026 \u2014 Seen 2026-09-24 for messages 9391-9404: text blocks opening with [!reply:n] that were followed by tool calls never appeared in the session's jsonl (only thinking and tool_use rows did), so the journal never saw them and the replies were lost. When a turn goes on after answering, send the answer with journal message reply <n> \"<text>\" instead of the tag.", "meta": {"from": "journal"}}
{"content": "work 1 in hand \u2014 Build the approved trigger editor and document choice buttons \u2014 if this is not what you are doing, end it or park it and start the work you are in; fact 13 \u2014 This live session runs the installed copy in .journal/journal.pyz \u2014 The running journal (server, hooks, CLI) runs from .journal/journal.pyz with its viewer and skills in .journal/src, never from the repo. A change in the repo reaches it only through python3 src/journal.py --root .journal upgrade, which packs the zip again. A commit alone changes nothing that is running.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 the files changed since the last check (`TurnMessage.vue`,\u2026 \u2014 Code Commandments \u2014 the files changed since the last check (`TurnMessage.vue`, `ChoiceCard.vue`, `buttons.js`) breaks a rule. Fix it now, at its SOURCE, while the code is still in front of you: \u00b7 \u2022 deep-data-reach at /Users/jessegall/projects/agent-journal/.claude/worktrees/main-massimo-wordwright/src/web/src/resource/ChoiceCard.vue:47 \u00b7 LOAD the skill `commandments-frontend-vue-components` before fixing \u2014 load it even if you believe you already have. \u00b7 Run `commandments info <sin>` if a rule is not one you recognise. This check reads a file at a time, so it is not the whole picture \u2014 `judge` still is.", "meta": {"from": "journal"}}
{"content": "rule 54 \u2014 Settings and feature switches are read at boot and on change, never\u2026 \u2014 The user, message 13349: the application boots, determines every feature and setting once, and re-evaluates only when something changes, such as a setting or a plugin. Never lazy-load settings.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 the files changed since the last check (`ResourceRow.vue`,\u2026 \u2014 Code Commandments \u2014 the files changed since the last check (`ResourceRow.vue`, `NewResource.vue`, `StartsOn.vue`) breaks a rule. Fix it now, at its SOURCE, while the code is still in front of you: \u00b7 \u2022 control-flow-on-element at /Users/jessegall/projects/agent-journal/.claude/worktrees/main-massimo-wordwright/src/web/src/resource/NewResource.vue:75 \u00b7 LOAD the skill `commandments-frontend-vue-control-flow` before fixing \u2014 load it even if you believe you already have. \u00b7 Run `commandments info <sin>` if a rule is not one you recognise. This check reads a file at a time, so it is not the whole picture \u2014 `judge` still is.", "meta": {"from": "journal"}}
{"content": "fact 27 \u2014 Running src/journal.py against the live .journal root starts a\u2026 \u2014 Seen 2026-10-01: with VERSION bumped in the tree, src/journal.py --root .journal saw the live server as another build and started a new one on a new port (8431, 8432), and the user's tabs kept losing connection. Run source builds against a throwaway or demo root (~/projects/demo-crumb/.journal), never the live one, until the release is installed.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 the files changed since the last check (`InlineName.vue`, `\u2026 \u2014 Code Commandments \u2014 the files changed since the last check (`InlineName.vue`, `TriggerEditor.vue`) breaks a rule. Fix it now, at its SOURCE, while the code is still in front of you: \u00b7 \u2022 control-flow-on-element at /Users/jessegall/projects/agent-journal/.claude/worktrees/main-massimo-wordwright/src/web/src/resource/TriggerEditor.vue:78; control-flow-on-element at /Users/jessegall/projects/agent-journal/.claude/worktrees/main-massimo-wordwright/src/web/src/resource/TriggerEditor.vue:79; index-as-key at /Users/jessegall/projects/agent-journal/.claude/worktrees/main-massimo-wordwright/src/web/src/resource/TriggerEditor.vue:77 \u00b7 LOAD the skill `commandments-frontend-vue-control-flow` before fixing \u2014 load it even if you believe you already have. \u00b7 Run `commandments info <sin>` if a rule is not one you recognise. This check reads a file at a time, so it is not the whole picture \u2014 `judge` still is.", "meta": {"from": "journal"}}
{"content": "fact 24 \u2014 An answer followed by tool calls can be missing from Claude's\u2026 \u2014 Seen 2026-09-24 for messages 9391-9404: text blocks opening with [!reply:n] that were followed by tool calls never appeared in the session's jsonl (only thinking and tool_use rows did), so the journal never saw them and the replies were lost. When a turn goes on after answering, send the answer with journal message reply <n> \"<text>\" instead of the tag.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 before you wrap up \u2014 you've changed 32 judged files since t\u2026 \u2014 Code Commandments \u2014 before you wrap up: you've changed 32 judged files since the last commit. Consider running `commandments judge --changes` to confirm they conform, and fix any sin at its SOURCE (don't launder a finding with a default/cast/null-check). This is a one-time nudge for this batch \u2014 if you've already judged, or these changes aren't worth a scan, just say so and carry on.; work 1 is still open \u2014 end it or park it before you stop: journal work end 1 --how \"<what landed>\", or journal work park 1 \"<why it waits>\"", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 the files changed since the last check (`ChoiceCard.vue`, `\u2026 \u2014 Code Commandments \u2014 the files changed since the last check (`ChoiceCard.vue`, `triggerWords.js`) breaks a rule. Fix it now, at its SOURCE, while the code is still in front of you: \u00b7 \u2022 deep-data-reach at /Users/jessegall/projects/agent-journal/.claude/worktrees/main-massimo-wordwright/src/web/src/resource/ChoiceCard.vue:53 \u00b7 LOAD the skill `commandments-frontend-vue-components` before fixing \u2014 load it even if you believe you already have. \u00b7 Run `commandments info <sin>` if a rule is not one you recognise. This check reads a file at a time, so it is not the whole picture \u2014 `judge` still is.", "meta": {"from": "journal"}}
{"content": "rule 49 \u2014 A dialog whose content grows keeps one fixed height, and its content\u2026 \u2014 Message 5361, after asking more than once: a dialog that shows output as it arrives (install, update, logs) opens at its final height and never jumps; only its content scrolls.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 the files changed since the last check (`NewResource.vue`,\u2026 \u2014 Code Commandments \u2014 the files changed since the last check (`NewResource.vue`, `ChoiceCard.vue`, `triggerWords.js`) breaks a rule. Fix it now, at its SOURCE, while the code is still in front of you: \u00b7 \u2022 deep-data-reach at /Users/jessegall/projects/agent-journal/.claude/worktrees/main-massimo-wordwright/src/web/src/resource/ChoiceCard.vue:58; deep-data-reach at /Users/jessegall/projects/agent-journal/.claude/worktrees/main-massimo-wordwright/src/web/src/resource/ChoiceCard.vue:64 \u00b7 LOAD the skill `commandments-frontend-vue-components` before fixing \u2014 load it even if you believe you already have. \u00b7 Run `commandments info <sin>` if a rule is not one you recognise. This check reads a file at a time, so it is not the whole picture \u2014 `judge` still is.", "meta": {"from": "journal"}}
{"content": "fact 27 \u2014 Running src/journal.py against the live .journal root starts a\u2026 \u2014 Seen 2026-10-01: with VERSION bumped in the tree, src/journal.py --root .journal saw the live server as another build and started a new one on a new port (8431, 8432), and the user's tabs kept losing connection. Run source builds against a throwaway or demo root (~/projects/demo-crumb/.journal), never the live one, until the release is installed.", "meta": {"from": "journal"}}
{"content": "rule 36 \u2014 Clean, DRY, idiomatic before it is committed, never after it is\u2026 \u2014 The user should never be the one who finds duplication, dead code, a clumsy name or a pattern the codebase does not use. Read the diff before every commit as a reviewer would, and fix what is not clean then, not in a follow-up after a complaint.; work 1 is still open \u2014 end it or park it before you stop: journal work end 1 --how \"<what landed>\", or journal work park 1 \"<why it waits>\"", "meta": {"from": "journal"}}
{"content": "work 1 is still open \u2014 end it or park it before you stop: journal work end 1 --how \"<what landed>\", or journal work park 1 \"<why it waits>\"", "meta": {"from": "journal"}}
{"content": "your chat talked about the journal's workings - \"Still waiting\" \u2014 the user sees replies, reactions, pills and reads themselves; say what the work is instead", "meta": {"from": "journal"}}
{"content": "waiting: 1 unread todo 1", "meta": {"from": "journal"}}
{"content": "waiting: 1 unread todo 1", "meta": {"from": "journal"}}
{"content": "rule 37 \u2014 Close every to-do explicitly with todo done or a Journal commit\u2026 \u2014 Ending work does not close its row. A to-do is closed by journal todo done <n> --how, or by a commit whose message carries Journal: todos done <n> at column 0, several numbers separated by commas. A row left open after its work landed misleads the next session and auto mode.", "meta": {"from": "journal"}}
{"content": "fact 28 \u2014 The designer agent type exists, so design work goes to a subagent \u2014 Since 2026-10-01 .claude/agents/designer.md (Dieter, Opus, Claude Design tools, read-only on the repository) is an agent type; rule 56 says design is a subagent's job, never a helper's.; rule 35 \u2014 Write clean code - one funnel per kind of operation, never the same\u2026 \u2014 Every kind of operation has one funnel: one method that creates, one that saves, one that refuses, one that formats. A second method that does the same thing under another name splits the behaviour, and the two drift apart. Before writing a method, search for the one that already does it and extend that. scripts/checks/funnels.py finds bodies written twice.; rule 50 \u2014 Everything the user does is doable in the viewer \u2014 Message 6710 (2026-09-23): the user never uses the CLI, only the UI; everything should be doable from the viewer. The journal commands are for agents; any action meant for the user (making boards, confirming, accepting, hosting, watching an agent) needs its place in the viewer.; rule 54 \u2014 Settings and feature switches are read at boot and on change, never\u2026 \u2014 The user, message 13349: the application boots, determines every feature and setting once, and re-evaluates only when something changes, such as a setting or a plugin. Never lazy-load settings.; rule 55 \u2014 Always dispatch Codex helpers on gpt-6-sol \u2014 The user's word, message 13431: switch the codex agents to GPT-6-Sol and make it their default. ~/.codex/config.toml names it as the default model too.; rule 56 \u2014 Helpers are for work that writes; subagents read, research and design \u2014 The user, message 13464: there must be a clear distinction. A subagent can be dispatched for anything read-only: research, review, design. A helper is for actual work that writes, best in its own worktree when the work is separate. Dieter designing in Claude Design should have been a subagent, not a helper.; rule 57 \u2014 Never merge the overnight refactor into main before its pull request\u2026 \u2014 Messages 15005, 15006, 15109, 15110 (2026-10-04): all refactor work goes on branch overnight-refactor and reaches the user as one pull request, which they read in the morning; nothing of it is merged into main until they say so. Hotfixes the user explicitly asks for go to main at once and are merged into the branch.; rule 58 \u2014 The user tests a design's clickable prototype and approves it before\u2026 \u2014 Message 15725 (2026-10-05): 'ask Dieter to create an interactive prototype! I want to test it first and give feedback before giving it my go', and remove any fact or rule that conflicts. Replaces rule 53's 'the designer decides'. The designer still runs one critique round (messages 12800, 13475) and revises before showing the prototype; then the user clicks through it, gives feedback, and only the user's go starts the build.", "meta": {"from": "journal"}}
{"content": "your chat talked about the journal's workings - \"to-do 1 is closed\" \u2014 the user sees replies, reactions, pills and reads themselves; say what the work is instead", "meta": {"from": "journal"}}
{"content": "Dieter checked b4d212ef against his prototype in a scratch journal: most of it matches. Please make these fixes, in this order, on your branch (rebase onto overnight-refactor first; it has moved), then report as before. Screenshots of what he saw: /private/tmp/claude-501/-Users-jessegall-projects-agent-journal/c35e7375-7ce3-4bc3-b1ae-7cdf73bd1488/scratchpad/v2/shots/ 1. TriggerSequences picker: list the user's own sequences first; the shipped ones after them under a \"Ship with the journal\" heading. 2. NewTrigger: pin the footer (missing-field line, Cancel, Create trigger) outside the scrolling body, with Dialog's footer slot. 3. NewTrigger: start \"Where the words count\" on Written and run (both). 4. StartsOn: add Board, with its moments, to \"Kind of item\" (the shipped \"Closing a board\" starts on board.finished). 5. ResourceMenu for triggers: Close's line reads \"Moves it to Closed. It stops acting. You can reopen it.\"; Delete is red. 6. TriggerEditor: \"Matched N times, last <when>\" (or \"Never matched yet\") under the summary, from the trigger's fired events. 7. TriggerEditor, shipped trigger: the notice \"Ships with the journal. You can read it and open its sequence, but not change it.\", \"Ships with the journal\" in the header chip instead of \"System\", and no duplicate disabled title field. 8. Change-action warning: no space before the full stop after the sequence name. 9. triggerWords sentence(): end with a full stop when the text is still empty. 10. StartsOn \"Or pick another trigger\": a row that is off reads \"<short what it does> Set it to Start a sequence first.\", e.g. \"It blocks the command.\" 11. ChoiceCard extra buttons: after a press, \"Sent as your message N: \u201c\u2026\u201d. The answer comes in the chat.\" instead of \"You pressed \u2026\". 12. ChoiceCard \"This report asks you to choose\" line: the kit Notice. 13. TriggerSequences: \"Make a new sequence for it\" as a ghost Btn. 14. TriggerEditor name: InlineName style, border only on hover and focus. 15. ChoiceChosen: \"Write more about this\" under the answered card (it opens the chat with the report quoted; add what that needs). 16. ResourceKeywords: the number in the repeat line (\"It is repeated at most once every 100 tool calls\"), read from the setting. 17. ResourceMenu: \"Add to collection\" moves into the \u00b7\u00b7\u00b7 menu for rules, facts and triggers. 18. Triggers controller: the brief is set to the summary sentence for triggers made from the CLI too. Leave fact create as it is: facts keep requiring keywords.", "meta": {"from": "main"}}
{"content": "journal-messages changed since you loaded them \u2014 load one again when you next need it; only the every-start skills are held for", "meta": {"from": "journal"}}
{"content": "rule 27 \u2014 Name a declaration with the word a reader already knows \u2014 An attribute, a variable or a field gets the ordinary programming word for what it holds, not an evocative one. was, heard and alone were poetry; aliases, notify_actions and urgent_actions are what they are. The test: could a reader who has never seen this codebase guess what it holds from the name alone? Prose belongs in the help text and the abstract, where it is read as prose. This does not license abbreviations \u2014 a plain word in full, not a short one.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 the files changed since the last check (`controller.py`, `r\u2026 \u2014 Code Commandments \u2014 the files changed since the last check (`controller.py`, `resource.py`, `summary.py`) breaks a rule. Fix it now, at its SOURCE, while the code is still in front of you: \u00b7 \u2022 python-invented-default at /Users/jessegall/projects/agent-journal/.claude/worktrees/main-massimo-wordwright/src/features/triggers/controller.py:46 \u00b7 LOAD the skill `commandments-python-absence` before fixing \u2014 load it even if you believe you already have. \u00b7 Run `commandments info <sin>` if a rule is not one you recognise. This check reads a file at a time, so it is not the whole picture \u2014 `judge` still is.", "meta": {"from": "journal"}}
{"content": "work 2 in hand \u2014 Fix the 18 review points on the trigger editor and answer card \u2014 if this is not what you are doing, end it or park it and start the work you are in", "meta": {"from": "journal"}}
{"content": "rule 48 \u2014 The viewer is built from its component library, and pages only\u2026 \u2014 Message 4258. Every visual piece the viewer shows more than once, or that a user would recognise as the same kind of thing (a dialog, a side panel or inspector, a dropdown, a list row, a switch, a button), is one component in web/src/kit, extracted aggressively, and every page composes those components instead of building its own copy. Before writing markup or styles in a page, look for the kit component that already does it and extend it with a prop; a second hand-built version is a bug. The side panel that animated in but not out, while a separate skill panel did both, is the example.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 the files changed since the last check (`NewResource.vue`,\u2026 \u2014 Code Commandments \u2014 the files changed since the last check (`NewResource.vue`, `NewTrigger.vue`) breaks a rule. Fix it now, at its SOURCE, while the code is still in front of you: \u00b7 \u2022 control-flow-on-element at /Users/jessegall/projects/agent-journal/.claude/worktrees/main-massimo-wordwright/src/web/src/resource/NewResource.vue:74 \u00b7 LOAD the skill `commandments-frontend-vue-control-flow` before fixing \u2014 load it even if you believe you already have. \u00b7 Run `commandments info <sin>` if a rule is not one you recognise. This check reads a file at a time, so it is not the whole picture \u2014 `judge` still is.", "meta": {"from": "journal"}}
{"content": "chat etiquette - a line from the journal is an instruction, not a message\u2026 \u2014 a turn that only handles a journal line needs no words: act on it, or say once in the chat what you wait on, then carry on; what the user needs to know still goes to the chat", "meta": {"from": "journal"}}
{"content": "law L3 \u2014 Read narrowly - grep for the line, sed a range, head the file; never\u2026 \u2014 Everything a tool returns stays in the context for good and is paid for on every turn after it. Search before you read, read the range you need, and cap output with grep, head or tail. Read a whole file only when you need all of it.; rule 42 \u2014 Every user-facing text passes the formatters before it leaves the\u2026 \u2014 Not only a brief. A title, an abstract, an outcome and every section body are read by a person, so each goes through the same formatters on its way to the viewer \u2014 chat turns, activity items, to-do rows, inspector pages, docs alike. One field formatted out of five is not a rule, it is an accident, and it is how a raw tag ended up in the activity list after the tags feature had been stripping them for weeks. When a new field carries words a person reads, it joins the list in the same place.", "meta": {"from": "journal"}}
{"content": "work 2 in hand \u2014 Fix the 18 review points on the trigger editor and answer card \u2014 if this is not what you are doing, end it or park it and start the work you are in; fact 23 \u2014 Every upgrade brings system sequences and their triggers in line\u2026 \u2014 install.py runs ship_sequences after the migrations on each upgrade, so features/sequences/shipped.py is the whole source: change its wording and the next upgrade updates every journal, no migration needed. Shipped rows carry system=True and are read-only for everyone but SYSTEM (controllers/base.py _shipped).", "meta": {"from": "journal"}}
{"content": "the log tag does this in one step \u2014 [!log:N] makes the turn itself the log entry; it runs only when it opens the last text of your turn", "meta": {"from": "journal"}}
{"content": "rule 38 \u2014 Never change the git branch until the user says so, by name \u2014 The work happens on the branch the user named. That was main until message 5929 and question 80 (2026-09-23), which moved the sins work to the branch sins. Do not create, switch to or merge any other branch unless the user names it in their own words.", "meta": {"from": "journal"}}
{"content": "rule 36 \u2014 Clean, DRY, idiomatic before it is committed, never after it is\u2026 \u2014 The user should never be the one who finds duplication, dead code, a clumsy name or a pattern the codebase does not use. Read the diff before every commit as a reviewer would, and fix what is not clean then, not in a follow-up after a complaint.", "meta": {"from": "journal"}}
{"content": "rule 45 \u2014 No prose words as names in code - said, says, heard, spoke, told\u2026 \u2014 Messages 1360 and 1698. The user has said more than once that code must not read like prose: a variable, attribute, property or function is named for what it holds or does (text, command, labels, lines), never with a verb from a story. 'says' on the Design type (1360) and 'said = call.said.lower()' in features/recital.py (1698) are the examples. Rule 27 states the naming rule; this one carries the words, so writing one of them whispers it. Before writing a name, ask whether a reader who has never seen the code would know what it holds.", "meta": {"from": "journal"}}
{"content": "your last message ran its paragraphs together \u2014 a blank line between parts is what makes a message readable: one thought to a paragraph", "meta": {"from": "journal"}}
{"content": "Taken, thanks: cd9e7eb7 is on overnight-refactor. Next round, from the user (message 16448, on report 77's answer card): 1. The answer card's first option is outlined in the accent colour (.answer.first in ChoiceCard.vue), which reads as the agent's pick though nobody picked it. Drop that outline. When the report's buttons name a pick (add an optional pick: <index> beside buttons, like a question's pick), show that option with the kit's 'The agent's pick' label, the same one OptionList uses. 2. At the top of a report or document that has unanswered choice buttons, show a kit Notice right under the title: 'This report asks you to choose' with a button 'Go to the choice' that scrolls smoothly to the answer card and briefly highlights it. Once answered, the notice goes. 3. A choice title is cut off: 'Apply the suggestions, and give the viewer its own feature text' shows as 'Apply the suggestions, and give the view'. Show the whole label, wrapping. Wait until overnight-refactor contains the commit 'A UnitTextInput in the kit\u2026' (a gate is running now), rebase onto it, run the full suite, and report as before.", "meta": {"from": "main"}}
{"content": "work 4 in hand \u2014 Answer card pick, notice and full labels \u2014 if this is not what you are doing, end it or park it and start the work you are in", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 before you commit \u2014 you've changed 6 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 6 judged files since the last commit. Consider running `commandments judge --changes` to confirm they conform, and fix any sin at its SOURCE (don't launder a finding with a default/cast/null-check). This is a one-time nudge for this batch \u2014 if you've already judged, or these changes aren't worth a scan, just say so and carry on.; rule 57 \u2014 Never merge the overnight refactor into main before its pull request\u2026 \u2014 Messages 15005, 15006, 15109, 15110 (2026-10-04): all refactor work goes on branch overnight-refactor and reaches the user as one pull request, which they read in the morning; nothing of it is merged into main until they say so. Hotfixes the user explicitly asks for go to main at once and are merged into the branch.", "meta": {"from": "journal"}}
{"content": "fact 27 \u2014 Running src/journal.py against the live .journal root starts a\u2026 \u2014 Seen 2026-10-01: with VERSION bumped in the tree, src/journal.py --root .journal saw the live server as another build and started a new one on a new port (8431, 8432), and the user's tabs kept losing connection. Run source builds against a throwaway or demo root (~/projects/demo-crumb/.journal), never the live one, until the release is installed.; rule 54 \u2014 Settings and feature switches are read at boot and on change, never\u2026 \u2014 The user, message 13349: the application boots, determines every feature and setting once, and re-evaluates only when something changes, such as a setting or a plugin. Never lazy-load settings.", "meta": {"from": "journal"}}
{"content": "rule 35 \u2014 Write clean code - one funnel per kind of operation, never the same\u2026 \u2014 Every kind of operation has one funnel: one method that creates, one that saves, one that refuses, one that formats. A second method that does the same thing under another name splits the behaviour, and the two drift apart. Before writing a method, search for the one that already does it and extend that. scripts/checks/funnels.py finds bodies written twice.", "meta": {"from": "journal"}}
{"content": "work 4 is still open \u2014 end it or park it before you stop: journal work end 4 --how \"<what landed>\", or journal work park 4 \"<why it waits>\"", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 before you wrap up \u2014 you've changed 3 judged files since th\u2026 \u2014 Code Commandments \u2014 before you wrap up: you've changed 3 judged files since the last commit. Consider running `commandments judge --changes` to confirm they conform, and fix any sin at its SOURCE (don't launder a finding with a default/cast/null-check). This is a one-time nudge for this batch \u2014 if you've already judged, or these changes aren't worth a scan, just say so and carry on.", "meta": {"from": "journal"}}
{"content": "work 4 is still open \u2014 end it or park it before you stop: journal work end 4 --how \"<what landed>\", or journal work park 4 \"<why it waits>\"", "meta": {"from": "journal"}}
{"content": "work 4 is still open \u2014 end it or park it before you stop: journal work end 4 --how \"<what landed>\", or journal work park 4 \"<why it waits>\"", "meta": {"from": "journal"}}
{"content": "fact 18 \u2014 cProfile inflates the slow-request profiles about tenfold \u2014 The faults feature writes a profile when a request passes its budget, and the profile is taken with cProfile, which adds per-call overhead. On 2026-09-22 /api/summary profiled at 58ms with 48ms inside Resource.fork's deep copy; with the profiler off the same call ran in 2 to 7ms. Read the profile for where the time goes in relative terms, then time the call with curl before changing anything.", "meta": {"from": "journal"}}
{"content": "More on point 2 of your current round, from the user (message 16487, in capitals): today's 'This report asks you to choose, at the end. Go to the choice' is a grey line of text and a link; it must be an obvious call to action. Make it a band the eye cannot miss, right under the title: the kit Notice in its accent or attention band (Mies added bands to Notice: report, wait, danger, info; use or add the one that reads as 'needs you'), an icon, a bold line 'Your answer is needed', a short line saying what is being asked (the answer card's question), and a primary Btn 'Go to the choice' that scrolls to the card and highlights it. The same band shows in the chat card and the side panel for that report. It goes once answered.", "meta": {"from": "main"}}
{"content": "rule 48 \u2014 The viewer is built from its component library, and pages only\u2026 \u2014 Message 4258. Every visual piece the viewer shows more than once, or that a user would recognise as the same kind of thing (a dialog, a side panel or inspector, a dropdown, a list row, a switch, a button), is one component in web/src/kit, extracted aggressively, and every page composes those components instead of building its own copy. Before writing markup or styles in a page, look for the kit component that already does it and extend it with a prop; a second hand-built version is a bug. The side panel that animated in but not out, while a separate skill panel did both, is the example.", "meta": {"from": "journal"}}
{"content": "rule 42 \u2014 Every user-facing text passes the formatters before it leaves the\u2026 \u2014 Not only a brief. A title, an abstract, an outcome and every section body are read by a person, so each goes through the same formatters on its way to the viewer \u2014 chat turns, activity items, to-do rows, inspector pages, docs alike. One field formatted out of five is not a rule, it is an accident, and it is how a raw tag ended up in the activity list after the tags feature had been stripping them for weeks. When a new field carries words a person reads, it joins the list in the same place.", "meta": {"from": "journal"}}
{"content": "your command ran 30s in the foreground and was moved to the background \u2014 carry on with other work; you are told when it ends. Start a command you expect to take long in the background yourself; work 4 in hand \u2014 Answer card pick, notice and full labels \u2014 if this is not what you are doing, end it or park it and start the work you are in", "meta": {"from": "journal"}}
{"content": "law L3 \u2014 Read narrowly - grep for the line, sed a range, head the file; never\u2026 \u2014 Everything a tool returns stays in the context for good and is paid for on every turn after it. Search before you read, read the range you need, and cap output with grep, head or tail. Read a whole file only when you need all of it.", "meta": {"from": "journal"}}
{"content": "work 4 is still open \u2014 end it or park it before you stop: journal work end 4 --how \"<what landed>\", or journal work park 4 \"<why it waits>\"", "meta": {"from": "journal"}}
{"content": "fact 13 \u2014 This live session runs the installed copy in .journal/journal.pyz \u2014 The running journal (server, hooks, CLI) runs from .journal/journal.pyz with its viewer and skills in .journal/src, never from the repo. A change in the repo reaches it only through python3 src/journal.py --root .journal upgrade, which packs the zip again. A commit alone changes nothing that is running.", "meta": {"from": "journal"}}
{"content": "work 4 is still open \u2014 end it or park it before you stop: journal work end 4 --how \"<what landed>\", or journal work park 4 \"<why it waits>\"", "meta": {"from": "journal"}}
{"content": "work 4 is still open \u2014 end it or park it before you stop: journal work end 4 --how \"<what landed>\", or journal work park 4 \"<why it waits>\"", "meta": {"from": "journal"}}
{"content": "From now on, never commit src/web/dist: commit only your source changes, and I build the viewer once after taking your work (your own vite build for checking in a browser stays local and uncommitted). If your branch already has a dist commit on top, drop it when you next rebase (git rebase -i is not available; use git rebase --onto or reset --soft and recommit your source). The tip of overnight-refactor moves soon with the commit 'The Documents list shows summaries in plain words'; rebase onto that when you are ready to report.", "meta": {"from": "main"}}
{"content": "you stopped 5 minutes ago with work 4, Answer card pick, notice and full\u2026 \u2014 carry on with it now. If it waits on something outside your hands, say journal work await \"<what you wait for>\"; if it waits on the user, put the question on its row with journal todo ask and take the next ready row; if something else goes first, journal work park 4 \"<why>\".", "meta": {"from": "journal"}}
{"content": "the await tag does this in one step \u2014 [!await] makes the rest of the turn what you wait for; [!await on=(\"<id>\", \"helper:<n>\")] waits on those; it runs only when it opens the last text of your turn", "meta": {"from": "journal"}}
{"content": "Next, from the user (message 16527, to-do 2908, in capitals): a user must always be able to answer in their own words. Every set of choice buttons, the answer card on reports and documents and the buttons on chat messages (find where message buttons render: grep buttons in src/web/src/chat), ends with a built-in 'Answer in your own words' that opens a text box in place and sends what is typed as the user's message about that row, the same path a button's say takes. It is part of the component, so no message's author can forget it. Fold it into your current round; source only, no dist.", "meta": {"from": "main"}}
{"content": "the full suite, which is running behind another run's lock came back\u2026", "meta": {"from": "journal"}}
{"content": "rule 41 \u2014 Keep moving, run the whole suite before every commit, never wait \u2014 The full suite runs in about seven seconds: .venv/bin/python -m pytest -q --timeout=300 -n auto. Run it before every commit instead of picking tests by name. Group rows that sit in the same code into one sitting: write them all, test once, commit once. And never wait, not for a subagent, a build, or an answer you can carry on without. Dispatch it and keep working. If you truly are waiting on something, say so in the work log.", "meta": {"from": "journal"}}
{"content": "rule 38 \u2014 Never change the git branch until the user says so, by name \u2014 The work happens on the branch the user named. That was main until message 5929 and question 80 (2026-09-23), which moved the sins work to the branch sins. Do not create, switch to or merge any other branch unless the user names it in their own words.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 before you commit \u2014 you've changed 15 judged files since th\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 15 judged files since the last commit. Consider running `commandments judge --changes` to confirm they conform, and fix any sin at its SOURCE (don't launder a finding with a default/cast/null-check). This is a one-time nudge for this batch \u2014 if you've already judged, or these changes aren't worth a scan, just say so and carry on.; fact 24 \u2014 An answer followed by tool calls can be missing from Claude's\u2026 \u2014 Seen 2026-09-24 for messages 9391-9404: text blocks opening with [!reply:n] that were followed by tool calls never appeared in the session's jsonl (only thinking and tool_use rows did), so the journal never saw them and the replies were lost. When a turn goes on after answering, send the answer with journal message reply <n> \"<text>\" instead of the tag.; rule 46 \u2014 Only commit and push once the whole journal is proven to boot \u2014 Messages 2178 and 2179. A release that has not been started for real can crash every project that installs it, as 2.78.3 did for Codex and 2.84.0 did to project records. Before every commit and push: the full suite passes, including tests/test_it_boots.py, which installs a packed copy into a fresh project, launches Claude and Codex from it, writes a project record, upgrades again and checks the record survives. When a change touches launching, installing or upgrading, also start a real journal in a scratch project and close it properly afterwards, leaving no process behind.; rule 52 \u2014 A chat mark for something the user did sits on the user's side \u2014 Message 10960 (2026-09-25): marks for the user's own actions, such as answering a question, are right-aligned like the user's messages. A mark is put there by giving its card side=user.", "meta": {"from": "journal"}}
{"content": "work 4 in hand \u2014 Answer card pick, notice and full labels \u2014 if this is not what you are doing, end it or park it and start the work you are in", "meta": {"from": "journal"}}
{"content": "work 4 is still open \u2014 end it or park it before you stop: journal work end 4 --how \"<what landed>\", or journal work park 4 \"<why it waits>\"", "meta": {"from": "journal"}}
{"content": "work 4 is still open \u2014 end it or park it before you stop: journal work end 4 --how \"<what landed>\", or journal work park 4 \"<why it waits>\"", "meta": {"from": "journal"}}
{"content": "work 4 is still open \u2014 end it or park it before you stop: journal work end 4 --how \"<what landed>\", or journal work park 4 \"<why it waits>\"", "meta": {"from": "journal"}}
{"content": "your chat talked about the journal's workings - \"Still waiting\" \u2014 the user sees replies, reactions, pills and reads themselves; say what the work is instead", "meta": {"from": "journal"}}
{"content": "you stopped 5 minutes ago with work 4, Answer card pick, notice and full\u2026 \u2014 carry on with it now. If it waits on something outside your hands, say journal work await \"<what you wait for>\"; if it waits on the user, put the question on its row with journal todo ask and take the next ready row; if something else goes first, journal work park 4 \"<why>\".", "meta": {"from": "journal"}}
{"content": "work 4 is still open \u2014 end it or park it before you stop: journal work end 4 --how \"<what landed>\", or journal work park 4 \"<why it waits>\"", "meta": {"from": "journal"}}
{"content": "work 4 is still open \u2014 end it or park it before you stop: journal work end 4 --how \"<what landed>\", or journal work park 4 \"<why it waits>\"", "meta": {"from": "journal"}}
{"content": "work 4 is still open \u2014 end it or park it before you stop: journal work end 4 --how \"<what landed>\", or journal work park 4 \"<why it waits>\"", "meta": {"from": "journal"}}
{"content": "work 4 is still open \u2014 end it or park it before you stop: journal work end 4 --how \"<what landed>\", or journal work park 4 \"<why it waits>\"", "meta": {"from": "journal"}}
{"content": "rule 37 \u2014 Close every to-do explicitly with todo done or a Journal commit\u2026 \u2014 Ending work does not close its row. A to-do is closed by journal todo done <n> --how, or by a commit whose message carries Journal: todos done <n> at column 0, several numbers separated by commas. A row left open after its work landed misleads the next session and auto mode.", "meta": {"from": "journal"}}
{"content": "fact 9 \u2014 Every public method on a controller becomes a journal command \u2014 The CLI is generated from the controllers: each public method of Controller, or of a typed controller, turns into journal <noun> <method>. A helper added to the base class therefore becomes a command on every type \u2014 which is how journal <type> handled and journal <type> refuse came to exist, from the CRUD funnel and the refusal funnel. An internal helper on a controller is named with a leading underscore, as _shaped and _status already are, or it ships as a command nobody meant.; rule 36 \u2014 Clean, DRY, idiomatic before it is committed, never after it is\u2026 \u2014 The user should never be the one who finds duplication, dead code, a clumsy name or a pattern the codebase does not use. Read the diff before every commit as a reviewer would, and fix what is not clean then, not in a follow-up after a complaint.; rule 55 \u2014 Always dispatch Codex helpers on gpt-6-sol \u2014 The user's word, message 13431: switch the codex agents to GPT-6-Sol and make it their default. ~/.codex/config.toml names it as the default model too.; rule 56 \u2014 Helpers are for work that writes; subagents read, research and design \u2014 The user, message 13464: there must be a clear distinction. A subagent can be dispatched for anything read-only: research, review, design. A helper is for actual work that writes, best in its own worktree when the work is separate. Dieter designing in Claude Design should have been a subagent, not a helper.", "meta": {"from": "journal"}}
{"content": "your message 85 names 120 without saying what they are \u2014 put the type before each number, like message 1712 or to-do 644, so the chat links it: journal message edit 85 \"<the text>\"; rule 45 \u2014 No prose words as names in code - said, says, heard, spoke, told\u2026 \u2014 Messages 1360 and 1698. The user has said more than once that code must not read like prose: a variable, attribute, property or function is named for what it holds or does (text, command, labels, lines), never with a verb from a story. 'says' on the Design type (1360) and 'said = call.said.lower()' in features/recital.py (1698) are the examples. Rule 27 states the naming rule; this one carries the words, so writing one of them whispers it. Before writing a name, ask whether a reader who has never seen the code would know what it holds.", "meta": {"from": "journal"}}
{"content": "rule 59 \u2014 Every viewer heading and label says plainly what it is about \u2014 The user, message 16499 (2026-10-06), after 'Where the words count' in the trigger editor: 'the stupid ass titles like where the words count, it doesnt say anything, and im not sure why this keeps happening'. Earlier the same in messages 16380 and 16484 ('Answer with it'). A heading names what the user is choosing or reading in the words a newcomer uses ('Watch for the words in', 'Tell the user in the chat'), never a phrase to decode; a label on a button says what happens when pressed. Test: would someone who never saw the feature know what the heading is about? Applies to designers' prototypes, helpers' builds and shipped sequence and trigger titles alike.; work deferred in words, not parked \u2014 \"once the card is\" is the title of a to-do: journal todo create \"<title>\" --brief, then say so", "meta": {"from": "journal"}}
{"content": "rule 27 \u2014 Name a declaration with the word a reader already knows \u2014 An attribute, a variable or a field gets the ordinary programming word for what it holds, not an evocative one. was, heard and alone were poetry; aliases, notify_actions and urgent_actions are what they are. The test: could a reader who has never seen this codebase guess what it holds from the name alone? Prose belongs in the help text and the abstract, where it is read as prose. This does not license abbreviations \u2014 a plain word in full, not a short one.", "meta": {"from": "journal"}}
{"content": "your command ran 35s in the foreground and was moved to the background \u2014 carry on with other work; you are told when it ends. Start a command you expect to take long in the background yourself", "meta": {"from": "journal"}}
{"content": "chat etiquette - a line from the journal is an instruction, not a message\u2026 \u2014 a turn that only handles a journal line needs no words: act on it, or say once in the chat what you wait on, then carry on; what the user needs to know still goes to the chat", "meta": {"from": "journal"}}
{"content": "work 5 is still open, with nothing logged \u2014 journal work log 5 \"<what was decided or done, and why>\" \u2014 then journal work end 5 --how \"<what landed>\", or journal work park 5 \"<why it waits>\"", "meta": {"from": "journal"}}
{"content": "your last message ran its paragraphs together \u2014 a blank line between parts is what makes a message readable: one thought to a paragraph", "meta": {"from": "journal"}}
