SUITS & SANDALS

Expertise

  • Website Strategy, UX & Development
  • Sales, Marketing & Investor Communications
  • Clarifying Complex Stories
  • Embedded Creative & Digital Services
  • Product UX/UI & Design Systems

Who We Help

  • Technical B2B & Expert-Led Companies
  • Healthtech & Life Sciences
  • Growth & Repositioning Brands
  • Platforms & Digital Products
Ask
Answers about our work, services, and insights
Email a partner
  • HR TechVault Workforce Screening
  • Enterprise SoftwareAdaCore
  • InsurtechArturo
  • FintechInterchecks
  • Works
  • Insights
  • Immersive Lab
  • About Us
  • Website Strategy, UX & Development
  • Sales, Marketing & Investor Communications
  • Clarifying Complex Stories
  • Embedded Creative & Digital Services
  • Product UX/UI & Design Systems
  • Technical B2B & Expert-Led Companies
  • Healthtech & Life Sciences
  • Growth & Repositioning Brands
  • Platforms & Digital Products
Get in touch

Brooklyn, NY / Philadelphia, PA

Get in touch

Lab / Tool

The lab journal

To document internal projects and R&D work, I built a journal to preserve the decisions behind work made with AI agents. Its first article showed what the record could capture, and what a writer still has to decide.

Editor
Miles Roxas
Published
27 September 2026
Built with
Claude Code, TypeSafe Jev, Payload CMS+3
Read
8 MIN

Keep the decisions while they are still clear

The idea started after a session reviewing the studio's CMS tooling. I asked for a document that kept the findings alongside my prompt, the model and its token usage. That raised a more useful question: could the same record follow every feature across days and sessions?

I wanted a Lab entry to explain why the work took its particular shape, including the options left behind and the problems that changed the plan. Reconstructing those decisions at the end would lose the context that made them worth writing about.

Record the reasons where the work happens

Claude proposed a skill for the working agent, hooks for the mechanical record, and a separate writer at the end. I accepted that split. The agent making a change has the context to log its reasons; the hooks can capture prompts and count tokens without asking a model to interpret them.

A fresh writer then gets the journal as its source. That separation matters: the finished article has to make sense to someone who was not in the session. Raw prompts stay redacted on my machine because the repository is public.

Who records what

logspromptsbrieftokensWorking sessionjournal.mdHooksJev digestWriter agentDraftDraft check
logspromptsbrieftokensWorking sessionjournal.mdHooksJev digestWriter agentDraftDraft check
Description and steps

A flow from the build to the draft. The working session logs each decision to journal.md. Hooks, with no model, capture every prompt and every session's token counts. At wrap-up Jev's digest reads the journal and the prompts and hands a brief to the writer agent, which also reads the token counts and writes the Lab Project draft, and the draft goes through the draft check. The takeaway is that the only model watching the build is the session doing the work. Everything else is captured by code or read once at the end.

  1. Working session
  2. journal.md
  3. Hooks
  4. Jev digest
  5. Writer agent
  6. Draft (start or end)
  7. Draft check (start or end)

Connections

  • Working session to journal.md: logs
  • journal.md to Jev digest
  • Hooks to Jev digest: prompts
  • Jev digest to Writer agent: brief
  • Hooks to Writer agent: tokens (optional or async)
  • Writer agent to Draft
  • Draft to Draft check

First, make the record trustworthy

The first run recorded the wrong conversation

Before a writer could trust that record, the capture had to belong to the right work. The first live run failed there. The start command chose the newest transcript file, but I had another session open in the same checkout. Its prompts and token counts went into the journal.

The session id in the output exposed the mistake. Claude changed the lookup to use the id supplied by Claude Code, leaving the newest file as a last resort. The unit tests had passed; running against the real machine revealed the assumption they had missed.

A session is not a feature

Finding the right conversation solved only part of the problem. Claude had put the CMS review and the building of the journal into one record, with the whole session's tokens. I caught the mix after the push.

The fix was a time window: close one feature's share of the session at the prompt where the subject changes, then open the next. That keeps the evidence and usage attached to the feature they describe. Someone still has to recognize the change of subject.

One session, split by a window

yesnoSessionBefore split?CMS reviewJournal build
yesnoSessionBefore split?CMS reviewJournal build
Split at the prompt sent on 21 September 2026 at 16:33:08 UTC. Earlier work belongs to the CMS review; later work belongs to the journal build.
Description and steps

A flow for the first session of 21 September, which held two features. A window at 16:33:08 UTC, the prompt where the conversation turned, sends everything before it to the MCP review journal and everything after it to the lab journal. The takeaway is that a session no longer has to belong to one feature, and its tokens are counted once across the two journals.

  1. Session (start or end)
  2. Before split? (decision)
  3. CMS review (start or end)
  4. Journal build (start or end)

Connections

  • Session to Before split?
  • Before split? to CMS review: yes
  • Before split? to Journal build: no

Help the writer choose and check

Give the writer a way into the record

A trustworthy record still leaves the writer with a lot to read. Claude added a digest using Jev, TypeSafe's model. It suggests where entries belong, which prompts might be worth quoting and where a figure could help. It also flags agent messages that might contain an unlogged decision.

The digest runs at wrap-up so a model request cannot interrupt prompt capture. Jev can suggest a diagram, but the writer still has to check whether drawing it would explain the decision. The first figure plan made that limit visible.

A suggestion that selected everything

Asked whether an entry described something a diagram could show, Jev selected all 17 entries. Almost anything can be drawn, so the answer did little to help the writer choose.

Claude changed the question to ask whether explaining a mechanism was the entry's main purpose. It also described the near miss: an entry can mention components while really being about a decision. That brought the selection down to five. The useful distinction was what a figure would help the reader understand.

Entries the diagram question put forward

Wording

Entries put forward, of 17

Source: docs/lab-journal/lab-journal/journal.md
Description and data table

A horizontal bar chart of three wordings of one question over the same 17 journal entries. Asked whether a diagram could show the entry, Jev put forward all 17. As a score from 0 to 3, 15 scored 2.9 or higher. Asked whether the entry is mainly an explanation of a mechanism, 5 passed. The takeaway is that the wording, not the model, decided whether the plan was useful.

Entries the diagram question put forward
WordingEntries
Could it be drawn?17
Score of 2.9+15
A mechanism?5

Check the claims against the source

Selection creates another responsibility: the writer must stay faithful to the evidence it keeps. The draft check first looks for numbers absent from the record. Jev then compares each sentence with the three journal entries that share the most words with it and reports support, contradiction or missing evidence.

That comparison can miss a source in a prompt or a commit. It gives the writer a list to investigate, rather than permission to treat every unflagged sentence as proven.

How a draft sentence is checked

yesnoDraftSentencesCode: dashes, numbersJev: verdictCheckable?ListedSkippedverify.md
yesnoDraftSentencesCode: dashes, numbersJev: verdictCheckable?ListedSkippedverify.md
Description and steps

A flow for one Lab Project draft. The draft is split into sentences. Code lists every em dash and every number the record does not hold. Jev then judges each sentence against the three journal entries nearest to it, with a verdict and whether it states a checkable fact. A checkable sentence is listed when the record contradicts it, says nothing about it, or supports it with low confidence. Anything else is skipped as connective prose. What is listed goes into verify.md, which ends with the voice check. The takeaway is that code handles what is exact and Jev only what needs judgment.

  1. Draft (start or end)
  2. Sentences
  3. Code: dashes, numbers
  4. Jev: verdict
  5. Checkable? (decision)
  6. Listed
  7. Skipped (start or end)
  8. verify.md (start or end)

Connections

  • Draft to Sentences
  • Sentences to Code: dashes, numbers
  • Code: dashes, numbers to Jev: verdict
  • Jev: verdict to Checkable?
  • Checkable? to Listed: yes
  • Checkable? to Skipped: no
  • Listed to verify.md

The first check needed a check of its own

A test draft included an em dash, invented numbers and a reversed decision. Code caught the punctuation and numbers; Jev caught the contradiction. But the invented result initially fell below the threshold for deciding whether a sentence made a checkable claim.

Lowering that threshold brought the claim into review. The test was useful because it exposed a missed error. It did not establish the check's accuracy on every future article.

Make the copy sound and read like me

Accuracy still leaves the voice to solve

A sourced sentence can still sound unlike me. I asked for the writer to follow the studio's voice, so the same pipeline gained a shared voice document, a save-time gate and a broader review with code and Jev.

The gate handles the exact rules: it refuses agent saves containing an em dash or a banned phrase. The review looks for generic, inflated or formulaic writing. Those judgments need a person to read them. The shared rules also reach other CMS collections and the Ask assistant.

One voice file, read in four places

testedone linevoice.mdvoice.tsAsk promptSave gateVoice checkDraft check
testedone linevoice.mdvoice.tsAsk promptSave gateVoice checkDraft check
Description and steps

One file, docs/editorial/voice.md, holds the house voice. A test keeps voice.ts, the same rules as code, identical to it, and one line of the rules goes into the Ask assistant's system prompt. From voice.ts the rules reach the save gate, which refuses an API key's save that holds an em dash or a banned phrase on every collection, and the check, pnpm editorial:voice, whose report also ends the draft check. The takeaway is that the voice work reaches past the lab pipeline: the gate covers the whole CMS, and the Ask assistant reads the same rules.

  1. voice.md (start or end)
  2. voice.ts
  3. Ask prompt
  4. Save gate
  5. Voice check
  6. Draft check

Connections

  • voice.md to voice.ts: tested
  • voice.md to Ask prompt: one line
  • voice.ts to Save gate
  • voice.ts to Voice check
  • Voice check to Draft check
The What is checked table in docs/editorial/voice.md on GitHub: each voice rule, where it is checked (at save for MCP writes, in pnpm editorial:voice, or in pnpm lab:journal:verify) and how, by code or by Jev, with the note that only API key saves are refused.

One table in voice.md says which rule is enforced where.

Calibrate against writing I would keep

Claude tested the voice review on two Lab Projects I had approved and a deliberately generic agency draft. The first thresholds flagged some of the approved assertions as inflated, so the thresholds moved into the gap between the two sets.

Some abstract lines still appeared as generic even though they expressed a specific studio point of view. I kept those. A voice check should help me notice weak writing without sanding away the ideas that make the writing mine.

Keep the article's signposts with its copy

The page also needed headings that would help a reader follow the story. Claude initially proposed copying each beat's heading from the Lab Project into its page block. I rejected that duplication: a beat now brings its heading from the canonical record, with a page override only when needed.

Repeated headings also needed a rule. Code hides exact repeats of the section opener. Jev judges paraphrases when the page is saved, so the page can avoid saying the same thing twice.

Lab Project 3 in the CMS admin with story beat 23 of the Approach section open: Key custom-copy-falls-through, Label Custom copy falls through, Heading Page copy wins, canonical copy falls through, and the beat's body below.

A beat carries its own public heading on the record.

Lab Page 2 on the live site: the eyebrow Payload CMS, the Section opener Enter Payload with its standfirst, then the beat heading Why Payload printed from the record one level down, and the start of the beat.

The record's beat heading prints one level under the Section's opener.

What the heading check actually added

In the test on the Webflow-to-Payload page's 48 beats, code hid 13 exact repeats and Jev identified two more paraphrases. The remaining 33 headings printed. Most of the work belonged to a simple rule; the model handled the narrower judgment the rule could not make.

The first article exposed a different problem

The first article asked too much of the reader

All of those checks still left the most important test: reading the finished article. The writer's first run on this journal produced 41 beats across 24 sections. It followed the journal closely, called me by name in the third person 28 times, and left 11 sections with no visual.

The brief had pointed to my published Lab Pages as examples and asked for every beat to appear. The writer copied their scale along with their strengths. The brief specified coverage and examples, but no reading-time limit.

The examples were over budget too

The first draft took 28 minutes by the site's prose count, before code listings were included. With code listings excluded, From Webflow to Payload took 15 minutes and the shader studio page took 14. At 200 words a minute, none fit the five-to-ten-minute article I wanted.

That made the problem concrete. Removing code from the reading-time calculation could make the estimate more useful, but the draft still needed an editorial cut.

Minutes to read, by the hero's count

  • With code
  • Prose only

Lab Page

Minutes

Counted on 27 September, first with code at 20 lines a minute, then prose only.Source: docs/lab-journal/lab-journal/journal.md
Description and data table

A horizontal bar chart of three Lab Pages, each read with code listings counted and with prose only. The first draft of this page took 39 minutes with code and 28 without. From Webflow to Payload took 22 and 15. The shader studio page took 15 and 14. A line marks the ten minute ceiling. The takeaway is that all three pages were over the budget, the two published pages the writer copied included.

Minutes to read, by the hero's count
Lab PageWith codeProse only
First draft of this page3928
From Webflow to Payload2215
Shader studio1514

Set the boundaries the examples left unstated

I set three requirements: write in my first person, stay within ten minutes of prose, and give every section a visual. Claude made them part of the draft check. The first rewrite came down to seven sections and 19 beats, with a seven-minute prose count.

The shorter page still gave session capture, voice calibration and heading mechanics similar weight. It needed a clearer connection between those parts: first preserve the decisions, then help a reader understand them. The page rules did not test for that.

What the first published test taught me

How the work was shared

I set the direction, reviewed the drafts and made the calls attributed to me in the journal. Claude designed and built the tooling, logged the work and proposed decisions of its own. Jev helped sort the record and review the copy.

The chart records the build and first write-up sessions through 27 September. Cache reads dominate that volume because context is read repeatedly; they should not be compared with output tokens as if they measured the same work. These figures document usage, not time saved or the quality of the result.

Tokens per session

  • Output
  • Cache write
  • Cache read

Session

Tokens

Historical snapshot through 27 September 2026, 18:49 UTC. The final session was incomplete at capture. Input tokens are too small to draw.Source: docs/lab-journal/lab-journal/sessions.jsonl
Description and data table

A horizontal bar chart of ten sessions in date order, each with its output, cache write and cache read tokens. Cache reads dominate every session. In this historical snapshot, the session that ran the first write-up and the new rules, from 17:17 UTC on 27 September, read 81.6 million tokens from cache by 18:49 UTC. The longest build session, from 23:50 UTC on 21 September, read 20.8 million and wrote 154 thousand output tokens. Four short sessions on 21 September read under 3 million each. The takeaway is that cache reads, the context read again on every message, are nearly all of the volume and are not comparable to output.

Tokens per session
SessionOutputCache writeCache read
21 Sep 16:33103.2K158.7K16.4M
21 Sep 17:534K47.9K867.9K
21 Sep 18:051.4K39.5K256.3K
21 Sep 18:1123.3K104.2K2.7M
21 Sep 18:3271.8K478.1K11.9M
21 Sep 19:282.1K41.9K215.1K
21 Sep 23:50153.9K640.2K20.8M
27 Sep 17:001.5K52.6K534.9K
27 Sep 17:0311.7K100.9K1.7M
27 Sep 17:1768.9K1.2M81.6M

Test the handoff, not just the parts

The same pattern appeared twice. Capture passed its unit tests and then took the wrong session on the real machine. The shorter article met the page rules and had been checked against the record, but it was still hard to follow.

Each handoff needs its own test: does the record describe the right work, and does the article help a new reader understand it? Checking the individual parts cannot answer both questions.

Tell the writer what the example is for

The brief should say what an example is for. I wanted the diagrams and screenshots on my published pages, but the writer also copied their length.

Next time I would name those qualities alongside a reading-time limit, rather than leave the writer to infer the brief from a reference page.

What I would carry into the next feature

The journal now gives a fresh writer a record of the decisions, failures and evidence behind a feature. It still depends on someone noticing when the conversation changes subject, and its private prompt history stays on the machine that captured it.

For the next write-up, I would decide the article's central question before choosing its beats or figures, then read the assembled page for the connections between sections. That is the judgment this first published test needed: enough context to follow the decisions, and enough restraint to know which ones belong in the story.

About this project

Status
In progress
Built with
Claude CodeTypeSafe JevPayload CMSTypeScriptModel Context ProtocolClaude in Chrome
  • A layered approach to brand and product design systems

    Research · Active

  • The new Suits & Sandals CMS

    Tool · Active

  • Payload CMS Shader Plugin

    Tool · Active

More from the lab

01 / 03

Ready to start?

Let’s make it make sense.

Request an estimateGet in touch

Want to go deeper?

Ask about our work, process, capabilities, or what working together could look like.

S&S

Ask Suits & Sandals

Online

Email a partner
Privacy PolicyTerms and Conditions