House rulesLesson
Session logs
An agent's session is seen only by the people in it. When it ends, its transcript is gone from view, and with it every wrong turn, confusing doc and wasted step. A session log keeps what only the session knew, so the project can learn from work nobody watched.
Know agent session logs already? Skip to In Terrarium.
Outside the box · General
The concept
Observability, for agents, means being able to tell from records what an agent did and where it struggled, without having watched it. Git shows what changed; it can't show what the agent read, which instruction misled it or which step it had to repeat.
A session log fills that gap. It has two halves. The judgement half only the agent can write: what it set out to do, how far it got, and every problem it hit, each with a possible fix. The mechanical half, such as timings, tools used and files read, comes from the recorded transcript, because an agent misremembers facts that the transcript holds exactly.
The problems are the point. One log's complaint is an anecdote; the same complaint in many logs is a pattern worth fixing. That only works if agents report every problem, small ones too, and report them honestly, so a log is a self-report to learn from, never a performance review.
In Terrarium
Each session writes a into the Journal, the Tenant where Terrarium documents itself. When its work reaches a coherent state, such as a PR opened or a question answered, the agent runs the close-session Skill, which calls log-session. The agent writes the judgement half into a scratch file: its goal, a status, an outcome, a summary, why the docs and Skills it names mattered, and every . The schema in shared/schemas/session.ts makes the list of Frictions required, even when it is empty:
132 // List EVERY friction — not just one or two. No `tag`: the Friction Ledger
133 // groups frictions by cause instead (GLOSSARY.md).
134 frictions: z.array(
135 z.object({
136 description: z.string(), // ~20 words — honest description
137 solution: z.string(), // possible fix / what would have helped
138 severity: z.enum(['nit', 'minor', 'moderate', 'major', 'blocker']),
139 }),
140 ),
The log-session Skill defines each severity grade.
At the end of that turn, a Stop hook in .claude/settings.json runs scripts/session/log-session.ts. It derives the mechanical half from the transcript with scripts/session/transcript-trace.ts, adding the files the session edited from its own commits so an edit made through a shell command counts, joins the two, checks the result against the schema, and commits that one file to main without a PR. Fallback hooks at session end and on resume land a log the Stop hook missed. If the work continues, say the PR merges, the session logs again and replaces its earlier log. No other session ever edits it.
Later sessions read the logs. One groups Frictions by root cause in the , with every session that hit each cause and every PR meant to fix it, and turns the ones worth fixing into PRs or issues. Another reads which Skills sessions used, and a takes the Frictions logged while it stands as its verdict. Logs from outside agents are marked external, and both Skills skip them.
Why it's built this way
- First-hand records. Nobody can see an ended session's transcript, and the repository shows what changed, not what was hard. The Skills that improve Terrarium need that record, so logs are first-hand, never rebuilt from the repository; a status dashboard built that way was rejected. The cost: this part of the Journal can't be regenerated. ADR-0008 (docs/adr/0008-self-documentation-tenant-is-a-journal.md).
- Straight to
main. A PR for a log is ceremony that makes agents skip or thin their logs, and no PR fits every session: some open none, some several, and a rejected PR's Frictions still happened. So a log skips the and goes straight tomain. ADR-0009 (docs/adr/0009-session-logs-commit-directly-to-main.md). - Why that is safe. A log is data checked against a fixed format and touches no code or page, so it can't break the build; one gated script limits the shortcut to that one file. The cost: unreviewed commits on
main, pushed with the owner's credential, which on its own could push anything. ADR-0009 (docs/adr/0009-session-logs-commit-directly-to-main.md). - Facts from the transcript. When the agent reported everything, its claims about reads, Skills and start time didn't match the transcript. Now it writes only the judgement and a script takes the facts. Whether a shell command "read" a doc is a guess, so the agent may deny a read the script counted, logged as a Friction so the script's mistakes stay visible. ADR-0009 (docs/adr/0009-session-logs-commit-directly-to-main.md).
- Written at closure. A hook at session end couldn't ask the agent or tell a pause from an end, and a paused web session can lose its network, so logs were lost. Now the agent writes at closure and the
Stophook lands the log at turn end, network up. The cost: no closure, no log, which beats a partial one. ADR-0009 (docs/adr/0009-session-logs-commit-directly-to-main.md).
What to watch for
- A flattering log is worse than none. The value is in the Frictions, nits included, so the Skills tell agents to be honest about what went wrong, even when they fixed it themselves.
- Don't inflate severity. A mistake caught before it landed stays a
nitorminor. Recurrence shows up in the Ledger's count, not in a louder grade. - A lost log is gone. Logs are never rebuilt from the repository, so a session that never writes one leaves no record of what it hit.
- Old logs never change. So the schema only grows; ADR-0009 says how a field may be added, and the one case where a person may remove one.
Try it in your project
At the end of each agent session, have the agent append three lines to a log file: what it tried to do, how far it got, and every problem it hit, with a possible fix and how much it cost. After a week, read the problems together and fix the one that appears most often.
Where next
- LessonCLAUDE.md
- LessonPull requests
- LessonSelf-improvement loop
- LessonScheduled tasks
- JournalFriction Ledger
Walkthroughs through this Lesson
- WalkthroughA change goes live
- WalkthroughAsking an agent for a change
Last updated · Latest source on GitHub ↗