{"content": "todo 1 next", "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 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 61 \u2014 Features wait as pull requests until approved; only hotfixes merge\u2026 \u2014 Message 17118 (2026-10-06), after the overnight refactor merged as 2.252.0: start new work in a new branch, do not merge, write the pull request. Every pull request or new feature is parked until the user approves it. Hotfixes can be merged into main immediately (by a dispatched agent in a worktree of main, rule 60).; rule 64 \u2014 A finished feature is merged into main without waiting for approval \u2014 The user, message 17815 (2026-10-07): 'make sure that no pull requests are lingering on the repository. You may merge them into main... You are allowed to merge everything into main once the feature is completed.' This replaces rule 61's wait for approval: a feature still goes on its own branch, and once it is complete, tested and its whole suite passes, it is merged into main and released, and no pull request is left open.", "meta": {"from": "journal"}}
{"content": "fact 34 \u2014 A hooks list in a checkout's .claude/settings.json stops every\u2026 \u2014 Seen 2026-10-08: since commit 707a82915 the committed .claude/settings.json held {\"hooks\": []}; current Claude Code answers a hooks value that is not an object with a SettingsWarning dialog, which a headless helper cannot answer, so helpers 183 and 184 exited before doing anything (their launch logs in .journal/runtime/launches/ show it). This repository's journal hooks live in settings.local.json; the committed settings.json stays {}.; 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 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": "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.; rule 65 \u2014 Run only new and affected tests while working; the whole suite only\u2026 \u2014 The user, messages 17914 to 17917 (2026-10-07): 'stop running the whole test suite and wasting my time... please only run the new or affected tests, and then, whenever you are merging to main or publishing to main, you can run the full test suite.' Replaces rule 41's whole suite before every commit: on a feature branch, run the tests beside what changed (journal check touched, or the feature's test.py and the browser scenarios it touches); the whole suite runs once, before a merge into main and its release.", "meta": {"from": "journal"}}
{"content": "your command ran 34s 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": "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": "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 generated runs, boot test and machines test came back - Run the generated\u2026", "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": "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.; 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": "timing the slow generated test on this branch and on main came back - Time the\u2026", "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 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 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.; fact 25 \u2014 A designer's install packs the whole tree, half-done server edits\u2026 \u2014 2026-09-25: Eames and Saul run python3 src/journal.py --root .journal upgrade after their viewer builds; it packs every file in src, so a server handler I was halfway through writing went live and raised on every PostToolUse hook. While designers work in parallel, keep server edits whole between tool calls (write and test in the scratchpad first), and reinstall after reverting anything.; 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.", "meta": {"from": "journal"}}
{"content": "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 58 \u2014 A design runs three critique rounds, then is built on a branch \u2014 Messages 17276 and 17281 (2026-10-06): the norm is a three-round cycle. Round by round, the designer designs (or revises), separate critic agents review the design through their lenses (the critic agent type, .claude/agents/critic.md: read-only, with a browser; one per lens, such as first-time, native, words and parity), and the designer adjusts it to their findings; three rounds in all. The three rounds stand in for the user's approval of the design: the user does not approve it. After the third round the design is built on a branch of its own, which ends in a pull request that waits for the user's approval (rule 61). Replaces message 15725's prototype approval.; rule 60 \u2014 A hotfix is done by a dispatched agent in a worktree of main \u2014 Message 16836 (2026-10-06): the orchestrator cut a worktree under .claude/worktrees for a Codex hotfix, its session moved to a new environment and the user's messages stopped reaching it. The user: when working on a branch and a hotfix comes in, create a worktree of main and dispatch an agent to do that work. The orchestrator stays on its branch and in its environment, and never cds into another checkout.; rule 63 \u2014 A small design is drawn once and the user approves it, with no\u2026 \u2014 The user, messages 17628 and 17629 (2026-10-07), about the tooltip and waiting-status designs: 'This design round doesn't really need multiple rounds... I just want the designer agent to design it, and I will approve it.' Rule 58's three critique rounds are for large designs such as the phone app; a small one (a tooltip, a status word, one control) is drawn once by the designer, the link goes to the user, and it is built once the user approves it.", "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": "that Bash call returned 28,171 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 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 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.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 before you commit \u2014 you've changed 236 judged files since t\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 236 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": "your command ran 31s 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": "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 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 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 40 \u2014 A feature is named for what it is, never for its machinery \u2014 Messages 599, 600 and 703. A feature is a capability the user would name and would think of switching off. File tracking, a write gate, a phrase bank, a tree diff are services used inside a feature, not features of their own: they live in the feature they serve. Before adding a directory under features/, say what the user would call it; if the answer names a mechanism, it belongs inside something else. Report 16 holds the grouping this implies.; rule 61 \u2014 Features wait as pull requests until approved; only hotfixes merge\u2026 \u2014 Message 17118 (2026-10-06), after the overnight refactor merged as 2.252.0: start new work in a new branch, do not merge, write the pull request. Every pull request or new feature is parked until the user approves it. Hotfixes can be merged into main immediately (by a dispatched agent in a worktree of main, rule 60).", "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": "Code Commandments \u2014 `owner.py`, changed since the last check, breaks a rule. Fi\u2026 \u2014 Code Commandments \u2014 `owner.py`, changed since the last check, breaks a rule. Fix it now, at its SOURCE, while the code is still in front of you: \u00b7 \u2022 python-placeholder-filled-data at /Users/jessegall/projects/agent-journal/.claude/worktrees/record-two-writers/src/features/hosted_journal/owner.py:119 \u00b7 LOAD the skill `commandments-python-type-honesty` 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 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": "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": "work 2 in hand \u2014 Plan 28 members write to a hosted journal \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 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.; rule 65 \u2014 Run only new and affected tests while working; the whole suite only\u2026 \u2014 The user, messages 17914 to 17917 (2026-10-07): 'stop running the whole test suite and wasting my time... please only run the new or affected tests, and then, whenever you are merging to main or publishing to main, you can run the full test suite.' Replaces rule 41's whole suite before every commit: on a feature branch, run the tests beside what changed (journal check touched, or the feature's test.py and the browser scenarios it touches); the whole suite runs once, before a merge into main and its release.", "meta": {"from": "journal"}}
{"content": "rule 59 \u2014 Every viewer heading and label says plainly what it is about \u2014 The user, messages 16499, 16839, 16844, 16989, 16992 and 16993 (2026-10-06), after 'Where the words count', 'Watch for the words in', 'This project', 'This browser' and 'Stop the journal' as tab names: viewer text reads like Linear, GitHub or Vercel. A place (page, tab, group, sidebar item) is a short noun: Settings, Project, Browser, Services, Updates, Plugins; never 'This project' or a phrase. A button is a verb for what happens: Stop, Install, Copy link, Pause the plan. A heading names what the reader looks at, and its options finish its sentence: 'Trigger when' / 'A word is written'. Plain literal words: no metaphor or whimsy ('kettle on, waiting'), no app speaking as I, none of the journal's internal words (row, hook, nudge, engine, slate). One word for one thing everywhere, sentence case, as short as it can be while clear. Applies to designers' prototypes, helpers' builds, the viewer's JavaScript lists, feature details, and shipped sequence and trigger titles alike.", "meta": {"from": "journal"}}
{"content": "13 facts standing, read them \u2014 9. Every public method on a controller becomes a journal command; 13. This live session runs the installed copy in .journal/journal.pyz; 18. cProfile inflates the slow-request profiles about tenfold; 20. A slim supervisor holds the agent and a worker reloads on every build; 23. Every upgrade brings system sequences and their triggers in line with the code; 24. An answer followed by tool calls can be missing from Claude's transcript; 25. A designer's install packs the whole tree, half-done server edits included; 26. Claude Code reads agent profiles when a session starts; 27. Running src/journal.py against the live .journal root starts a second server; 28. The designer agent type exists, so design work goes to a subagent; 29. Codex's transcript records the end of every exec session, polled or not; 30. The tunler server refuses TLS for any subdomain without a tunnel; 34. A hooks list in a checkout's .claude/settings.json stops every helper at start; 40 rules in force, read them \u2014 7. journal disable must only ever be run because the user explicitly asked for it,; 9. Research dispatched to a subagent ends in a REPORT for the user, compiled by the; 13. A title names the thing in at most 80 characters and never explains it with a co; 14. A small journal capability is a feature under features, with at most one test; 17. Do not restart the viewer for frontend-only changes; 18. Provider-specific code belongs in providers, never features; 19. Providers report facts; features decide behavior; 22. File distinct user work requests immediately; 27. Name a declaration with the word a reader already knows; 30. The viewer has one API client, and every piece of it does one job; 31. Every finding a reviewing agent reports becomes its own to-do; 35. Write clean code - one funnel per kind of operation, never the same method twice; 36. Clean, DRY, idiomatic before it is committed, never after it is complained about; 37. Close every to-do explicitly with todo done or a Journal commit trailer; 38. Never change the git branch until the user says so, by name; 39. Use only registered exclamation response tags; 40. A feature is named for what it is, never for its machinery; 41. Keep moving, run the whole suite before every commit, never wait; 42. Every user-facing text passes the formatters before it leaves the server; 43. A request or hook over its budget is fixed before the next release; 45. No prose words as names in code - said, says, heard, spoke, told, shown, became; 46. Only commit and push once the whole journal is proven to boot; 47. The journal sets itself up once, when the server starts, never per command; 48. The viewer is built from its component library, and pages only compose it; 49. A dialog whose content grows keeps one fixed height, and its content scrolls; 50. Everything the user does is doable in the viewer; 51. Every finished feature is committed, pushed and released with a new version tag; 52. A chat mark for something the user did sits on the user's side; 54. Settings and feature switches are read at boot and on change, never per call; 55. Always dispatch Codex helpers on gpt-6-sol; 56. Helpers are for work that writes; subagents read, research and design; 57. Never merge the overnight refactor into main before its pull request is approved; 58. A design runs three critique rounds, then is built on a branch; 59. Every viewer heading and label says plainly what it is about; 60. A hotfix is done by a dispatched agent in a worktree of main; 61. Features wait as pull requests until approved; only hotfixes merge at once; 62. The voice profile shapes only the agent's chat speech, never code or text; 63. A small design is drawn once and the user approves it, with no critique rounds; 64. A finished feature is merged into main without waiting for approval; 65. Run only new and affected tests while working; the whole suite only before main", "meta": {"from": "journal"}}
{"content": "work 2 in hand \u2014 Plan 28 members write to a hosted journal \u2014 if this is not what you are doing, end it or park it and start the work you are in; 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": "Code Commandments \u2014 the edit you just made to `gate.py` breaks a rule. Fix it n\u2026 \u2014 Code Commandments \u2014 the edit you just made to `gate.py` breaks a rule. Fix it now, at its SOURCE, while the code is still in front of you: \u00b7 \u2022 python-placeholder-filled-data at /Users/jessegall/projects/agent-journal/.claude/worktrees/record-two-writers/src/features/members/gate.py:95 \u00b7 LOAD the skill `commandments-python-type-honesty` 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 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": "rule 47 \u2014 The journal sets itself up once, when the server starts, never per\u2026 \u2014 Messages 2220 and 2224. Discovering features and their handlers, seating the feature rows and the rename sweep happen once, at server boot, and again only when a feature is switched on or off, a plugin changes or an environment is added: features.load keeps a set-up generation per journal (SEATED) and redoes the work only when that generation moves. A command, a request or a hook uses what is already there; nothing in their path may rediscover handlers or rescan folders. A cost that repeats per call is a bug to fix, not a budget to raise.", "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 58 \u2014 A design runs three critique rounds, then is built on a branch \u2014 Messages 17276 and 17281 (2026-10-06): the norm is a three-round cycle. Round by round, the designer designs (or revises), separate critic agents review the design through their lenses (the critic agent type, .claude/agents/critic.md: read-only, with a browser; one per lens, such as first-time, native, words and parity), and the designer adjusts it to their findings; three rounds in all. The three rounds stand in for the user's approval of the design: the user does not approve it. After the third round the design is built on a branch of its own, which ends in a pull request that waits for the user's approval (rule 61). Replaces message 15725's prototype approval.; rule 63 \u2014 A small design is drawn once and the user approves it, with no\u2026 \u2014 The user, messages 17628 and 17629 (2026-10-07), about the tooltip and waiting-status designs: 'This design round doesn't really need multiple rounds... I just want the designer agent to design it, and I will approve it.' Rule 58's three critique rounds are for large designs such as the phone app; a small one (a tooltip, a status word, one control) is drawn once by the designer, the link goes to the user, and it is built once the user approves it.; 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.; 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": "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 64 \u2014 A finished feature is merged into main without waiting for approval \u2014 The user, message 17815 (2026-10-07): 'make sure that no pull requests are lingering on the repository. You may merge them into main... You are allowed to merge everything into main once the feature is completed.' This replaces rule 61's wait for approval: a feature still goes on its own branch, and once it is complete, tested and its whole suite passes, it is merged into main and released, and no pull request is left open.", "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 21 judged files since t\u2026 \u2014 Code Commandments \u2014 before you wrap up: you've changed 21 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": "the viewer build for 3267 came back - Build the viewer completed - carry on\u2026", "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.; 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.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 the edit you just made to `roles.py` breaks a rule. Fix it\u2026 \u2014 Code Commandments \u2014 the edit you just made to `roles.py` breaks a rule. Fix it now, at its SOURCE, while the code is still in front of you: \u00b7 \u2022 python-placeholder-filled-data at /Users/jessegall/projects/agent-journal/.claude/worktrees/record-two-writers/src/features/members/roles.py:61; python-placeholder-filled-data at /Users/jessegall/projects/agent-journal/.claude/worktrees/record-two-writers/src/features/members/roles.py:70 \u00b7 LOAD the skill `commandments-python-type-honesty` 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 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": "work 2 in hand \u2014 Plan 28 members write to a hosted journal \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 the edit you just made to `People.vue` breaks a rule. Fix i\u2026 \u2014 Code Commandments \u2014 the edit you just made to `People.vue` 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/record-two-writers/src/web/src/layout/People.vue:66 \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": "rule 61 \u2014 Features wait as pull requests until approved; only hotfixes merge\u2026 \u2014 Message 17118 (2026-10-06), after the overnight refactor merged as 2.252.0: start new work in a new branch, do not merge, write the pull request. Every pull request or new feature is parked until the user approves it. Hotfixes can be merged into main immediately (by a dispatched agent in a worktree of main, rule 60).", "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": "Code Commandments \u2014 before you wrap up \u2014 you've changed 19 judged files since t\u2026 \u2014 Code Commandments \u2014 before you wrap up: you've changed 19 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": "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": "the viewer build for 3268 came back - Build the viewer for to-do 3268\u2026", "meta": {"from": "journal"}}
{"content": "law L5 \u2014 Every subagent dispatch names the agent - a human name, a little\u2026 \u2014 A name is how the user and the chat tell subagents apart and how they are messaged later; an id or a task line is not a name. Start the dispatch's description with the name, a colon, then the task, such as \"Dr. Einstein: profile the slow hooks\" or \"Coco Rams: draw the plan card\". A designer can borrow from famous designers, a researcher from famous scientists, mixed up for fun.; 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": "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.; 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).; fact 26 \u2014 Claude Code reads agent profiles when a session starts \u2014 Seen 2026-09-26: after the board-filler's profile in .claude/agents gained its steps and the Grep rule, dispatches from the running session still used the old profile (a 3.5-minute first question, shell grep refused); after the session restarted, the same request took 21 seconds with 4 calls. A change to an agent type reaches only sessions started after it is written.; fact 34 \u2014 A hooks list in a checkout's .claude/settings.json stops every\u2026 \u2014 Seen 2026-10-08: since commit 707a82915 the committed .claude/settings.json held {\"hooks\": []}; current Claude Code answers a hooks value that is not an object with a SettingsWarning dialog, which a headless helper cannot answer, so helpers 183 and 184 exited before doing anything (their launch logs in .journal/runtime/launches/ show it). This repository's journal hooks live in settings.local.json; the committed settings.json stays {}.; rule 43 \u2014 A request or hook over its budget is fixed before the next release \u2014 Comment 1151 on this rule. When the faults feature reports a request, a hook or a command slower than its budget, file it as a to-do at once. It does not jump ahead of the work in hand, but no version is published while one is still open: profile it, fix it, and verify the new time before the release goes out. The budget is 50ms, because everything runs locally against files.; 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 60 \u2014 A hotfix is done by a dispatched agent in a worktree of main \u2014 Message 16836 (2026-10-06): the orchestrator cut a worktree under .claude/worktrees for a Codex hotfix, its session moved to a new environment and the user's messages stopped reaching it. The user: when working on a branch and a hotfix comes in, create a worktree of main and dispatch an agent to do that work. The orchestrator stays on its branch and in its environment, and never cds into another checkout.; rule 62 \u2014 The voice profile shapes only the agent's chat speech, never code or\u2026 \u2014 The user, message 17620 (2026-10-07): the profile (butler, homie, coach, colleague) must not leak into the code the agent writes or into user-facing text of any application it works on: names, labels, comments, commit messages, docs and briefs written into a project use plain words (helper, subagent). Speaking in the chat in the profile's voice is fine.", "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": "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": "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 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.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 before you commit \u2014 you've changed 5 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 5 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": "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": "rule 40 \u2014 A feature is named for what it is, never for its machinery \u2014 Messages 599, 600 and 703. A feature is a capability the user would name and would think of switching off. File tracking, a write gate, a phrase bank, a tree diff are services used inside a feature, not features of their own: they live in the feature they serve. Before adding a directory under features/, say what the user would call it; if the answer names a mechanism, it belongs inside something else. Report 16 holds the grouping this implies.", "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": "rule 39 \u2014 Use only registered exclamation response tags \u2014 A tag like [!reply:12] runs a command, and only the tags in the tags.runs setting are registered. An invented tag does nothing and shows as raw text in the chat. Use the registered ones (reply, log, end, todo, fact, rule) and nothing else.; 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.; rule 47 \u2014 The journal sets itself up once, when the server starts, never per\u2026 \u2014 Messages 2220 and 2224. Discovering features and their handlers, seating the feature rows and the rename sweep happen once, at server boot, and again only when a feature is switched on or off, a plugin changes or an environment is added: features.load keeps a set-up generation per journal (SEATED) and redoes the work only when that generation moves. A command, a request or a hook uses what is already there; nothing in their path may rediscover handlers or rescan folders. A cost that repeats per call is a bug to fix, not a budget to raise.", "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": "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": "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.", "meta": {"from": "journal"}}
{"content": "fact 25 \u2014 A designer's install packs the whole tree, half-done server edits\u2026 \u2014 2026-09-25: Eames and Saul run python3 src/journal.py --root .journal upgrade after their viewer builds; it packs every file in src, so a server handler I was halfway through writing went live and raised on every PostToolUse hook. While designers work in parallel, keep server edits whole between tool calls (write and test in the scratchpad first), and reinstall after reverting anything.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 the edit you just made to `m0070_rows_name_their_writer.py`\u2026 \u2014 Code Commandments \u2014 the edit you just made to `m0070_rows_name_their_writer.py` breaks a rule. Fix it now, at its SOURCE, while the code is still in front of you: \u00b7 \u2022 deep-python-nesting at /Users/jessegall/projects/agent-journal/.claude/worktrees/record-two-writers/src/migrations/m0070_rows_name_their_writer.py:15 \u00b7 LOAD the skill `commandments-python-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": "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": "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; rule 64 \u2014 A finished feature is merged into main without waiting for approval \u2014 The user, message 17815 (2026-10-07): 'make sure that no pull requests are lingering on the repository. You may merge them into main... You are allowed to merge everything into main once the feature is completed.' This replaces rule 61's wait for approval: a feature still goes on its own branch, and once it is complete, tested and its whole suite passes, it is merged into main and released, and no pull request is left open.", "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": "the viewer build for 3271 came back - Build the viewer for to-do 3271\u2026", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 before you commit \u2014 you've changed 17 judged files since th\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 17 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 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.; 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.", "meta": {"from": "journal"}}
{"content": "work 2 is still open \u2014 end it or park it before you stop: journal work end 2 --how \"<what landed>\", or journal work park 2 \"<why it waits>\"; 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": "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": "waiting: 1 unread todo 2", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 before you wrap up \u2014 you've changed 12 judged files since t\u2026 \u2014 Code Commandments \u2014 before you wrap up: you've changed 12 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": "the viewer build for 3272 came back - Tidy the stream helper, log 3272 and\u2026; 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": "context 50% full, decide \u2014 a fact is what a later reader would get wrong without, a rule binds every environment, or nothing \"<why>\"; 13 facts standing, read them \u2014 9. Every public method on a controller becomes a journal command; 13. This live session runs the installed copy in .journal/journal.pyz; 18. cProfile inflates the slow-request profiles about tenfold; 20. A slim supervisor holds the agent and a worker reloads on every build; 23. Every upgrade brings system sequences and their triggers in line with the code; 24. An answer followed by tool calls can be missing from Claude's transcript; 25. A designer's install packs the whole tree, half-done server edits included; 26. Claude Code reads agent profiles when a session starts; 27. Running src/journal.py against the live .journal root starts a second server; 28. The designer agent type exists, so design work goes to a subagent; 29. Codex's transcript records the end of every exec session, polled or not; 30. The tunler server refuses TLS for any subdomain without a tunnel; 34. A hooks list in a checkout's .claude/settings.json stops every helper at start; 40 rules in force, read them \u2014 7. journal disable must only ever be run because the user explicitly asked for it,; 9. Research dispatched to a subagent ends in a REPORT for the user, compiled by the; 13. A title names the thing in at most 80 characters and never explains it with a co; 14. A small journal capability is a feature under features, with at most one test; 17. Do not restart the viewer for frontend-only changes; 18. Provider-specific code belongs in providers, never features; 19. Providers report facts; features decide behavior; 22. File distinct user work requests immediately; 27. Name a declaration with the word a reader already knows; 30. The viewer has one API client, and every piece of it does one job; 31. Every finding a reviewing agent reports becomes its own to-do; 35. Write clean code - one funnel per kind of operation, never the same method twice; 36. Clean, DRY, idiomatic before it is committed, never after it is complained about; 37. Close every to-do explicitly with todo done or a Journal commit trailer; 38. Never change the git branch until the user says so, by name; 39. Use only registered exclamation response tags; 40. A feature is named for what it is, never for its machinery; 41. Keep moving, run the whole suite before every commit, never wait; 42. Every user-facing text passes the formatters before it leaves the server; 43. A request or hook over its budget is fixed before the next release; 45. No prose words as names in code - said, says, heard, spoke, told, shown, became; 46. Only commit and push once the whole journal is proven to boot; 47. The journal sets itself up once, when the server starts, never per command; 48. The viewer is built from its component library, and pages only compose it; 49. A dialog whose content grows keeps one fixed height, and its content scrolls; 50. Everything the user does is doable in the viewer; 51. Every finished feature is committed, pushed and released with a new version tag; 52. A chat mark for something the user did sits on the user's side; 54. Settings and feature switches are read at boot and on change, never per call; 55. Always dispatch Codex helpers on gpt-6-sol; 56. Helpers are for work that writes; subagents read, research and design; 57. Never merge the overnight refactor into main before its pull request is approved; 58. A design runs three critique rounds, then is built on a branch; 59. Every viewer heading and label says plainly what it is about; 60. A hotfix is done by a dispatched agent in a worktree of main; 61. Features wait as pull requests until approved; only hotfixes merge at once; 62. The voice profile shapes only the agent's chat speech, never code or text; 63. A small design is drawn once and the user approves it, with no critique rounds; 64. A finished feature is merged into main without waiting for approval; 65. Run only new and affected tests while working; the whole suite only before main", "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 61 \u2014 Features wait as pull requests until approved; only hotfixes merge\u2026 \u2014 Message 17118 (2026-10-06), after the overnight refactor merged as 2.252.0: start new work in a new branch, do not merge, write the pull request. Every pull request or new feature is parked until the user approves it. Hotfixes can be merged into main immediately (by a dispatched agent in a worktree of main, rule 60).; fact 34 \u2014 A hooks list in a checkout's .claude/settings.json stops every\u2026 \u2014 Seen 2026-10-08: since commit 707a82915 the committed .claude/settings.json held {\"hooks\": []}; current Claude Code answers a hooks value that is not an object with a SettingsWarning dialog, which a headless helper cannot answer, so helpers 183 and 184 exited before doing anything (their launch logs in .journal/runtime/launches/ show it). This repository's journal hooks live in settings.local.json; the committed settings.json stays {}.; 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": "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 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": "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 before you wrap up \u2014 you've changed 11 judged files since t\u2026 \u2014 Code Commandments \u2014 before you wrap up: you've changed 11 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": "the viewer build for 3276 came back - Log the 3276 journal side and build the\u2026", "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": "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": "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": "law L5 \u2014 Every subagent dispatch names the agent - a human name, a little\u2026 \u2014 A name is how the user and the chat tell subagents apart and how they are messaged later; an id or a task line is not a name. Start the dispatch's description with the name, a colon, then the task, such as \"Dr. Einstein: profile the slow hooks\" or \"Coco Rams: draw the plan card\". A designer can borrow from famous designers, a researcher from famous scientists, mixed up for fun.", "meta": {"from": "journal"}}
{"content": "rule 47 \u2014 The journal sets itself up once, when the server starts, never per\u2026 \u2014 Messages 2220 and 2224. Discovering features and their handlers, seating the feature rows and the rename sweep happen once, at server boot, and again only when a feature is switched on or off, a plugin changes or an environment is added: features.load keeps a set-up generation per journal (SEATED) and redoes the work only when that generation moves. A command, a request or a hook uses what is already there; nothing in their path may rediscover handlers or rescan folders. A cost that repeats per call is a bug to fix, not a budget to raise.", "meta": {"from": "journal"}}
{"content": "rule 40 \u2014 A feature is named for what it is, never for its machinery \u2014 Messages 599, 600 and 703. A feature is a capability the user would name and would think of switching off. File tracking, a write gate, a phrase bank, a tree diff are services used inside a feature, not features of their own: they live in the feature they serve. Before adding a directory under features/, say what the user would call it; if the answer names a mechanism, it belongs inside something else. Report 16 holds the grouping this implies.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 before you commit \u2014 you've changed 29 judged files since th\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 29 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": "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": "rule 65 \u2014 Run only new and affected tests while working; the whole suite only\u2026 \u2014 The user, messages 17914 to 17917 (2026-10-07): 'stop running the whole test suite and wasting my time... please only run the new or affected tests, and then, whenever you are merging to main or publishing to main, you can run the full test suite.' Replaces rule 41's whole suite before every commit: on a feature branch, run the tests beside what changed (journal check touched, or the feature's test.py and the browser scenarios it touches); the whole suite runs once, before a merge into main and its release.", "meta": {"from": "journal"}}
{"content": "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 64 \u2014 A finished feature is merged into main without waiting for approval \u2014 The user, message 17815 (2026-10-07): 'make sure that no pull requests are lingering on the repository. You may merge them into main... You are allowed to merge everything into main once the feature is completed.' This replaces rule 61's wait for approval: a feature still goes on its own branch, and once it is complete, tested and its whole suite passes, it is merged into main and released, and no pull request is left open.", "meta": {"from": "journal"}}
{"content": "rule 43 \u2014 A request or hook over its budget is fixed before the next release \u2014 Comment 1151 on this rule. When the faults feature reports a request, a hook or a command slower than its budget, file it as a to-do at once. It does not jump ahead of the work in hand, but no version is published while one is still open: profile it, fix it, and verify the new time before the release goes out. The budget is 50ms, because everything runs locally against files.; rule 59 \u2014 Every viewer heading and label says plainly what it is about \u2014 The user, messages 16499, 16839, 16844, 16989, 16992 and 16993 (2026-10-06), after 'Where the words count', 'Watch for the words in', 'This project', 'This browser' and 'Stop the journal' as tab names: viewer text reads like Linear, GitHub or Vercel. A place (page, tab, group, sidebar item) is a short noun: Settings, Project, Browser, Services, Updates, Plugins; never 'This project' or a phrase. A button is a verb for what happens: Stop, Install, Copy link, Pause the plan. A heading names what the reader looks at, and its options finish its sentence: 'Trigger when' / 'A word is written'. Plain literal words: no metaphor or whimsy ('kettle on, waiting'), no app speaking as I, none of the journal's internal words (row, hook, nudge, engine, slate). One word for one thing everywhere, sentence case, as short as it can be while clear. Applies to designers' prototypes, helpers' builds, the viewer's JavaScript lists, feature details, and shipped sequence and trigger titles alike.", "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": "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 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 66 \u2014 The journal never slows the agent down \u2014 The user, message 18990, after hooks timed out and waited on locks under load: the journal must never, ever decrease the performance of an agent. A hook answers at once with what decides the tool call; everything else runs after, in the background, and reaches the agent as a message. No hook waits on a lock it does not need.", "meta": {"from": "journal"}}
{"content": "law L1 \u2014 Every subagent dispatch names its model and chooses the least\u2026 \u2014 Use a fast, economical model for mechanical work with a known answer, a capable general model for careful implementation, and the strongest model only when the task turns on difficult judgement. Inheriting the orchestrator's model is not a model choice. If the dispatch API cannot accept a model, that operation is exempt.", "meta": {"from": "journal"}}
{"content": "work 4 in hand \u2014 A plan's page opens fast, with skeletons while its agents\u2026 \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 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.; 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.; 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": "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": "Code Commandments \u2014 before you wrap up \u2014 you've changed 7 judged files since th\u2026 \u2014 Code Commandments \u2014 before you wrap up: you've changed 7 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": "waiting: 1 unread todo 3", "meta": {"from": "journal"}}
{"content": "the viewer build for 3434 came back - Log the 3434 findings and build the\u2026", "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.; 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.", "meta": {"from": "journal"}}
{"content": "work deferred in words, not parked \u2014 \"once the fetch is\" is the title of a to-do: journal todo create \"<title>\" --brief, then say so", "meta": {"from": "journal"}}
{"content": "work deferred in words, not parked \u2014 \"Once the fetch is\" is the title of a to-do: journal todo create \"<title>\" --brief, then say so", "meta": {"from": "journal"}}
{"content": "todo 4 next", "meta": {"from": "journal"}}
{"content": "fact 34 \u2014 A hooks list in a checkout's .claude/settings.json stops every\u2026 \u2014 Seen 2026-10-08: since commit 707a82915 the committed .claude/settings.json held {\"hooks\": []}; current Claude Code answers a hooks value that is not an object with a SettingsWarning dialog, which a headless helper cannot answer, so helpers 183 and 184 exited before doing anything (their launch logs in .journal/runtime/launches/ show it). This repository's journal hooks live in settings.local.json; the committed settings.json stays {}.; 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 61 \u2014 Features wait as pull requests until approved; only hotfixes merge\u2026 \u2014 Message 17118 (2026-10-06), after the overnight refactor merged as 2.252.0: start new work in a new branch, do not merge, write the pull request. Every pull request or new feature is parked until the user approves it. Hotfixes can be merged into main immediately (by a dispatched agent in a worktree of main, rule 60).", "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": "nothing is ready - every open row waits \u2014 to-do 4, The helpers poll fetches only the helpers a page needs. For each that waits on a person or a decision, put it to them now with journal todo ask <n> \"<who decides what>\" --set options='[...]' --set pick=<n>; unblock any that can go on and work it. Stop only when each one waits on a question.", "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": "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": "Code Commandments \u2014 before you commit \u2014 you've changed 10 judged files since th\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 10 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": "todo 4 next", "meta": {"from": "journal"}}
{"content": "nothing is ready - every open row waits \u2014 to-do 4, The helpers poll fetches only the helpers a page needs. For each that waits on a person or a decision, put it to them now with journal todo ask <n> \"<who decides what>\" --set options='[...]' --set pick=<n>; unblock any that can go on and work it. Stop only when each one waits on a question.", "meta": {"from": "journal"}}
{"content": "that Bash call returned 28,504 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": "the four failing members tests under the suite lock came back - Run the four\u2026", "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", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 before you wrap up \u2014 you've changed 1 judged file since the\u2026 \u2014 Code Commandments \u2014 before you wrap up: you've changed 1 judged file 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": "the browser rerun of the members scenario came back - Rerun the browser test\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 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": "the browser test rerun with its full error came back - Rerun the browser test\u2026", "meta": {"from": "journal"}}
{"content": "the fixed members tests and the allow-list sweep came back - Scope the locator\u2026", "meta": {"from": "journal"}}
{"content": "your command ran 33s 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": "waiting: 1 unread todo 5", "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": "the allow-list sweep naming what a reader opened came back - Make the reader\u2026", "meta": {"from": "journal"}}
{"content": "waiting: 1 unread todo 5", "meta": {"from": "journal"}}
{"content": "waiting: 1 unread todo 5", "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": "the allow-list sweep after the reader assertion fix came back - Assert a\u2026", "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": "rule 67 \u2014 Never answer a journal line in the chat; act on it silently \u2014 The user, messages 19360 and 19365: the agent kept writing chat lines in reply to the journal's own reminders (old helper reports, notices), filling the user's chat with noise. A journal line is an instruction to the agent, not a message: act on it and write nothing, unless the user needs to know something (a failure, a finished piece of work, a decision that waits on them). The journal itself should enforce it, not a local reminder.", "meta": {"from": "journal"}}
{"content": "fact 25 \u2014 A designer's install packs the whole tree, half-done server edits\u2026 \u2014 2026-09-25: Eames and Saul run python3 src/journal.py --root .journal upgrade after their viewer builds; it packs every file in src, so a server handler I was halfway through writing went live and raised on every PostToolUse hook. While designers work in parallel, keep server edits whole between tool calls (write and test in the scratchpad first), and reinstall after reverting anything.; 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.; law L2 \u2014 Every subagent is bound to a concrete job; never dispatch a generic\u2026 \u2014 Use the most specific available agent type whose declared purpose matches the assignment. On providers without agent types, give the dispatch a concrete task name and bounded prompt. If no suitable specialization exists, keep the work in the main agent instead of manufacturing an unscoped helper.; law L4 \u2014 Related work goes back to the helper or subagent that already worked\u2026 \u2014 A helper or subagent that drew a design, wrote the code or ran the research keeps what it learned. When new work changes its work, is related to it or touches the same code, send it there with a message (SendMessage, journal helper say) rather than dispatching a new one that has to rediscover everything; start fresh only when the earlier one is gone or the new work is unrelated.; law L5 \u2014 Every subagent dispatch names the agent - a human name, a little\u2026 \u2014 A name is how the user and the chat tell subagents apart and how they are messaged later; an id or a task line is not a name. Start the dispatch's description with the name, a colon, then the task, such as \"Dr. Einstein: profile the slow hooks\" or \"Coco Rams: draw the plan card\". A designer can borrow from famous designers, a researcher from famous scientists, mixed up for fun.; 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.; rule 58 \u2014 A design runs three critique rounds, then is built on a branch \u2014 Messages 17276 and 17281 (2026-10-06): the norm is a three-round cycle. Round by round, the designer designs (or revises), separate critic agents review the design through their lenses (the critic agent type, .claude/agents/critic.md: read-only, with a browser; one per lens, such as first-time, native, words and parity), and the designer adjusts it to their findings; three rounds in all. The three rounds stand in for the user's approval of the design: the user does not approve it. After the third round the design is built on a branch of its own, which ends in a pull request that waits for the user's approval (rule 61). Replaces message 15725's prototype approval.; rule 63 \u2014 A small design is drawn once and the user approves it, with no\u2026 \u2014 The user, messages 17628 and 17629 (2026-10-07), about the tooltip and waiting-status designs: 'This design round doesn't really need multiple rounds... I just want the designer agent to design it, and I will approve it.' Rule 58's three critique rounds are for large designs such as the phone app; a small one (a tooltip, a status word, one control) is drawn once by the designer, the link goes to the user, and it is built once the user approves it.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 before you commit \u2014 you've changed 2 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 2 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": "auto mode is on and work 7 stands still while todo 5 is ready \u2014 if work 7 waits on the user, decide it yourself when you can; otherwise put the question on its row with journal todo ask, end or park the work, and start todo 5. Stop only when nothing ready is left.; work 7 is still open, with nothing logged \u2014 journal work log 7 \"<what was decided or done, and why>\" \u2014 then journal work end 7 --how \"<what landed>\", or journal work park 7 \"<why it waits>\"", "meta": {"from": "journal"}}
{"content": "todo 4, The helpers poll fetches only the helpers a page needs, is still\u2026 \u2014 it is blocked because: The user's answer to question 6: the helpers poll waits, filed as its own to-do, until it is handed over. If it is not any more, journal todo unblock 4. If it waits on a person or a decision, make it a question to them: journal todo ask 4 \"<who decides what>\" --set options='[...]' --set pick=<n>, and the row waits on their answer. Otherwise tell the user in the chat what it waits on, in their terms, and propose how to clear it.", "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": "nothing is ready - every open row waits \u2014 to-do 4, The helpers poll fetches only the helpers a page needs. For each that waits on a person or a decision, put it to them now with journal todo ask <n> \"<who decides what>\" --set options='[...]' --set pick=<n>; unblock any that can go on and work it. Stop only when each one waits on a question.", "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": "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": "rule 47 \u2014 The journal sets itself up once, when the server starts, never per\u2026 \u2014 Messages 2220 and 2224. Discovering features and their handlers, seating the feature rows and the rename sweep happen once, at server boot, and again only when a feature is switched on or off, a plugin changes or an environment is added: features.load keeps a set-up generation per journal (SEATED) and redoes the work only when that generation moves. A command, a request or a hook uses what is already there; nothing in their path may rediscover handlers or rescan folders. A cost that repeats per call is a bug to fix, not a budget to raise.", "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": "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; Code Commandments \u2014 before you commit \u2014 you've changed 2 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 2 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": "auto mode is on and work 8 stands still while todo 6 is ready \u2014 if work 8 waits on the user, decide it yourself when you can; otherwise put the question on its row with journal todo ask, end or park the work, and start todo 6. Stop only when nothing ready is left.; work 8 is still open \u2014 end it or park it before you stop: journal work end 8 --how \"<what landed>\", or journal work park 8 \"<why it waits>\"", "meta": {"from": "journal"}}
{"content": "rule 65 \u2014 Run only new and affected tests while working; the whole suite only\u2026 \u2014 The user, messages 17914 to 17917 (2026-10-07): 'stop running the whole test suite and wasting my time... please only run the new or affected tests, and then, whenever you are merging to main or publishing to main, you can run the full test suite.' Replaces rule 41's whole suite before every commit: on a feature branch, run the tests beside what changed (journal check touched, or the feature's test.py and the browser scenarios it touches); the whole suite runs once, before a merge into main and its release.", "meta": {"from": "journal"}}
{"content": "rule 43 \u2014 A request or hook over its budget is fixed before the next release \u2014 Comment 1151 on this rule. When the faults feature reports a request, a hook or a command slower than its budget, file it as a to-do at once. It does not jump ahead of the work in hand, but no version is published while one is still open: profile it, fix it, and verify the new time before the release goes out. The budget is 50ms, because everything runs locally against files.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 before you commit \u2014 you've changed 1 judged file since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 1 judged file 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": "the end tag does this in one step \u2014 [!end:N] makes the turn itself what landed; it runs only when it opens the last text of your turn", "meta": {"from": "journal"}}
{"content": "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 64 \u2014 A finished feature is merged into main without waiting for approval \u2014 The user, message 17815 (2026-10-07): 'make sure that no pull requests are lingering on the repository. You may merge them into main... You are allowed to merge everything into main once the feature is completed.' This replaces rule 61's wait for approval: a feature still goes on its own branch, and once it is complete, tested and its whole suite passes, it is merged into main and released, and no pull request is left open.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 `playwright.py`, changed since the last check, breaks a rul\u2026 \u2014 Code Commandments \u2014 `playwright.py`, changed since the last check, breaks a rule. Fix it now, at its SOURCE, while the code is still in front of you: \u00b7 \u2022 python-raw-decoded-return at /Users/jessegall/projects/agent-journal/.claude/worktrees/record-two-writers/src/providers/playwright.py:39 \u00b7 LOAD the skill `commandments-python-value-objects` 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 before you commit \u2014 you've changed 5 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 5 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": "auto mode is on and work 10 stands still while todo 7 is ready \u2014 if work 10 waits on the user, decide it yourself when you can; otherwise put the question on its row with journal todo ask, end or park the work, and start todo 7. Stop only when nothing ready is left.; work 10 is still open \u2014 end it or park it before you stop: journal work end 10 --how \"<what landed>\", or journal work park 10 \"<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": "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": "13 facts standing, read them \u2014 9. Every public method on a controller becomes a journal command; 13. This live session runs the installed copy in .journal/journal.pyz; 18. cProfile inflates the slow-request profiles about tenfold; 20. A slim supervisor holds the agent and a worker reloads on every build; 23. Every upgrade brings system sequences and their triggers in line with the code; 24. An answer followed by tool calls can be missing from Claude's transcript; 25. A designer's install packs the whole tree, half-done server edits included; 26. Claude Code reads agent profiles when a session starts; 27. Running src/journal.py against the live .journal root starts a second server; 28. The designer agent type exists, so design work goes to a subagent; 29. Codex's transcript records the end of every exec session, polled or not; 30. The tunler server refuses TLS for any subdomain without a tunnel; 34. A hooks list in a checkout's .claude/settings.json stops every helper at start", "meta": {"from": "journal"}}
{"content": "42 rules in force, read them \u2014 7. journal disable must only ever be run because the user explicitly asked for it,; 9. Research dispatched to a subagent ends in a REPORT for the user, compiled by the; 13. A title names the thing in at most 80 characters and never explains it with a co; 14. A small journal capability is a feature under features, with at most one test; 17. Do not restart the viewer for frontend-only changes; 18. Provider-specific code belongs in providers, never features; 19. Providers report facts; features decide behavior; 22. File distinct user work requests immediately; 27. Name a declaration with the word a reader already knows; 30. The viewer has one API client, and every piece of it does one job; 31. Every finding a reviewing agent reports becomes its own to-do; 35. Write clean code - one funnel per kind of operation, never the same method twice; 36. Clean, DRY, idiomatic before it is committed, never after it is complained about; 37. Close every to-do explicitly with todo done or a Journal commit trailer; 38. Never change the git branch until the user says so, by name; 39. Use only registered exclamation response tags; 40. A feature is named for what it is, never for its machinery; 41. Keep moving, run the whole suite before every commit, never wait; 42. Every user-facing text passes the formatters before it leaves the server; 43. A request or hook over its budget is fixed before the next release; 45. No prose words as names in code - said, says, heard, spoke, told, shown, became; 46. Only commit and push once the whole journal is proven to boot; 47. The journal sets itself up once, when the server starts, never per command; 48. The viewer is built from its component library, and pages only compose it; 49. A dialog whose content grows keeps one fixed height, and its content scrolls; 50. Everything the user does is doable in the viewer; 51. Every finished feature is committed, pushed and released with a new version tag; 52. A chat mark for something the user did sits on the user's side; 54. Settings and feature switches are read at boot and on change, never per call; 55. Always dispatch Codex helpers on gpt-6-sol; 56. Helpers are for work that writes; subagents read, research and design; 57. Never merge the overnight refactor into main before its pull request is approved; 58. A design runs three critique rounds, then is built on a branch; 59. Every viewer heading and label says plainly what it is about; 60. A hotfix is done by a dispatched agent in a worktree of main; 61. Features wait as pull requests until approved; only hotfixes merge at once; 62. The voice profile shapes only the agent's chat speech, never code or text; 63. A small design is drawn once and the user approves it, with no critique rounds; 64. A finished feature is merged into main without waiting for approval; 65. Run only new and affected tests while working; the whole suite only before main; 66. The journal never slows the agent down; 67. Never answer a journal line in the chat; act on it silently", "meta": {"from": "journal"}}
{"content": "the cherry-picks onto release-266 came back - Drop build files from the merge\u2026", "meta": {"from": "journal"}}
{"content": "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.", "meta": {"from": "journal"}}
{"content": "the remaining cherry-picks onto release-266 came back - Continue the picks\u2026; 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": "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": "fact 34 \u2014 A hooks list in a checkout's .claude/settings.json stops every\u2026 \u2014 Seen 2026-10-08: since commit 707a82915 the committed .claude/settings.json held {\"hooks\": []}; current Claude Code answers a hooks value that is not an object with a SettingsWarning dialog, which a headless helper cannot answer, so helpers 183 and 184 exited before doing anything (their launch logs in .journal/runtime/launches/ show it). This repository's journal hooks live in settings.local.json; the committed settings.json stays {}.; 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.", "meta": {"from": "journal"}}
{"content": "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": "the cherry-picks from 19 onto release-266 came back - Finish pick 18 and\u2026", "meta": {"from": "journal"}}
{"content": "rule 61 \u2014 Features wait as pull requests until approved; only hotfixes merge\u2026 \u2014 Message 17118 (2026-10-06), after the overnight refactor merged as 2.252.0: start new work in a new branch, do not merge, write the pull request. Every pull request or new feature is parked until the user approves it. Hotfixes can be merged into main immediately (by a dispatched agent in a worktree of main, rule 60).", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 before you commit \u2014 you've changed 5 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 5 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": "the cherry-picks from 20 onto release-266 came back - Check the test's syntax\u2026", "meta": {"from": "journal"}}
{"content": "the cherry-picks from 22 onto release-266 came back - Continue the picks from\u2026", "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.; 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.; fact 26 \u2014 Claude Code reads agent profiles when a session starts \u2014 Seen 2026-09-26: after the board-filler's profile in .claude/agents gained its steps and the Grep rule, dispatches from the running session still used the old profile (a 3.5-minute first question, shell grep refused); after the session restarted, the same request took 21 seconds with 4 calls. A change to an agent type reaches only sessions started after it is written.; rule 62 \u2014 The voice profile shapes only the agent's chat speech, never code or\u2026 \u2014 The user, message 17620 (2026-10-07): the profile (butler, homie, coach, colleague) must not leak into the code the agent writes or into user-facing text of any application it works on: names, labels, comments, commit messages, docs and briefs written into a project use plain words (helper, subagent). Speaking in the chat in the profile's voice is fine.", "meta": {"from": "journal"}}
{"content": "the cherry-picks from 32 onto release-266 came back - Continue the picks from\u2026", "meta": {"from": "journal"}}
{"content": "your chat talked about the journal's workings - \"Reading them\" \u2014 the user sees replies, reactions, pills and reads themselves; say what the work is instead", "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": "the cherry-picks from 35 onto release-266 came back - Continue the picks from\u2026", "meta": {"from": "journal"}}
{"content": "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.; 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 cherry-picks from 36 onto release-266 came back - Finish pick 35 and\u2026", "meta": {"from": "journal"}}
{"content": "your chat talked about the journal's workings - \"Reading them\" \u2014 the user sees replies, reactions, pills and reads themselves; say what the work is instead", "meta": {"from": "journal"}}
{"content": "the cherry-picks from 37 onto release-266 came back - Finish pick 36 and\u2026", "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": "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": "the cherry-picks from 38 onto release-266 came back - Finish pick 37 and\u2026", "meta": {"from": "journal"}}
{"content": "rule 47 \u2014 The journal sets itself up once, when the server starts, never per\u2026 \u2014 Messages 2220 and 2224. Discovering features and their handlers, seating the feature rows and the rename sweep happen once, at server boot, and again only when a feature is switched on or off, a plugin changes or an environment is added: features.load keeps a set-up generation per journal (SEATED) and redoes the work only when that generation moves. A command, a request or a hook uses what is already there; nothing in their path may rediscover handlers or rescan folders. A cost that repeats per call is a bug to fix, not a budget to raise.", "meta": {"from": "journal"}}
{"content": "the cherry-picks from 39 onto release-266 came back - Finish pick 38 and\u2026", "meta": {"from": "journal"}}
{"content": "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 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).; 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": "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": "Code Commandments \u2014 before you commit \u2014 you've changed 10 judged files since th\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 10 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": "Code Commandments \u2014 before you commit \u2014 you've changed 2 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 2 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 43 \u2014 A request or hook over its budget is fixed before the next release \u2014 Comment 1151 on this rule. When the faults feature reports a request, a hook or a command slower than its budget, file it as a to-do at once. It does not jump ahead of the work in hand, but no version is published while one is still open: profile it, fix it, and verify the new time before the release goes out. The budget is 50ms, because everything runs locally against files.", "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 11 in hand \u2014 Assemble the 2.266.0 release branch \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": "release-266 rebasing onto release-265's new tip came back - Rebase release-266\u2026; rule 64 \u2014 A finished feature is merged into main without waiting for approval \u2014 The user, message 17815 (2026-10-07): 'make sure that no pull requests are lingering on the repository. You may merge them into main... You are allowed to merge everything into main once the feature is completed.' This replaces rule 61's wait for approval: a feature still goes on its own branch, and once it is complete, tested and its whole suite passes, it is merged into main and released, and no pull request is left open.", "meta": {"from": "journal"}}
{"content": "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.", "meta": {"from": "journal"}}
{"content": "the import check and the viewer build of release-266 came back - Look for\u2026", "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.; 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.; 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.; rule 65 \u2014 Run only new and affected tests while working; the whole suite only\u2026 \u2014 The user, messages 17914 to 17917 (2026-10-07): 'stop running the whole test suite and wasting my time... please only run the new or affected tests, and then, whenever you are merging to main or publishing to main, you can run the full test suite.' Replaces rule 41's whole suite before every commit: on a feature branch, run the tests beside what changed (journal check touched, or the feature's test.py and the browser scenarios it touches); the whole suite runs once, before a merge into main and its release.", "meta": {"from": "journal"}}
{"content": "rule 59 \u2014 Every viewer heading and label says plainly what it is about \u2014 The user, messages 16499, 16839, 16844, 16989, 16992 and 16993 (2026-10-06), after 'Where the words count', 'Watch for the words in', 'This project', 'This browser' and 'Stop the journal' as tab names: viewer text reads like Linear, GitHub or Vercel. A place (page, tab, group, sidebar item) is a short noun: Settings, Project, Browser, Services, Updates, Plugins; never 'This project' or a phrase. A button is a verb for what happens: Stop, Install, Copy link, Pause the plan. A heading names what the reader looks at, and its options finish its sentence: 'Trigger when' / 'A word is written'. Plain literal words: no metaphor or whimsy ('kettle on, waiting'), no app speaking as I, none of the journal's internal words (row, hook, nudge, engine, slate). One word for one thing everywhere, sentence case, as short as it can be while clear. Applies to designers' prototypes, helpers' builds, the viewer's JavaScript lists, feature details, and shipped sequence and trigger titles alike.", "meta": {"from": "journal"}}
{"content": "rule 39 \u2014 Use only registered exclamation response tags \u2014 A tag like [!reply:12] runs a command, and only the tags in the tags.runs setting are registered. An invented tag does nothing and shows as raw text in the chat. Use the registered ones (reply, log, end, todo, fact, rule) and nothing else.", "meta": {"from": "journal"}}
{"content": "your command ran 33s 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": "rule 66 \u2014 The journal never slows the agent down \u2014 The user, message 18990, after hooks timed out and waited on locks under load: the journal must never, ever decrease the performance of an agent. A hook answers at once with what decides the tool call; everything else runs after, in the background, and reaches the agent as a message. No hook waits on a lock it does not need.", "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 `engine.py`, changed since the last check, breaks a rule. F\u2026 \u2014 Code Commandments \u2014 `engine.py`, changed since the last check, 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/record-two-writers/src/runner/engine.py:173 \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": "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": "fact 34 \u2014 A hooks list in a checkout's .claude/settings.json stops every\u2026 \u2014 Seen 2026-10-08: since commit 707a82915 the committed .claude/settings.json held {\"hooks\": []}; current Claude Code answers a hooks value that is not an object with a SettingsWarning dialog, which a headless helper cannot answer, so helpers 183 and 184 exited before doing anything (their launch logs in .journal/runtime/launches/ show it). This repository's journal hooks live in settings.local.json; the committed settings.json stays {}.; 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 67 \u2014 Never answer a journal line in the chat; act on it silently \u2014 The user, messages 19360 and 19365: the agent kept writing chat lines in reply to the journal's own reminders (old helper reports, notices), filling the user's chat with noise. A journal line is an instruction to the agent, not a message: act on it and write nothing, unless the user needs to know something (a failure, a finished piece of work, a decision that waits on them). The journal itself should enforce it, not a local reminder.", "meta": {"from": "journal"}}
{"content": "rule 40 \u2014 A feature is named for what it is, never for its machinery \u2014 Messages 599, 600 and 703. A feature is a capability the user would name and would think of switching off. File tracking, a write gate, a phrase bank, a tree diff are services used inside a feature, not features of their own: they live in the feature they serve. Before adding a directory under features/, say what the user would call it; if the answer names a mechanism, it belongs inside something else. Report 16 holds the grouping this implies.", "meta": {"from": "journal"}}
{"content": "rule 61 \u2014 Features wait as pull requests until approved; only hotfixes merge\u2026 \u2014 Message 17118 (2026-10-06), after the overnight refactor merged as 2.252.0: start new work in a new branch, do not merge, write the pull request. Every pull request or new feature is parked until the user approves it. Hotfixes can be merged into main immediately (by a dispatched agent in a worktree of main, rule 60).", "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": "your command ran 34s 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": "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 commit \u2014 you've changed 2 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 2 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 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.", "meta": {"from": "journal"}}
{"content": "the helpers tests under the lock came back - Drop the unused import and run\u2026", "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.; fact 26 \u2014 Claude Code reads agent profiles when a session starts \u2014 Seen 2026-09-26: after the board-filler's profile in .claude/agents gained its steps and the Grep rule, dispatches from the running session still used the old profile (a 3.5-minute first question, shell grep refused); after the session restarted, the same request took 21 seconds with 4 calls. A change to an agent type reaches only sessions started after it is written.; rule 62 \u2014 The voice profile shapes only the agent's chat speech, never code or\u2026 \u2014 The user, message 17620 (2026-10-07): the profile (butler, homie, coach, colleague) must not leak into the code the agent writes or into user-facing text of any application it works on: names, labels, comments, commit messages, docs and briefs written into a project use plain words (helper, subagent). Speaking in the chat in the profile's voice is fine.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 before you commit \u2014 you've changed 4 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 4 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": "the end tag does this in one step \u2014 [!end:N] makes the turn itself what landed; it runs only when it opens the last text of your turn", "meta": {"from": "journal"}}
{"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": "todo 11 next", "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": "rule 60 \u2014 A hotfix is done by a dispatched agent in a worktree of main \u2014 Message 16836 (2026-10-06): the orchestrator cut a worktree under .claude/worktrees for a Codex hotfix, its session moved to a new environment and the user's messages stopped reaching it. The user: when working on a branch and a hotfix comes in, create a worktree of main and dispatch an agent to do that work. The orchestrator stays on its branch and in its environment, and never cds into another checkout.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 before you commit \u2014 you've changed 1 judged file since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 1 judged file 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": "Code Commandments \u2014 before you commit \u2014 you've changed 4 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 4 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": "rule 47 \u2014 The journal sets itself up once, when the server starts, never per\u2026 \u2014 Messages 2220 and 2224. Discovering features and their handlers, seating the feature rows and the rename sweep happen once, at server boot, and again only when a feature is switched on or off, a plugin changes or an environment is added: features.load keeps a set-up generation per journal (SEATED) and redoes the work only when that generation moves. A command, a request or a hook uses what is already there; nothing in their path may rediscover handlers or rescan folders. A cost that repeats per call is a bug to fix, not a budget to raise.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 before you commit \u2014 you've changed 2 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 2 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": "Code Commandments \u2014 before you commit \u2014 you've changed 3 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: 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": "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 before you commit \u2014 you've changed 3 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: 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.; 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": "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": "auto mode is on and work 18 stands still while todo 16 is ready \u2014 if work 18 waits on the user, decide it yourself when you can; otherwise put the question on its row with journal todo ask, end or park the work, and start todo 16. Stop only when nothing ready is left.; work 18 is still open, with nothing logged \u2014 journal work log 18 \"<what was decided or done, and why>\" \u2014 then journal work end 18 --how \"<what landed>\", or journal work park 18 \"<why it waits>\"", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 before you commit \u2014 you've changed 2 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 2 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 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 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": "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": "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": "that Bash call returned 35,595 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": "Code Commandments \u2014 before you commit \u2014 you've changed 5 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 5 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 34 \u2014 A hooks list in a checkout's .claude/settings.json stops every\u2026 \u2014 Seen 2026-10-08: since commit 707a82915 the committed .claude/settings.json held {\"hooks\": []}; current Claude Code answers a hooks value that is not an object with a SettingsWarning dialog, which a headless helper cannot answer, so helpers 183 and 184 exited before doing anything (their launch logs in .journal/runtime/launches/ show it). This repository's journal hooks live in settings.local.json; the committed settings.json stays {}.; 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": "rule 66 \u2014 The journal never slows the agent down \u2014 The user, message 18990, after hooks timed out and waited on locks under load: the journal must never, ever decrease the performance of an agent. A hook answers at once with what decides the tool call; everything else runs after, in the background, and reaches the agent as a message. No hook waits on a lock it does not need.", "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 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 61 \u2014 Features wait as pull requests until approved; only hotfixes merge\u2026 \u2014 Message 17118 (2026-10-06), after the overnight refactor merged as 2.252.0: start new work in a new branch, do not merge, write the pull request. Every pull request or new feature is parked until the user approves it. Hotfixes can be merged into main immediately (by a dispatched agent in a worktree of main, rule 60).", "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": "Code Commandments \u2014 before you commit \u2014 you've changed 2 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 2 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 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.", "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.; 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 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": "Code Commandments \u2014 before you commit \u2014 you've changed 4 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 4 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": "Code Commandments \u2014 `linking.py`, changed since the last check, breaks a rule.\u2026 \u2014 Code Commandments \u2014 `linking.py`, changed since the last check, breaks a rule. Fix it now, at its SOURCE, while the code is still in front of you: \u00b7 \u2022 python-dict-return-bag at /Users/jessegall/projects/agent-journal/.claude/worktrees/record-two-writers/src/features/connection/linking.py:96 \u00b7 LOAD the skill `commandments-python-value-objects` 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": "Code Commandments \u2014 before you commit \u2014 you've changed 10 judged files since th\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 10 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 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": "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.; law L5 \u2014 Every subagent dispatch names the agent - a human name, a little\u2026 \u2014 A name is how the user and the chat tell subagents apart and how they are messaged later; an id or a task line is not a name. Start the dispatch's description with the name, a colon, then the task, such as \"Dr. Einstein: profile the slow hooks\" or \"Coco Rams: draw the plan card\". A designer can borrow from famous designers, a researcher from famous scientists, mixed up for fun.; 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.", "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.; 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).; 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 64 \u2014 A finished feature is merged into main without waiting for approval \u2014 The user, message 17815 (2026-10-07): 'make sure that no pull requests are lingering on the repository. You may merge them into main... You are allowed to merge everything into main once the feature is completed.' This replaces rule 61's wait for approval: a feature still goes on its own branch, and once it is complete, tested and its whole suite passes, it is merged into main and released, and no pull request is left open.", "meta": {"from": "journal"}}
{"content": "rule 47 \u2014 The journal sets itself up once, when the server starts, never per\u2026 \u2014 Messages 2220 and 2224. Discovering features and their handlers, seating the feature rows and the rename sweep happen once, at server boot, and again only when a feature is switched on or off, a plugin changes or an environment is added: features.load keeps a set-up generation per journal (SEATED) and redoes the work only when that generation moves. A command, a request or a hook uses what is already there; nothing in their path may rediscover handlers or rescan folders. A cost that repeats per call is a bug to fix, not a budget to raise.", "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": "Code Commandments \u2014 before you commit \u2014 you've changed 10 judged files since th\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 10 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 24 in hand \u2014 A handover whose answer is lost leaves exactly one holder \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 5 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 5 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": "rule 65 \u2014 Run only new and affected tests while working; the whole suite only\u2026 \u2014 The user, messages 17914 to 17917 (2026-10-07): 'stop running the whole test suite and wasting my time... please only run the new or affected tests, and then, whenever you are merging to main or publishing to main, you can run the full test suite.' Replaces rule 41's whole suite before every commit: on a feature branch, run the tests beside what changed (journal check touched, or the feature's test.py and the browser scenarios it touches); the whole suite runs once, before a merge into main and its release.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 you're editing `two_containers.py`, a test/stub/fixture tha\u2026 \u2014 Code Commandments \u2014 you're editing `two_containers.py`, a test/stub/fixture that `judge` never scans, so nothing here will flag a symptom-fix. If you're changing it to make a failing check pass, first ask WHERE the failure is born: a failing test usually means the PRODUCTION code is missing behaviour \u2014 a method, a type, a total value on the real type. Fix it THERE (trace to the source; re-open the relevant skill), and change this file only if the TEST itself is wrong. If this is just legitimate test coverage, carry on.; fact 25 \u2014 A designer's install packs the whole tree, half-done server edits\u2026 \u2014 2026-09-25: Eames and Saul run python3 src/journal.py --root .journal upgrade after their viewer builds; it packs every file in src, so a server handler I was halfway through writing went live and raised on every PostToolUse hook. While designers work in parallel, keep server edits whole between tool calls (write and test in the scratchpad first), and reinstall after reverting anything.", "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.; 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 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": "Code Commandments \u2014 before you commit \u2014 you've changed 1 judged file since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 1 judged file 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": "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": "your message 831 names 500 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 831 \"<the text>\"; your message 832 names 404 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 832 \"<the text>\"", "meta": {"from": "journal"}}
{"content": "todo 23 next", "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": "your command ran 34s 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": "Code Commandments \u2014 before you wrap up \u2014 you've changed 6 judged files since th\u2026 \u2014 Code Commandments \u2014 before you wrap up: 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.", "meta": {"from": "journal"}}
{"content": "todo 24 next", "meta": {"from": "journal"}}
{"content": "your chat talked about the journal's workings - \"Nothing else is open\" \u2014 the user sees replies, reactions, pills and reads themselves; say what the work is instead", "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": "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": "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 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 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 before you commit \u2014 you've changed 5 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 5 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": "rule 61 \u2014 Features wait as pull requests until approved; only hotfixes merge\u2026 \u2014 Message 17118 (2026-10-06), after the overnight refactor merged as 2.252.0: start new work in a new branch, do not merge, write the pull request. Every pull request or new feature is parked until the user approves it. Hotfixes can be merged into main immediately (by a dispatched agent in a worktree of main, rule 60).", "meta": {"from": "journal"}}
{"content": "rule 59 \u2014 Every viewer heading and label says plainly what it is about \u2014 The user, messages 16499, 16839, 16844, 16989, 16992 and 16993 (2026-10-06), after 'Where the words count', 'Watch for the words in', 'This project', 'This browser' and 'Stop the journal' as tab names: viewer text reads like Linear, GitHub or Vercel. A place (page, tab, group, sidebar item) is a short noun: Settings, Project, Browser, Services, Updates, Plugins; never 'This project' or a phrase. A button is a verb for what happens: Stop, Install, Copy link, Pause the plan. A heading names what the reader looks at, and its options finish its sentence: 'Trigger when' / 'A word is written'. Plain literal words: no metaphor or whimsy ('kettle on, waiting'), no app speaking as I, none of the journal's internal words (row, hook, nudge, engine, slate). One word for one thing everywhere, sentence case, as short as it can be while clear. Applies to designers' prototypes, helpers' builds, the viewer's JavaScript lists, feature details, and shipped sequence and trigger titles alike.", "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": "Code Commandments \u2014 before you commit \u2014 you've changed 4 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 4 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": "rule 40 \u2014 A feature is named for what it is, never for its machinery \u2014 Messages 599, 600 and 703. A feature is a capability the user would name and would think of switching off. File tracking, a write gate, a phrase bank, a tree diff are services used inside a feature, not features of their own: they live in the feature they serve. Before adding a directory under features/, say what the user would call it; if the answer names a mechanism, it belongs inside something else. Report 16 holds the grouping this implies.", "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": "Code Commandments \u2014 before you commit \u2014 you've changed 2 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 2 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": "Code Commandments \u2014 before you commit \u2014 you've changed 5 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 5 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 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 66 \u2014 The journal never slows the agent down \u2014 The user, message 18990, after hooks timed out and waited on locks under load: the journal must never, ever decrease the performance of an agent. A hook answers at once with what decides the tool call; everything else runs after, in the background, and reaches the agent as a message. No hook waits on a lock it does not need.", "meta": {"from": "journal"}}
{"content": "auto mode is on and work 27 stands still while todo 28 is ready \u2014 if work 27 waits on the user, decide it yourself when you can; otherwise put the question on its row with journal todo ask, end or park the work, and start todo 28. Stop only when nothing ready is left.; work 27 is still open, with nothing logged \u2014 journal work log 27 \"<what was decided or done, and why>\" \u2014 then journal work end 27 --how \"<what landed>\", or journal work park 27 \"<why it waits>\"", "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 47 \u2014 The journal sets itself up once, when the server starts, never per\u2026 \u2014 Messages 2220 and 2224. Discovering features and their handlers, seating the feature rows and the rename sweep happen once, at server boot, and again only when a feature is switched on or off, a plugin changes or an environment is added: features.load keeps a set-up generation per journal (SEATED) and redoes the work only when that generation moves. A command, a request or a hook uses what is already there; nothing in their path may rediscover handlers or rescan folders. A cost that repeats per call is a bug to fix, not a budget to raise.", "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": "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": "fact 25 \u2014 A designer's install packs the whole tree, half-done server edits\u2026 \u2014 2026-09-25: Eames and Saul run python3 src/journal.py --root .journal upgrade after their viewer builds; it packs every file in src, so a server handler I was halfway through writing went live and raised on every PostToolUse hook. While designers work in parallel, keep server edits whole between tool calls (write and test in the scratchpad first), and reinstall after reverting anything.", "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 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 L1 \u2014 Every subagent dispatch names its model and chooses the least\u2026 \u2014 Use a fast, economical model for mechanical work with a known answer, a capable general model for careful implementation, and the strongest model only when the task turns on difficult judgement. Inheriting the orchestrator's model is not a model choice. If the dispatch API cannot accept a model, that operation is exempt.; law L2 \u2014 Every subagent is bound to a concrete job; never dispatch a generic\u2026 \u2014 Use the most specific available agent type whose declared purpose matches the assignment. On providers without agent types, give the dispatch a concrete task name and bounded prompt. If no suitable specialization exists, keep the work in the main agent instead of manufacturing an unscoped helper.; law L4 \u2014 Related work goes back to the helper or subagent that already worked\u2026 \u2014 A helper or subagent that drew a design, wrote the code or ran the research keeps what it learned. When new work changes its work, is related to it or touches the same code, send it there with a message (SendMessage, journal helper say) rather than dispatching a new one that has to rediscover everything; start fresh only when the earlier one is gone or the new work is unrelated.; law L5 \u2014 Every subagent dispatch names the agent - a human name, a little\u2026 \u2014 A name is how the user and the chat tell subagents apart and how they are messaged later; an id or a task line is not a name. Start the dispatch's description with the name, a colon, then the task, such as \"Dr. Einstein: profile the slow hooks\" or \"Coco Rams: draw the plan card\". A designer can borrow from famous designers, a researcher from famous scientists, mixed up for fun.; 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": "Code Commandments \u2014 before you commit \u2014 you've changed 5 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 5 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 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 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 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": "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": "fact 34 \u2014 A hooks list in a checkout's .claude/settings.json stops every\u2026 \u2014 Seen 2026-10-08: since commit 707a82915 the committed .claude/settings.json held {\"hooks\": []}; current Claude Code answers a hooks value that is not an object with a SettingsWarning dialog, which a headless helper cannot answer, so helpers 183 and 184 exited before doing anything (their launch logs in .journal/runtime/launches/ show it). This repository's journal hooks live in settings.local.json; the committed settings.json stays {}.; 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": "Code Commandments \u2014 the files changed since the last check (`handlers.py`, `tes\u2026 \u2014 Code Commandments \u2014 the files changed since the last check (`handlers.py`, `test.py`, `test.py`, `move.py`, `install.py`) breaks a rule. Fix it now, at its SOURCE, while the code is still in front of you: \u00b7 \u2022 python-loop-wrapped-in-if at /Users/jessegall/projects/agent-journal/.claude/worktrees/record-two-writers/src/features/agent_sessions/handlers.py:90 \u00b7 LOAD the skill `commandments-python-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": "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": "Code Commandments \u2014 before you commit \u2014 you've changed 8 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 8 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": "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": "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.; rule 64 \u2014 A finished feature is merged into main without waiting for approval \u2014 The user, message 17815 (2026-10-07): 'make sure that no pull requests are lingering on the repository. You may merge them into main... You are allowed to merge everything into main once the feature is completed.' This replaces rule 61's wait for approval: a feature still goes on its own branch, and once it is complete, tested and its whole suite passes, it is merged into main and released, and no pull request is left open.", "meta": {"from": "journal"}}
{"content": "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": "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.", "meta": {"from": "journal"}}
{"content": "The viewer build for release-267; Barbara's sins-266 is still being written\u2026", "meta": {"from": "journal"}}
{"content": "rule 65 \u2014 Run only new and affected tests while working; the whole suite only\u2026 \u2014 The user, messages 17914 to 17917 (2026-10-07): 'stop running the whole test suite and wasting my time... please only run the new or affected tests, and then, whenever you are merging to main or publishing to main, you can run the full test suite.' Replaces rule 41's whole suite before every commit: on a feature branch, run the tests beside what changed (journal check touched, or the feature's test.py and the browser scenarios it touches); the whole suite runs once, before a merge into main and its release.", "meta": {"from": "journal"}}
{"content": "work 31 is still open \u2014 end it or park it before you stop: journal work end 31 --how \"<what landed>\", or journal work park 31 \"<why it waits>\"", "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": "rule 40 \u2014 A feature is named for what it is, never for its machinery \u2014 Messages 599, 600 and 703. A feature is a capability the user would name and would think of switching off. File tracking, a write gate, a phrase bank, a tree diff are services used inside a feature, not features of their own: they live in the feature they serve. Before adding a directory under features/, say what the user would call it; if the answer names a mechanism, it belongs inside something else. Report 16 holds the grouping this implies.", "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.; rule 66 \u2014 The journal never slows the agent down \u2014 The user, message 18990, after hooks timed out and waited on locks under load: the journal must never, ever decrease the performance of an agent. A hook answers at once with what decides the tool call; everything else runs after, in the background, and reaches the agent as a message. No hook waits on a lock it does not need.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 before you commit \u2014 you've changed 1 judged file since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 1 judged file 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 47 \u2014 The journal sets itself up once, when the server starts, never per\u2026 \u2014 Messages 2220 and 2224. Discovering features and their handlers, seating the feature rows and the rename sweep happen once, at server boot, and again only when a feature is switched on or off, a plugin changes or an environment is added: features.load keeps a set-up generation per journal (SEATED) and redoes the work only when that generation moves. A command, a request or a hook uses what is already there; nothing in their path may rediscover handlers or rescan folders. A cost that repeats per call is a bug to fix, not a budget to raise.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 before you commit \u2014 you've changed 1 judged file since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 1 judged file 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": "your chat talked about the journal's workings - \"Reading them\" \u2014 the user sees replies, reactions, pills and reads themselves; say what the work is instead", "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 commit \u2014 you've changed 1 judged file since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 1 judged file 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": "Code Commandments \u2014 `test.py`, changed since the last check, breaks a rule. Fix\u2026 \u2014 Code Commandments \u2014 `test.py`, changed since the last check, breaks a rule. Fix it now, at its SOURCE, while the code is still in front of you: \u00b7 \u2022 python-blank-string-default at /Users/jessegall/projects/agent-journal/.claude/worktrees/record-two-writers/src/features/integrations/test.py:171 \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": "Code Commandments \u2014 before you commit \u2014 you've changed 1 judged file since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 1 judged file 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": "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).; rule 39 \u2014 Use only registered exclamation response tags \u2014 A tag like [!reply:12] runs a command, and only the tags in the tags.runs setting are registered. An invented tag does nothing and shows as raw text in the chat. Use the registered ones (reply, log, end, todo, fact, rule) and nothing else.", "meta": {"from": "journal"}}
{"content": "work 32 in hand \u2014 Coverage for what 2.267.0 adds \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 1 judged file since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 1 judged file 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 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 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": "fact 30 \u2014 The tunler server refuses TLS for any subdomain without a tunnel \u2014 Seen 2026-10-04 in the server's docker logs (ssh root@tunler.jessegall.nl, container tunler): 'TLS handshake error ... host \"journal-probe.tunler.jessegall.nl\" not allowed'. A made-up subdomain never answers even when the server is healthy; probe https://tunler.jessegall.nl/ for the server itself. Root SSH to the server works.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 before you commit \u2014 you've changed 1 judged file since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 1 judged file 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": "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.; fact 25 \u2014 A designer's install packs the whole tree, half-done server edits\u2026 \u2014 2026-09-25: Eames and Saul run python3 src/journal.py --root .journal upgrade after their viewer builds; it packs every file in src, so a server handler I was halfway through writing went live and raised on every PostToolUse hook. While designers work in parallel, keep server edits whole between tool calls (write and test in the scratchpad first), and reinstall after reverting anything.; 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 31, Assemble 2.267.0 on release-267, is still parked - can you continue\u2026 \u2014 it was parked because: release-267 is assembled at 6ce4f1266; Barbara's sins-266 is picked when she reports. journal work resume 31 picks it up again.; 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 34 \u2014 A hooks list in a checkout's .claude/settings.json stops every\u2026 \u2014 Seen 2026-10-08: since commit 707a82915 the committed .claude/settings.json held {\"hooks\": []}; current Claude Code answers a hooks value that is not an object with a SettingsWarning dialog, which a headless helper cannot answer, so helpers 183 and 184 exited before doing anything (their launch logs in .journal/runtime/launches/ show it). This repository's journal hooks live in settings.local.json; the committed settings.json stays {}.; 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 chat talked about the journal's workings - \"Reading them\" \u2014 the user sees replies, reactions, pills and reads themselves; say what the work is instead", "meta": {"from": "journal"}}
{"content": "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.", "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": "Code Commandments \u2014 before you commit \u2014 you've changed 1 judged file since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 1 judged file 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 34 is still open, with nothing logged \u2014 journal work log 34 \"<what was decided or done, and why>\" \u2014 then journal work end 34 --how \"<what landed>\", or journal work park 34 \"<why it waits>\"", "meta": {"from": "journal"}}
{"content": "work 31, Assemble 2.267.0 on release-267, is still parked - can you continue\u2026 \u2014 it was parked because: release-267 is assembled at 6ce4f1266; Barbara's sins-266 is picked when she reports. journal work resume 31 picks it up again.", "meta": {"from": "journal"}}
{"content": "law L5 \u2014 Every subagent dispatch names the agent - a human name, a little\u2026 \u2014 A name is how the user and the chat tell subagents apart and how they are messaged later; an id or a task line is not a name. Start the dispatch's description with the name, a colon, then the task, such as \"Dr. Einstein: profile the slow hooks\" or \"Coco Rams: draw the plan card\". A designer can borrow from famous designers, a researcher from famous scientists, mixed up for fun.; 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 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": "your message 1187 names 200 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 1187 \"<the text>\"", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 before you commit \u2014 you've changed 1 judged file since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 1 judged file 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": "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.; 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 64 \u2014 A finished feature is merged into main without waiting for approval \u2014 The user, message 17815 (2026-10-07): 'make sure that no pull requests are lingering on the repository. You may merge them into main... You are allowed to merge everything into main once the feature is completed.' This replaces rule 61's wait for approval: a feature still goes on its own branch, and once it is complete, tested and its whole suite passes, it is merged into main and released, and no pull request is left open.", "meta": {"from": "journal"}}
{"content": "your message 1190 names 500 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 1190 \"<the text>\"", "meta": {"from": "journal"}}
{"content": "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.", "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": "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": "work 31, Assemble 2.267.0 on release-267, is still parked - can you continue\u2026 \u2014 it was parked because: release-267 is assembled at 6ce4f1266; Barbara's sins-266 is picked when she reports. journal work resume 31 picks it up again.", "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 31 in hand \u2014 Assemble 2.267.0 on release-267 \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 61 \u2014 Features wait as pull requests until approved; only hotfixes merge\u2026 \u2014 Message 17118 (2026-10-06), after the overnight refactor merged as 2.252.0: start new work in a new branch, do not merge, write the pull request. Every pull request or new feature is parked until the user approves it. Hotfixes can be merged into main immediately (by a dispatched agent in a worktree of main, rule 60).", "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.", "meta": {"from": "journal"}}
{"content": "rule 66 \u2014 The journal never slows the agent down \u2014 The user, message 18990, after hooks timed out and waited on locks under load: the journal must never, ever decrease the performance of an agent. A hook answers at once with what decides the tool call; everything else runs after, in the background, and reaches the agent as a message. No hook waits on a lock it does not need.", "meta": {"from": "journal"}}
{"content": "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 47 \u2014 The journal sets itself up once, when the server starts, never per\u2026 \u2014 Messages 2220 and 2224. Discovering features and their handlers, seating the feature rows and the rename sweep happen once, at server boot, and again only when a feature is switched on or off, a plugin changes or an environment is added: features.load keeps a set-up generation per journal (SEATED) and redoes the work only when that generation moves. A command, a request or a hook uses what is already there; nothing in their path may rediscover handlers or rescan folders. A cost that repeats per call is a bug to fix, not a budget to raise.; install.py names 2 files in the project \u2014 write the path so the chat can link it: install.py, src/install.py; 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": "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": "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 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 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": "work 31 in hand \u2014 Assemble 2.267.0 on release-267 \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": "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": "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 before you commit \u2014 you've changed 1 judged file since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 1 judged file 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 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).; fact 25 \u2014 A designer's install packs the whole tree, half-done server edits\u2026 \u2014 2026-09-25: Eames and Saul run python3 src/journal.py --root .journal upgrade after their viewer builds; it packs every file in src, so a server handler I was halfway through writing went live and raised on every PostToolUse hook. While designers work in parallel, keep server edits whole between tool calls (write and test in the scratchpad first), and reinstall after reverting anything.; fact 34 \u2014 A hooks list in a checkout's .claude/settings.json stops every\u2026 \u2014 Seen 2026-10-08: since commit 707a82915 the committed .claude/settings.json held {\"hooks\": []}; current Claude Code answers a hooks value that is not an object with a SettingsWarning dialog, which a headless helper cannot answer, so helpers 183 and 184 exited before doing anything (their launch logs in .journal/runtime/launches/ show it). This repository's journal hooks live in settings.local.json; the committed settings.json stays {}.; 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 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 1248 names 500 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 1248 \"<the text>\"; work 31 is still open \u2014 end it or park it before you stop: journal work end 31 --how \"<what landed>\", or journal work park 31 \"<why it waits>\"", "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": "rule 65 \u2014 Run only new and affected tests while working; the whole suite only\u2026 \u2014 The user, messages 17914 to 17917 (2026-10-07): 'stop running the whole test suite and wasting my time... please only run the new or affected tests, and then, whenever you are merging to main or publishing to main, you can run the full test suite.' Replaces rule 41's whole suite before every commit: on a feature branch, run the tests beside what changed (journal check touched, or the feature's test.py and the browser scenarios it touches); the whole suite runs once, before a merge into main and its release.", "meta": {"from": "journal"}}
{"content": "rule 40 \u2014 A feature is named for what it is, never for its machinery \u2014 Messages 599, 600 and 703. A feature is a capability the user would name and would think of switching off. File tracking, a write gate, a phrase bank, a tree diff are services used inside a feature, not features of their own: they live in the feature they serve. Before adding a directory under features/, say what the user would call it; if the answer names a mechanism, it belongs inside something else. Report 16 holds the grouping this implies.", "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": "Code Commandments \u2014 before you commit \u2014 you've changed 3 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: 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.; 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.; 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 64 \u2014 A finished feature is merged into main without waiting for approval \u2014 The user, message 17815 (2026-10-07): 'make sure that no pull requests are lingering on the repository. You may merge them into main... You are allowed to merge everything into main once the feature is completed.' This replaces rule 61's wait for approval: a feature still goes on its own branch, and once it is complete, tested and its whole suite passes, it is merged into main and released, and no pull request is left open.", "meta": {"from": "journal"}}
{"content": "work 31, Assemble 2.267.0 on release-267, is still parked - can you continue\u2026 \u2014 it was parked because: release-267 at 01aae9470; waiting for test results and the Docker network-cut lines. journal work resume 31 picks it up again.", "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": "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 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": "law L5 \u2014 Every subagent dispatch names the agent - a human name, a little\u2026 \u2014 A name is how the user and the chat tell subagents apart and how they are messaged later; an id or a task line is not a name. Start the dispatch's description with the name, a colon, then the task, such as \"Dr. Einstein: profile the slow hooks\" or \"Coco Rams: draw the plan card\". A designer can borrow from famous designers, a researcher from famous scientists, mixed up for fun.", "meta": {"from": "journal"}}
{"content": "work 31, Assemble 2.267.0 on release-267, is still parked - can you continue\u2026 \u2014 it was parked because: release-267 at 08bbd889e on Ingrid's 84d9a3e56; rebase again when she adds commits. journal work resume 31 picks it up again.; 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.", "meta": {"from": "journal"}}
{"content": "The viewer build for release-267 after rebasing onto Ingrid's 7c9e8bf55 came\u2026", "meta": {"from": "journal"}}
{"content": "rule 66 \u2014 The journal never slows the agent down \u2014 The user, message 18990, after hooks timed out and waited on locks under load: the journal must never, ever decrease the performance of an agent. A hook answers at once with what decides the tool call; everything else runs after, in the background, and reaches the agent as a message. No hook waits on a lock it does not need.", "meta": {"from": "journal"}}
{"content": "Code Commandments \u2014 before you commit \u2014 you've changed 8 judged files since the\u2026 \u2014 Code Commandments \u2014 before you commit: you've changed 8 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": "rule 61 \u2014 Features wait as pull requests until approved; only hotfixes merge\u2026 \u2014 Message 17118 (2026-10-06), after the overnight refactor merged as 2.252.0: start new work in a new branch, do not merge, write the pull request. Every pull request or new feature is parked until the user approves it. Hotfixes can be merged into main immediately (by a dispatched agent in a worktree of main, rule 60).", "meta": {"from": "journal"}}
{"content": "work 31, Assemble 2.267.0 on release-267, is still parked - can you continue\u2026 \u2014 it was parked because: release-267 at f1f256bf6 on Ingrid's 7c9e8bf55; rebase again when she adds commits. journal work resume 31 picks it up again.", "meta": {"from": "journal"}}
{"content": "rule 47 \u2014 The journal sets itself up once, when the server starts, never per\u2026 \u2014 Messages 2220 and 2224. Discovering features and their handlers, seating the feature rows and the rename sweep happen once, at server boot, and again only when a feature is switched on or off, a plugin changes or an environment is added: features.load keeps a set-up generation per journal (SEATED) and redoes the work only when that generation moves. A command, a request or a hook uses what is already there; nothing in their path may rediscover handlers or rescan folders. A cost that repeats per call is a bug to fix, not a budget to raise.", "meta": {"from": "journal"}}
{"content": "that Bash call returned 97,405 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": "that Bash call returned 142,806 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 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": "your answer to a journal line was kept out of the chat \u2014 a journal line is an instruction, not a message: act on it and write nothing, unless the user needs to know something such as a failure, finished work or a decision that waits on them", "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 L6 \u2014 A journal line is an instruction, never a message - act on it and\u2026 \u2014 A line that starts with [journal], a reminder, a notice or an old helper report is the journal telling the agent what to do, not the user speaking. Answering it fills the user's chat with noise. Act on it, or note it and carry on; write in the chat only what the user needs to know, such as a failure, a finished piece of work or a decision that waits on them.; rule 67 \u2014 Never answer a journal line in the chat; act on it silently \u2014 The user, messages 19360 and 19365: the agent kept writing chat lines in reply to the journal's own reminders (old helper reports, notices), filling the user's chat with noise. A journal line is an instruction to the agent, not a message: act on it and write nothing, unless the user needs to know something (a failure, a finished piece of work, a decision that waits on them). The journal itself should enforce it, not a local reminder.", "meta": {"from": "journal"}}
{"content": "law L4 \u2014 Related work goes back to the helper or subagent that already worked\u2026 \u2014 A helper or subagent that drew a design, wrote the code or ran the research keeps what it learned. When new work changes its work, is related to it or touches the same code, send it there with a message (SendMessage, journal helper say) rather than dispatching a new one that has to rediscover everything; start fresh only when the earlier one is gone or the new work is unrelated.", "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.; 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.; rule 43 \u2014 A request or hook over its budget is fixed before the next release \u2014 Comment 1151 on this rule. When the faults feature reports a request, a hook or a command slower than its budget, file it as a to-do at once. It does not jump ahead of the work in hand, but no version is published while one is still open: profile it, fix it, and verify the new time before the release goes out. The budget is 50ms, because everything runs locally against files.", "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.; fact 34 \u2014 A hooks list in a checkout's .claude/settings.json stops every\u2026 \u2014 Seen 2026-10-08: since commit 707a82915 the committed .claude/settings.json held {\"hooks\": []}; current Claude Code answers a hooks value that is not an object with a SettingsWarning dialog, which a headless helper cannot answer, so helpers 183 and 184 exited before doing anything (their launch logs in .journal/runtime/launches/ show it). This repository's journal hooks live in settings.local.json; the committed settings.json stays {}.; 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": "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": "work 31, Assemble 2.267.0 on release-267, is still parked - can you continue\u2026 \u2014 it was parked because: release-267 at 8c1aa8312 on main f88d1e510; picking further sins-267 commits as Barbara reports. journal work resume 31 picks it up again.", "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": "the end tag does this in one step \u2014 [!end:N] makes the turn itself what landed; it runs only when it opens the last text of your turn", "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": "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": "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": "rule 60 \u2014 A hotfix is done by a dispatched agent in a worktree of main \u2014 Message 16836 (2026-10-06): the orchestrator cut a worktree under .claude/worktrees for a Codex hotfix, its session moved to a new environment and the user's messages stopped reaching it. The user: when working on a branch and a hotfix comes in, create a worktree of main and dispatch an agent to do that work. The orchestrator stays on its branch and in its environment, and never cds into another checkout.", "meta": {"from": "journal"}}
{"content": "work 31 in hand \u2014 Assemble 2.267.0 on release-267 \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 the files changed since the last check (`integrations.mjs`,\u2026 \u2014 Code Commandments \u2014 the files changed since the last check (`integrations.mjs`, `IntegrationsPage.vue`, `navigation.js`, `handlers.py`, `feature.py`) breaks a rule. Fix it now, at its SOURCE, while the code is still in front of you: \u00b7 \u2022 plain-viewer-text at /Users/jessegall/projects/agent-journal/.claude/worktrees/record-two-writers/src/web/src/pages/IntegrationsPage.vue:17 \u00b7 LOAD the skill `commandments-plain-viewer-text` 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 64 \u2014 A finished feature is merged into main without waiting for approval \u2014 The user, message 17815 (2026-10-07): 'make sure that no pull requests are lingering on the repository. You may merge them into main... You are allowed to merge everything into main once the feature is completed.' This replaces rule 61's wait for approval: a feature still goes on its own branch, and once it is complete, tested and its whole suite passes, it is merged into main and released, and no pull request is left open.", "meta": {"from": "journal"}}
