{"content": "todo 1 next", "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 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 20 \u2014 A slim supervisor holds the agent and a worker reloads on every build \u2014 Since 2.118.0 (2026-09-23). src/supervisor.py is standard library only and never reloads: journal claude hands its process over to it (os.execv), and it owns the pty and the agent process, relays the terminal, writes the printed and screen captures, listens on the typist socket, restarts the agent in the same session from a relaunch command written to its runtime folder while a restart is pending, and stops it with escalation while draining the pty (an agent cannot finish exiting on macOS while its output is unread). It starts the worker (src/worker.py, which runs runner/worker.py; engine/worker.py stays as an alias for supervisors started before 2.201) and starts it again whenever it exits: RELOAD on a new build, RELAUNCH to restart the agent, STOP to end, HEAL or a quick crash to roll back a build through journal heal. The worker holds everything else: seating the session, the start-up confirm typed through the typist, services, viewer, update check, check-in, and the one-time relaunch of sessions launched before agents/terminal.py LAUNCH. agents/terminal.py holds only journal-side helpers. The server (serve.py) still runs the engines and re-execs itself on a .py change. When the agent exits, the supervisor runs journal ended, which puts set-aside hooks back and stops the server when no session is left.", "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).; 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 {}.", "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 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 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": "your command ran 32s 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": "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 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 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 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": "your command ran 55s 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 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": "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": "your command ran 98s 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 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": "your chat talked about the journal's workings - \"to-do 3722 are closed\" \u2014 the user sees replies, reactions, pills and reads themselves; say what the work is instead", "meta": {"from": "journal"}}
{"content": "your chat talked about the journal's workings - \"To-do 1 is closed\" \u2014 the user sees replies, reactions, pills and reads themselves; say what the work is instead", "meta": {"from": "journal"}}
{"content": "law L5 \u2014 Every subagent dispatch names the agent, in the naming style of the\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. The profile in use says how its agents are named.; 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 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 chat talked about the journal's workings - \"to-do 1 is closed\" \u2014 the user sees replies, reactions, pills and reads themselves; say what the work is instead", "meta": {"from": "journal"}}
{"content": "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.", "meta": {"from": "journal"}}
{"content": "your chat talked about the journal's workings - \"To-do 1 is already closed\" \u2014 the user sees replies, reactions, pills and reads themselves; say what the work is instead; 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": "your command ran 182s 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": "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 42 \u2014 Every user-facing text passes the formatters before it leaves the\u2026 \u2014 Not only a brief. A title, an abstract, an outcome and every section body are read by a person, so each goes through the same formatters on its way to the viewer \u2014 chat turns, activity items, to-do rows, inspector pages, docs alike. One field formatted out of five is not a rule, it is an accident, and it is how a raw tag ended up in the activity list after the tags feature had been stripping them for weeks. When a new field carries words a person reads, it joins the list in the same place.", "meta": {"from": "journal"}}
{"content": "your command ran 32s 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 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": "test.py names 76 files in the project \u2014 write the path so the chat can link it: src/features/acknowledgements/test.py, src/features/agent_sessions/test.py, src/features/ask_questions/test.py, src/features/attachment_descriptions/test.py, src/features/auto_archive/test.py", "meta": {"from": "journal"}}
