Repository navigation
Releases: DkPanseriya/deckhq
Release list
v1.7.0
Highlights
The office has been redrawn, and it is lit. Daylight comes in through the windows, furniture looks
like furniture, rooms stand behind solid, glass or low partitions and are dressed like rooms
somebody works in, and each project's room can have a colour of its own; there are eleven styles
to choose from, with Light and Room colours beside them. Sub-agents read as juniors: a
size smaller than their lead, cross-legged on the floor with a laptop and a Junior chip, and a
lead whose crew is still working stays at its desk. A git worktree is a bench inside its
repository's room, not a room of its own. Go to session — one button, or O — brings the
window a session is already running in to the front, and the panel's transcript reads like a
document, with tables, code you can copy and each tool call folded to one line. A Look button
and a Settings button are in the header. A floor where nothing is moving is not redrawn, and a
DeckHQ window pinned to the Windows taskbar keeps DeckHQ's icon.
Added
- A Look button in the header. Click it, or press
L, and a small panel opens under it with
the six things people change most: agent size (small, medium, large, auto), theme,
style (eleven presets, as pictures, four to a row so all of them are in view at once),
density, light and room colours. A click changes the floor straight away.Esc,L
again or a click anywhere else closes it. All look options… at the bottom opens the full
Look section. If a choice would leave the floor unreadable, the panel says why under the
control and changes nothing. - Density. One control, Calm / Normal / Lively, for how many plants and props are on the floor.
It moves the two together. If you want them different, set each one under Advanced. - A Settings button in the header. The gear beside Look opens the settings sheet.
,does the
same from the floor.Ctrl K→ Settings still works. - Section names at the top of Settings. State, Notifications, Resume, Floor, Look, Data and
Hooks are listed across the top of the sheet and stay there as you scroll. Click one to jump to
it. - A one-time pointer to the Look button. The first time you open a version that has it, one
line under the button says "Change the floor, the furniture and the agent size here." Press
Got it, or just use the button, and it does not come back. - Light: morning, noon or evening. Three words in the Look panel and at the top of Settings →
Look, beside Density, moved with a click or the arrow keys. It turns the one light on the floor
— 30°, 45° or 60°, always falling down and to the right — makes every shadow longer in the
morning and longer still in the evening, and colours the daylight on the floor cool, warm or
amber. Noon is the default. - Partitions: solid, glass or low. Under Look → Advanced, in Walls and room colours, each
choice a small picture of two rooms and the wall between them. It changes what stands between two
rooms. Solid is a band that casts like a wall. Glass is a sheet between two thin dark frame lines
with a post every few units, and casts nothing. Low is a waist-high divider with rounded ends
that stops short of each corner. The building's outside wall does not change. - Three more floors: oak plank, fine herringbone and felt carpet. In the floor pickers under
Advanced — oak plank for the office, the rooms and the lounge, fine herringbone for the office
and the lounge, felt for the office and the rooms. They are laid at the size of a real floor: a
board about 18 cm wide, a parquet block about 11 cm, and a felt with a fine grain and no weave.
Their seams are exactly one pixel of your screen wide. - Room colours: subtle, zoned or off. A switch in the Look panel and at the top of Settings →
Look: off is Subtle, on is Zoned. Space or Enter throws it. All three levels are under Advanced,
in Walls and room colours, and while Off is chosen there the switch reads off and says Off.
Subtle is the floor as it was: each
project room's carpet leans a little toward its project's colour, and on a floor of five rooms
the five are nearly the same beige. Zoned gives each project's room one of six calm colours —
sage, powder blue, lilac, mint, straw, rose — so two rooms side by side are told apart before
you read a plate. The colour is the floor's own brightness, so names and state colours read
exactly as they did: on the Colour plan style a name is 11.2:1 on the default theme, 10.3:1 on
night shift and 11.7:1 on blueprint, and two neighbouring rooms are at least 14.7, 23.0 and 21.6
RGB apart (subtle: 1 to 3). It works on every floor a room can have, wood included. Off is the
bare floor. Your agents keep their own colours. - Five more styles, which makes eleven. Daylight studio is pale ash under noon light with
glass between the rooms. Nordic wool is cool ash, cork and broadloom with low dividers under
morning light. Graphite loft is grey terrazzo and loop pile with dark frames behind glass, under
evening light. Colour plan gives every repository its own colour on a neutral building. Walnut
executive is fine herringbone and cork in a clay wash.?look=daylight-studio,
?look=nordic-wool,?look=graphite-loft,?look=colour-planand?look=walnut-executive
open the floor in them, and a look file exported from an earlier version still imports exactly
as it was. - A style's card shows its rooms, its walls and its light. Each of the eleven cards is painted
by the floor's own painter, and now shows two project rooms side by side in the colours that
style gives them, the partition between them, and shadows as long as its light throws. Colour
plan's card has a green room beside a blue one; before, it was a picture of a grey office, much
the same as two others. The cards' shadows are also the length they are on the floor — they
were drawn at half of it or less. - Daylight is one of the figures under Advanced. The line of measured contrast at the foot of
the Look section ends with daylight on the floor: how bright the strongest patch of daylight
is against the floor it lands on, in the light and the theme you are looking at. It is the
number the light is refused on, and it is never above 1.18:1. - Rooms look lived in. A room used to have the right furniture and bare walls. Each project
room now has a waste bin by its desks (and one at each worktree bench), a coat stand beside its
door, felt panels on its clear walls, and a lamp over a meeting table. Where one desk sits in a
room with empty floor, the room also gets a second place: a standing table with stools, a
reading corner with an armchair and a floor lamp, a booth for a call, or a whiteboard with two
stools. Nobody is ever seated at these, and nothing is put within a body's width of a seat, in
a doorway or on the way from the door to a desk. On the demo floor that is 35 more things in
five rooms; on a 150-agent floor, 199 in 22. - Density changes how much of that there is. Calm keeps only the bin and the coat stand.
Normal adds the panels, the lamps and up to two second places a room, three in a big team's.
Lively allows three in any room, and a planter run beside a reading corner. - A sub-agent's name tag has two rows. The first is a small chip that says Junior, on a
dark background of its own; the second is its name, without the·jrthat used to follow it. A
session of your own keeps one row. The same word is in the tooltip, in the deck's rows and in a
crew's list. On the chip the word is 8.7:1 against its background on the default theme, 12.1:1
on night shift and 13.2:1 on blueprint. - A sub-agent working on the floor has a laptop. It sits cross-legged with a small open laptop
on the carpet in front of it: the screen is lit green while its transcript is moving, and the
lid is shut once it has stopped. This was drawn for a crew of three or more and is now drawn for
one or two beside their lead as well, who used to stand. A sub-agent at a real desk or on a sofa
sits in the furniture as before. - Go to session. The panel has one button under the agent's name that takes you to where that
session is already running: the terminal, the editor or the Claude desktop app it is in comes to
the front, and the line beside the button says which —Windows Terminal — tab "fix the parser".
It never starts a second copy of a running session.Odoes the same from the keyboard, and
Ctrl Khas Go to …'s session. In Windows Terminal the session's tab is selected when its
title is the only one of its name; in the desktop app the app is opened on that session. When
the session has ended, the same button reads Resume in … and resumes it where you chose in
Settings. When a running session cannot be reached, the button is dead and says why. Measured on
Windows 11; written and not yet run on macOS and Linux, anddeckhq doctorhas a
go to sessionrow that says which your machine is. - A reply reads like a document. Tables are tables, task lists have their boxes, headings step
down in size, and prose stops at a readable line length. A code block shows its language and has
a copy button. A web link opens in a new tab. A file reference such assrc/panel.js:42
opens that file at that line in your editor. - What the agent ran is in the panel. Earlier in the conversation is folded above the answer,
and it now includes each tool call as one line —Bash npm test,Edit src/panel.js— that
opens to its input and its result. A sub-agent's hand-back opens to its report. latest ↓
takes you back to the answer. Claude Code sessions only. - Open in the session. An artifact, a picture you attached, and a result too long to show in
full each have a button that takes you to the session itself...
v1.6.2
Highlights
Subagents now have first names, with a small junior mark (Marta·jr), and keep their names and
numbers when DeckHQ restarts. Names stay next to the people they belong to, even in a crowded
office. A project whose sessions are all waiting on you shrinks to a small room, and your office is
only as wide as its sofas, so the rooms get the space.
Changed
- Subagents have names. A subagent used to be labelled with its parent's tag and a number,
MK129.5j8. It now gets a first name from the same list as everyone else, with a small junior
mark after it,Marta·jr, and keeps that name when DeckHQ restarts. The panel shows its parent
beside it. A subagent can share a first name with one of your sessions; the mark tells them
apart, anddeckhq open <name>still finds the session. - A project whose sessions are all waiting on you gets a small room. If everyone from a
project is on the sofas in your office and nobody is at a desk, the project keeps a room, but a
small one along the bottom of the working side, with one desk and itsN need youline. The
room grows back to full size as soon as one of its sessions starts working again.
Fixed
-
Names stay next to the person they belong to. In a crowded office, names could end up a row
or two away from the people they named, across the rug. A name now goes under the figure, over
its head, or beside it. If none of those spots is free, the name is drawn smaller, then cut to
four letters and a dot (Cass.). Only after that can it move further away, and when it does, a
thin line joins it to its figure. A name in the lounge that has no free spot next to its figure
is not drawn. -
Your office no longer takes the whole width when your projects are waiting on you. With
several projects shrunk to small rooms, the office could stretch across most of the window: a
long empty rug with the waiting sessions along its edges. The office is now only as wide as its
sofas need. The extra width goes to the project rooms, so the small rooms stand in one row, and
the lounge below gets any height left over. -
A subagent keeps its number when DeckHQ restarts. Subagent numbers were kept in memory, so
restarting DeckHQ after some subagents had finished could renumber the ones still running.
Each number is now saved in~/.deckhq/state.jsonwith the other names and numbers, so a
subagent keeps it across restarts, and a new subagent takes the next number its parent has not
used. Only the most recent 64 numbers per session are remembered for subagents that have
finished, so the file does not grow with every subagent ever run.
Testing
- The look import and export tests touch nothing outside the test. Once in a full run,
look-io.test.mjspassed every test and still exited with a failure, with no message. Its
command-line tests now replace every connection, file and output with a stand-in, and a check
at the end fails with a name if anything the tests started is still running.
v1.6.1
Highlights
A patch for what the first real floor showed. Working subagents were drawn beside a waiting parent
in your office; they now sit at the desks in their project room. On a busy floor, names and room
plate lines no longer vanish, and the building fills your window instead of leaving dark bands.
Subagents in worktrees form one crew, "at desk" counts only the sessions at desks, a subagent keeps
its name, and a finished session stays still.
Fixed
- Working subagents sit at the desks in their project room, not in your office. With several
sessions running, the desks could be empty and everyone shown working in the office. Subagents
were placed beside their parent session wherever it was, so when the parent finished its turn and
sat on the office sofa to wait for review, its thirteen still-working subagents stood round the
sofa. Each session is now placed by its own state. A working subagent takes a desk in its
parent's project room: beside the parent's desk when the parent is at one, and its own desk when
it is not. Three or more work in the usual arc, cabled to the room's first free desk, with the
parent's name on that desk and the+Nchip beside it. A subagent that has finished rests in the
lounge, and one that needs your input waits in your office. A project with a working session in
it always has a room, even when that session is a subagent running in a worktree with no session
of its own. A benched session stays in the lounge even when it is working again, because the
bench is yours to lift. - Subagents running in git worktrees form one crew. A subagent started in its own worktree
reports that worktree as its project, so five subagents of one session could be five crews of one
and the arc never formed. They are now grouped under the parent's project, and they still share
one room when the parent is not on the floor. - "At desk" counts the sessions at desks. The header counted every subagent as at a desk,
including finished ones and ones shown in your office. It now counts exactly the working and
stalled sessions the floor seats at a desk, subagents included, and never a finished, benched or
waiting one. - A subagent keeps its name. Subagent names were numbered by position among the ones running,
so when one finished, the others after it were renamed and a name you had just read pointed at a
different subagent. Each subagent is now numbered once, when it first appears, and keeps that
number. - The crew chip counts one crew. With reduced motion on, the chip counted working subagents
among the twelve drawn but divided by the whole crew, so it read "6/13 working" while seven
were. Both numbers are now over the whole crew, and+Nis only the subagents not drawn. - Source files no longer contain raw NUL bytes. Four files used one as a separator, which made
search tools treat them as binary. They use an escape now, and a test keeps it that way. - A busy floor in a laptop-sized window keeps its names and its counts. With about 150 sessions
in a window around 1400 x 800, the floor dropped to its lowest level of detail and stopped drawing
every name, every room'sN need youline, and the cables and+Nchip of a subagent crew.
Detail is now decided by how tall a person is drawn, and the smallest people only lose their
outline, chest mark and far arm. Names, theneed youline, cables and the+Nchip are drawn at
every size. A room plate that is short on space sets its lines smaller before it drops one, drops
the "doing" line before today's tokens, and never drops theneed youline. When the plate is too
narrow for that line it shortens to the dot and the number. - Names no longer land on room plates, people or each other. Names under the bottom row of your
office were drawn over the Lounge plate, and a crew of subagents printed the same type five times
on top of itself. Room plates now count as obstacles. A name that has no room below its person
moves to the side, or above the person's head. A crew shows each type once, with a count, such as
general-purpose ×5. - Finished sessions sit still. A session that has ended used to keep bobbing and blinking in the
lounge after it powered down. It now powers down once and stays still. - The office fills your window. On a wide window the building used to stop short and leave
dark ground down both sides, a quarter of the width on a busy floor, or above and below it when
the floor was laid in two rows. The building is now the shape of the window, so it fills it edge
to edge. The project rooms take the extra width as open floor round their desks, which stay where
they were. The lounge can widen and come down to meet them, and the reception grows its waiting
area. A one-room floor on a very wide or very tall window can still leave some ground, rather
than turn its one room into a hall. - No empty strip under the project rooms. When the lounge was taller than the rows of rooms
beside it, the difference was left as a bare strip of floor under the rooms. The rows and the
lounge now end on the same line: the rooms grow a little deeper, move into another row, or the
lounge is laid wider and shorter, whichever leaves the least of your window unused.
v1.6.0
Highlights
Studio is complete, from an idea to tracked work. Plan, hire a role, and move its cards across a
six-column board, from the keyboard if you like. A role hands its work back in a file you accept
or bounce; each card shows the tokens and time it spent; a regular pass flags drift; and a card
over its budget is blocked. The robots sit — at desks, on sofas, cross-legged with laptops. The
board fits any window, the floor fills the window again, and Linux screenshots are now checked too.
Added
-
The Studio board. A project with Studio on now has its cards as a board, beside the floor:
six columns — Backlog, Ready, In progress, Review, Done, Blocked — with each card showing its
title, who it is assigned to and that person's own robot, how many acceptance criteria it has,
its budget and any flags raised against it.⌘K→ Studio: board opens it, and so does the
board control besideboard.jsonin the panel.Esc, the ✕ and Back to floor all close
it, and closing it selects the assignee of the last card you clicked, so you land on that desk.Underneath the columns is a real table of the same cards in the same order, so a screen
reader gets the whole board rather than a pile of boxes.Every card is reachable and every move is performable from the keyboard. Tab walks the cards;
[and]— or the left and right arrows — move the focused card one column, and say where it
went;Enteropens it for editing. Dragging does the same thing. A move you make is shown
immediately and, if DeckHQ refuses it, the card goes back where it was and you are told why in
DeckHQ's own words rather than left looking at a card that silently moved back.A card's column stays yours. A session ending, a hook arriving and a scan completing move no
card — they flag it, and you move it. -
A card can start the work. Move a card into Ready and the role it is assigned to gets it:
if that role has no session yet, it is hired with this card as its brief; if it already has one,
the card is sent as the next thing to do. A card with nobody on it asks who, and never
guesses — nothing is started until you say. -
Cards are written from the board. New card, or Enter on one you have, opens an editor for the
title, the acceptance criteria, the milestone, the assignee and the budget. Anything DeckHQ
refuses is shown beside the field it is about, with what you typed still in it. -
The handover, and the review gate. A hired role's brief now carries one instruction: when it
believes a card is done, it writes.deckhq/studio/handovers/<cardId>.mdwith what changed, the
tests it ran and their real counts, open questions and the next step. DeckHQ watches that folder.
When a handover lands, the card is flagged and never moved — the flag shows as a chip on the
board — and the session's review card shows the handover above what it said, next to the diff of
its own worktree, so you can read what it claims beside what it actually changed.Two answers, and they are yours: Accept handover, where you name the column the card moves to
— Review or Done — or Bounce, with a note. A bounce leaves the card where it is and the note
arrives in that role's next brief, so it comes back knowing why.Test counts are quoted, never believed. The panel says "the handover says 41 passed" and
attributes it; DeckHQ runs nothing to check it and never prints the figure as its own. A handover
that leaves a section out is reported as missing rather than filled in, and a handover whose
filename matches no card is shown unattached rather than quietly dropped. -
Tracking, on every card. Each card on the board now shows how many tokens its session spent
while the card was in progress, how long it spent in progress, and the tests its handover says it
ran, quoted as the handover's own sentence. Every figure comes from a file you can open — your
ledger, the card's own record of when it was moved, the handover — and a figure with nothing
behind it saysno data, never zero. With Show cost on, a card also shows its list-price
estimate with the date of the rate card, and a model the rate card cannot price showsno rate
instead of a number. -
Milestones and the burn-down. Above the columns, one line per milestone: how many of its
acceptance criteria are ticked and how many of its cards are left. The ticks are yours — the card
editor has a checklist of the card's criteria — and nothing DeckHQ observes ever ticks one. -
The PM pass. Every 30 minutes, and whenever you ask, the planner is handed the blueprint, the
board and the handovers since the last pass, and asked what has drifted. What it says appears as
flags on the cards and in the planner's review card. A flag never moves a card, reassigns a
role or stops a session; what to do about it is your call. -
The budget stop. When a card in progress runs past its budget — tokens or minutes, whichever
comes first — DeckHQ moves it to Blocked, stops sending that role's session any more work
(and says which card and which budget when you try), and sends the session one message asking
it to stop and write its handover. DeckHQ does not kill the session: it did not start the
terminal it runs in and it cannot promise to stop it, so it does not claim to. Move the card out
of Blocked and sending works again — raise its budget first, or the next check stops it again. This is the only time DeckHQ itself
moves a card, and Blocked is the only place it can move one to.
Testing
- The Linux goldens are baked on Linux, by CI, and committed by a person.
npm run goldens
only writes the platform it runs on, so the Linux set could only be baked on a Linux machine, and
until this releasetest/goldens/linux/was empty and CI'sgoldensjob reported every capture
as not yet baked. A new manual workflow, Goldens bake (.github/workflows/goldens-bake.yml,
optionalpopulationsinput), runs the bake onubuntu-latestwith Node 22 and the runner's own
Chrome, prints one line per capture, and uploadstest/goldens/linux/asgoldens-linux-<sha>
for 7 days. It has only the default read token and never pushes. The Linux set now holds all 18
captures, baked by that workflow and committed after a look.
node scripts/goldens-import.mjs <dir-or-zip>puts a downloaded artifact into
test/goldens/linux/. Every file has to be<capture>.pngfor a capture that
node scripts/goldens.mjs --list(new) names, and has to be a PNG, or the whole import is
refused and nothing is placed. It reads the artifact zip without a dependency. An empty input
exits 2. CONTRIBUTING.md has the four steps. - A release refuses to ship with a gap in a Linux set that exists.
publish.ymlgains a
goldensjob, andpublishnow needs it. It runs with--strictwhentest/goldens/linux/holds
at least one PNG, and without it when the directory has none.--stricton its own would have
refused 1.4.0 and 1.5.0, which were both tagged with an empty Linux set. Pushes and pull
requests stay non-strict.test/unit/goldens-import.test.mjsholds the importer and the shape
of both workflows (13 tests).
Changed
-
The board fits the window. All six columns are on screen at once, with the panel open or
shut — the board gives the panel its room and arranges itself in what is left, and it never
scrolls sideways. Where six side by side will not fit, it becomes two rows of three; in a narrow
space (under 900 px) it shows one column at a time, with a row of buttons naming all six and how
many cards each holds — tap one to see it, or drag a card onto one to move it there. An empty
column is a thin strip with its name on its side, and opens when you point at it or drag a card
over it. Column names stay in view as you scroll. A card is four short lines: its title, who has
it, one row of chips, and one line of figures —400k tok · 12 min · says 43 passed— or a
singleno datawhen there are none yet. The project's path shows its last two folders (point
at it for the whole path), and the how-to line is behind a ? beside New card. -
The robots sit down. Until now every figure on the floor stood, including the ones at a
desk, on a sofa and in a crew. A session at its desk now sits at the chair with its hands on the
keys; a session waiting in Your Office, and a benched one on a lounge sofa or at the board-game
table, sits back on the cushions with its legs out; and a crew of juniors sits cross-legged on
the floor with each laptop on its knees — the lid open while that junior is writing and shut once
it has stopped, exactly as the floor laptop did, and the cable now runs into it. Anyone walking,
queueing, or standing beside a parent's desk stays on their feet.Nothing you read moved. Each figure's name, halo, shadow and click target sit where they did,
under its feet; only the body above them is lower. A raised hand stays exactly where it was, so
seated it clears the robot's head by more than it did standing, at every zoom. The typing, the
wave, the page flip and the stall still animate on a seated robot, and a seated robot drawn small
simplifies to one shorter shape rather than to a smudge of legs.
Fixed
- The floor fills the window again when it has five or six busy projects. Such a floor could be
laid as one long row of rooms with the lounge underneath, a building much wider than the window,
so it was drawn with a dark band above it and another below — on the 1600 × 1000 demo floor the
building used rows 206–922 of 1000. When one way of laying the floor fits the window and the
other does not, the two are now compared by how much of the whole window each leaves unused,
rather than by how much of its own rooms' side is bare. The demo floor now us...
v1.5.0
Highlights
Studio can hire. Ask for a role and DeckHQ makes it a workspace of its own, writes it a brief,
and starts a real session there — and it says plainly what it will not do. Sessions and worktrees
are matched by the folder they are in rather than by how the folder is spelt, so a Windows path
that has two names is recognised either way. The website and the README describe the product and
nothing else: the planning documents have moved to a private repository.
Added
- Hire — WP-68. Studio's roster now starts people.
POST /api/studio/hiretakes{ role }or
{ roles: […] }and, per role, does four things:git worktree add <state>/worktrees/<project>-<role> -b studio/<role>, an argv array with no shell anywhere in it; a brief file under
.deckhq/studio/briefs/<role>.md, which is never regenerated under a running session and never
overwritten when the user has edited it (the regeneration goes beside it as<role>.next.md); a
session started in that worktree, under that brief, where the brief's path is on the command
line and the brief's body never is; androster.roles[i].agentIdwritten down when the ORDINARY
scan finds the session — no private session list, matched by the worktree directory it is running
in. The command palette carries oneStudio: hire <role>row per role that is not already at a
desk, and the panel's Studio block grows a line per role beneath the three files: not hired, hired
with its id, hired-unverified, or the reason the name cannot be hired. Firing leaves the worktree
and the process alone, and says so.docs/DEVIATIONS.md§188.
Changed
-
Planning documents moved to a private repository. The requirements, architecture,
specifications, plan, deviations and designer mockups are no longer part of this repository;
the source, its tests, the manual and the adapter contract stay public and MIT. -
The website is the product now, and the blueprint is not on it — WP-95a. The owner: "The
website is purely public marketing and PR. Do not put requirements and architecture docs there.
We only put the product public and its features." The site was eleven pages and 171 generated
ones — the whole decision log, an entry per page — plus a Docs page linking every document in
docs/. It is nine marketing pages now: Home, Features, Look, Characters, Studio, Install, FAQ,
Privacy and security (new, in plain words, with the route for reporting a vulnerability) and
Changelog (new, generated from theHighlightsparagraph of each release and nothing under
it). The bar is six links with no "More" disclosure; the footer is GitHub, npm, the licence and
privacy. A gate insite/build.mjsrefuses to write any page carryingdocs/plan,DEVIATIONS,
00-REQUIREMENTS,02-ARCHITECTURE,ARCHITECTURE-AUDIT,STUDIO-DESIGN,RELAY-DESIGN, a
work-package id or a section number, and the same list runs overREADME.md, whose Docs table
now lists only the guide, the changelog, the security policy, the licence andADAPTERS.md.
docs/DEVIATIONS.md§189.
Fixed
-
A session is recognised by its directory, not by how the directory was spelt. DeckHQ finds
the session it has just started by the folder it started it in, and compared two spellings of
that folder as strings. Where a folder has two names — a symlink (every macOS temp directory), a
junction, a Windows short name — the two never matched: a name chosen with+was never applied,
a Studio planner and a hired role were never recognised, and hiring a role a second time was
refused as "already exists and is not a worktree of this repository" by the hire that made
it. All four comparisons are by directory now, in one place,src/core/same-path.mjs. A session
that reports no folder at all no longer matches the folder DeckHQ itself was started in. -
The project hub's footer survives a tab press. It was appended to
#main, and every tab
switch rewritesmain.innerHTML— so the footer was there until the reader pressed a second tab
and then gone for good. It is inserted after#mainnow.docs/DEVIATIONS.md§190.2. -
The project hub's tab bar is bound once, not once per render.
renderChrome()attached the
bar's click listener and the listener callsrenderChrome(), so the nth press ran the handler n
times and re-rendered the page n times over. The delegated listener moved to start-up; the bar's
element is never replaced, only itsinnerHTML. §190.3. -
The site no longer says three shipped features are unbuilt — WP-95a. Look, agent size and the
crew landed in 1.4.0, and Look and Characters still carried "None of it is built" over four
mockups of them. Those pages describe what you can go and use, and the site publishes no mockup
at all.
Testing
scripts/dashboard/template.mjsis back under the 900-line ceiling, with no exemption row.
Prettier's reformatting of the one long template string had put it at 1,109 lines. The stylesheet
moved verbatim totemplate-css.mjs(258 lines) and the client script totemplate-script.mjs
(756 lines, asclientScript(data)because the footer interpolates two links);template.mjs
keeps the helpers, the markup and the assembly at 109. Proved a move and not a rewrite: the built
page is byte-identical before and after, bycmp. §190.1.test/integration/studio-hire.test.mjs's three-role acceptance no longer fails under load.
Its roster poll ran a fixed five seconds and asked for a scan only every tenth round, so a
loaded machine could finish the loop before the third role'sagentIdhad been recorded. Every
round now triggers a scan and waits for it, the loop leaves the moment all three ids are on disk,
and the 45-second bound is a failure path — reached, it reports the rounds, the elapsed time and
the roster. The fake CLI fixturefsyncs its transcript before exiting. Ten consecutive runs
green with a fullnpm testrunning beside them. §190.4.
Refused, and why
- Everything a Hire can refuse is refused before the first worktree exists. No consent, an
unknown runtime, a runtime with noopenNewSession(refused by name, never silently skipped),
a role that is not inroster.json, a role name carrying a space, a quote, a;, a leading dash
or a path separator — git is never asked to escape a name, and a seventh role in one press is
refused with the count, because "too many" is not a number anybody can act on. A failure after
that point is reported per role rather than rolled back: a worktree that exists is a fact.
Known gaps
- Hired roles have not been measured doing work. The one real run of WP-68 made two worktrees,
two briefs and two realclaudesessions on the reference machine, and the ordinary scan found
both and wrote both ids intoroster.json— but the stored login on that machine is expired
(OAuth session expired and could not be refreshed), so neither session got past authentication.
§188.1 records it verbatim. Oneclaude loginis what is owed. - A Codex, Gemini CLI or OpenCode role is hired unverified. No terminal has ever been opened
on those three by this project. They are hired, the floor degrades for them exactly as it already
does, and both the response and the panel's roster line say so rather than pretending. - There is no roster screen. Roles are added, renamed and rewritten by editing
roster.json,
which the panel opens in your editor, and the daemon validates with the path and the line of
anything it refuses. The board tab is WP-69 and the handover is WP-70.
v1.4.0
Highlights
DeckHQ opens as an app, and one line installs it on a machine with no Node — or a file you download
and run. Every agent is a robot that walks in, sits, types and leaves. The floor is a drawn
interior, and Look chooses its material, its colour and how big the people are. Seating holds: the
same session returns to the same chair. A session running three or more sub-agents grows a crew
around its desk, cabled to it. Counters read tokens, not dollars. Every room carries a plate. A
resume chain is one agent rather than six. Six hundred names. Studio keeps a store and writes a
plan; hiring has not landed. And a pass over the architecture.
Added
- The crew — WP-89. The owner: "If a chat session fires 3+ agents … the GUI launches all those
sub-agents (smaller in size), connected by cables to the main chat session agent, surrounding it,
sat on the floor with their own laptops, feeding data by cables." Three or more live sub-agents on
a session at a desk now turn its desk into a formation: the juniors at 0.65 of the parent,
seated in an arc of radius 4.2 U in front of it (a crew of twelve opens to 10.3 U), a laptop each,
and one axis-aligned cable per junior running with two bends — round the furniture, never through
it — to a port on the desk's front edge. A cable pulses junior→parent, at 1, 2 or 4 pulses a
loop, only while that junior's transcript was observed to grow inside the last minute; a junior
whose file has stopped keeps its cable and it goes grey, and its laptop folds. Twelve are drawn and
the rest are a+Nchip, with every one of them still in the panel and in the deck, where a crew is
one expandable row under its parent rather than N sibling rows. The room grows for it: a crew is
contents, so it bids for the arc's floor instead of for chairs nobody sits in. One softdoorcue
when a crew forms — never per junior and never per pulse. Two new goldens,crewand
crew@reduced; the other fourteen are unchanged to the pixel.docs/DEVIATIONS.md§178. - The
wf_<id>a workflow's transcripts have always carried — WP-89. A multi-agent workflow's
juniors live one level deeper, undersubagents/workflows/, and the floor walked past that segment
and threw it away. It is kept now, as one field and no extra I/O, so four juniors of one workflow
can be told from four independentTaskcalls. - The floor is configurable, and two rugs that had never been measured are fixed — WP-88a. The
owner: "I still don't see any option to configure the overall GUI graphics: office floor carpet
and colours, rugs, tables, chairs, sofa, plants, etc. We do not flood everything with too many
options; the interior designer carefully crafts options that can be mixed and matched." There are
now nine floor materials over four zones — herringbone oak, wide ash boards, terrazzo, polished
concrete, wool broadloom, loop-pile tile, ceramic tile, poured screed and cork — six colour
schemes, three furniture sets, two rugs in three tones and two patterns, three plant families,
three planting and three prop densities, and a four-bay lounge kit: 52 options over ten
pickers, with six presets. The default, Studio oak, is the floor exactly as it shipped, byte
for byte. No UI yet — this package is the model, the derivation and the guards; the Look
section is WP-88b.docs/DEVIATIONS.md§175. - The Look section, where those 52 options are actually chosen — WP-88b.
⌘K→ Settings →
Look: six preset cards, each a real floor thumbnail painted by the floor painter itself; a
live preview that repaints as you change anything, with the zone edges, both rug ratios and the
worst floor ink measured underneath it; and a row per picker, every chip a swatch of the material
it stands for rather than a colour square. A combination the guards refuse shows the reason in
its own row beside the control that caused it and changes nothing at all — not the floor, not
the control, and nothing is posted. Nine more palette rows (Look: Night lab,Look: reset,
Look: export,Look: import), Export and Import buttons on the section, and every control
operable from the keyboard alone: one Tab stop per picker, arrows inside it.
docs/DEVIATIONS.md§176. - Agent size, and the furniture follows the people — WP-88c. The owner: "the user can set the
size of agents compared to screen; someone with 100 agents wants them smaller, someone with 5–10
wants them bigger so they are not lost; accordingly the size of table, chair, sofa, everything
adjusts automatically." Small, medium, large or auto, in the Look section and in
the palette (Agents: large). Everything a body sets moves with it — seats, the pitch between two
people, desk and sofa depth, the rugs, the planting, the figure's own chrome — and everything the
building sets does not: the corridors, the room padding, the plate band, the parquet, and every
label, which stays exactly the size it was. Rooms grow and shrink with their contents, so a floor
of five people fills the window and a floor of a hundred still fits with every body readable.
Auto reads how many people are actually on the floor — large under ten, small over forty —
and holds its choice two either side of each threshold so one session starting does not re-plan
the building. Medium is the floor as it shipped, byte for byte.?scale=smallpaints one tab.
docs/DEVIATIONS.md§177. - A look is a file you own, and unlike a layout it is anonymous — WP-88a.
deckhq look export > my-floor.json,deckhq look import my-floor.json,deckhq look presets, plusGET/POST /api/lookand?look=night-labto paint one tab. A look names no project, no path and no
session, so it is a file you can post. A malformed one is refused whole with its reason, and so is
a legal one whose combination the contrast guards will not paint.
Fixed — floor
- The wool rug was invisible on night shift and the task rug shouted on blueprint — WP-88a. Both
derived through a constant mix weight while the gap between the carpet and the floor under the rug
is not constant across themes, so nothing measured them: the wool rug came out at 1.00:1 on
night shift and the task rug at 1.69:1 on blueprint with every contrast test green. Both are
now a bisection on the ratio, held to[1.06, 1.45]— measured after: 1.23 / 1.16 / 1.16 and
1.32 / 1.42 / 1.42. The default floor is unchanged to the channel: all nine default-theme goldens
are at 0 px moved. The two themed captures were rebaked, and the moved pixels in both are only
the rugs.test/goldens/linux/demo@night-shift.pnganddemo@blueprint.pngare owed the same
rebake on Linux. - A room plate ranks its lines, and the one you might act on is the biggest — WP-81. The owner:
"Make sure the calculations on the whiteboard of the project rooms are right and informative and
not just there for the sake of it. […] how to make it easy to read at a glance in a split second
so the user does not have to spend effort reading it." The plate saidorbital-api · 7 sessions · 580k tok · 2 need youovertoday 5.8M tok · with cache— three numbers in one size, of which
exactly one is ever acted on. It now readsorbital-apiover● 2 need you · oldest 1d 2hoverElif · Bash npm testovertoday 5.8M tok · with cache, in four sizes and four
inks, largest first. When nothing needs you the big line says what the room IS doing —3 working,
orquiet— so it is never a zero you have to stop on.docs/DEVIATIONS.md§173. - The plate says what each agent is doing right now — WP-81. Up to two live
currentTool
summaries, from the same field the side panel'sdoing:line and the floor's thought bubble read,
with the same MCP substitution (mcp__gmail__sendreadsGmail · sendon all three). An agent
with no tool open contributes no entry and none is invented for it. - Your Office, the Lounge and a pinned room follow the same grammar — WP-81.
2 waiting · oldest 3h,5 resting,1 session · pinned. The office saysnobody waitingwhere it used to
say0 waiting. A pinned room keeps its session count because with nothing running it is the
only fact it has. - The site shows the product as it is now, and weighs a third of what it did — WP-94b. The
owner, after reading the site: "The homepage visuals are outdated, the UI changed many times.
Images load slowly and the Look page images do not load." Nothing 404s; Features weighed 6.3 MB
and Look 4.0 MB. Every image now declares the role it plays, and the role fixes the width it is
served at and the weight it may reach (hero1100 px / 600 KB,crop680 px / 250 KB,gif
2.5 MB), with a whole-page cap of 2 MB on Home and 3 MB elsewhere. Both are enforced in
site/build.mjsand again intest/unit/site.test.mjs. Features is 1.4 MB, Look 1.6 MB,
Home 1.5 MB, Characters 0.6 MB. scripts/site-assets.mjsandsite/assets.json— the site's pictures, declared and taken from
the running product. Each asset names a fixture population, a viewport, the keys or clicks that
reach the state, a crop rectangle in CSS pixels and the width it is written at; the script boots
one demo daemon per picture on a port the OS chooses withDECKHQ_NOWpinned, takes the shot, and
takes it down. Fourteen pictures: nine crops of the one thing their words are about (the waiting
strip, a room plate, Your Office, a lounge bay, the idle popover, the deck's Queue and Usage tabs,
the panel on a review, and a permission request raised through the real hook endpoint), a themed
room plate in each of the other two themes, and four GIFs at 25 fps against the old hero's 10:
the whole floor, typing and thinking, the lounge, and an agent walking to Your Office with its
hand up. A picture a fixture c...
v1.3.0
Highlights
The panel became a review surface: what the agent said, rendered as markdown, what changed on
disk, and three weighted actions. Replies stream in as they are written, and a permission prompt
raised in the terminal can be answered — Allow or Deny — from the panel; both were run live
against Claude Code on 4 September 2026. The floor is generated from the people on it rather than
the repositories on disk: a room exists because somebody is in it. Every agent arrives with a
face, a name and a rarity — most are common, about one in a hundred legendary. A queue strip sits
under the header, Tab swaps the floor for the same queue as a table, and notifications reach a
closed tab. An append-only event ledger records what the floor did; deckhq stats, the day's
postcard and a weekly Wrapped all read it, computed on the machine and sent nowhere. DeckHQ
installs as a Claude Code plugin, ships a VS Code extension, and prints both a status line and a
terminal deck. Three floor themes are free; the Supporter pack adds more themes and avatars and
takes nothing away. The Codex adapter is verified against real Codex sessions; Gemini CLI and
OpenCode remain unverified. Node 18 or newer, zero dependencies, CI green on Linux, macOS and
Windows.
Added
- The Supporter pack: more themes and avatars, and nothing else. A pack is one signed JSON
file.deckhq pack install <file>copies it into~/.deckhq/packs/<name>/pack.jsonand a
running DeckHQ picks it up within a second, no restart. It carries floor themes and avatar sets;
there is no key in its format for a tier, a licence, an expiry or a feature flag, and one that
tried to carry a key like that is refused rather than ignored.⌘K→ Settings → Floor now
shows the pack's themes beside the shipped ones, and an Avatars row appears only when a pack
actually offers a set — an install with no pack has no row and no advertisement. Choosing "as
they come" puts every face back exactly, and nothing changes because a file appeared in a
directory: the set is a setting, empty by default, because a face is the one thing in this
product that must never change on its own.docs/DEVIATIONS.md§129. deckhq pack—build,verify,install,list,remove. No account, no licence check,
no activation, no update check and no network call anywhere in it; the only question DeckHQ ever
asks about a pack is whether it was signed by the Ed25519 publisher key compiled into the build,
and it answers that locally withnode:cryptoover the pack's canonical JSON. An unsigned pack,
one signed by a key this build does not know, or one edited after signing is refused whole
with its reason and nothing in it loads. A bad ITEM is refused alone: a theme that fails the
contrast gate is dropped with the measurement and the rest of the pack still installs, so one
bad colour cannot cost a customer the pack they paid for.deckhq pack verifyprints what is
inside one before you install it.- A pack cannot lower a bar. Every theme in a pack goes through the same
validateThemeand
the sameassertThemeContrasta theme DeckHQ ships does — this is the doordocs/DEVIATIONS.md
§125.9 left closed, opened exactly this far and no further. Every avatar colour is held to the
same ≥ 70 sRGB distance from every state colour thatpublic/render/palette.jsholds its own
tables to, so an agent can never wear a state, and a pale "jacket" that would read as the torso
under it is refused with its luminance.packs/supporter-sample/is a real pack with two extra
themes — warehouse (poured concrete and steel racking) and garden (a conservatory in
leaf) — plus one avatar set, committed as reviewable unsigned source beside the signed artifact
and a build script. - Floor replay: watch yesterday. Free.
⌘K→ "Watch yesterday" scrubs the floor through a day
of your own event ledger at 60×, so a working day is about twenty minutes and dragging the bar
is instant. Each frame isreconstructQueue(records, t)— the needs-you queue exactly as the
machine wrote it down, not a re-derivation — and frames land on changes rather than on a clock,
so a quiet hour is one frame and a busy day is a few dozen. It is read-only: there is no
writer anywhere in the path, no acknowledgement moves, the ledger file's modification time does
not change, and anINVARIANT:test drives a whole day to the end and asserts all three. The
deck, the panel, the header count and the notifications stay live the whole time; only the
canvas is looking at yesterday. The plan listed replay in the Supporter pack; it ships free,
because a feature that reads your own ledger cannot be sold without becoming a gate on data you
already own. §129. - A rate-card editor in the settings sheet. Also free. Settings → Data now edits
~/.deckhq/rates.json— your own prices per million tokens, merged over the shipped table one
model at a time, with the shipped model ids offered as completions and the cache columns showing
the multiplier that will be used if you leave them empty. A malformed row is refused whole with
the row named and nothing is written; clearing every row removes the file rather than leaving an
empty one behind that would claim the table is overridden for ever. There is no "fetch the
latest prices" button and there will not be one. The plan listed this in the pack too; it ships
free, because the file has existed since WP-26 and anybody can edit it in a text editor — and
because "cost is an estimate, never a bill" only holds if the person looking at a wrong number
can correct it. §129. GET /api/packs,GET /api/replay/days,GET /api/replay?day=, and
GET/POST /api/rates. All loopback, all local, none of them egress. The replay routes are
two GETs and there is no writer among them, asserted.- Two more runtimes: Gemini CLI and OpenCode. Four now, on one floor, with correct attribution
and no shared state: disabling or removing any one leaves the others fully working, and a runtime
that is not installed contributes nothing and reports itself cleanly rather than erroring.
deckhq doctorgrew two rows withoutsrc/cli/doctor.mjschanging at all, which is the property
the adapter interface exists for and there is now a test asserting it against the real registry.
Gemini CLI is read from its JSONL session files under~/.gemini/tmp/<project>/chats/, including
juniors; OpenCode through its own JSON-emitting commands —opencode db,session listand
export— because since v1.2.0 it keeps everything in a SQLite database, and DeckHQ has no
dependencies and would not guess at a byte layout when the runtime ships a supported interface.
Resume, new session and send are wired for both, as argv arrays with no shell anywhere.
Both are unverified — see Known gaps.docs/DEVIATIONS.md§123. docs/ADAPTERS.md— add a runtime without asking us. TheRuntimeAdaptercontract with what
each method owes you, the seven stability rules, a worked example that adds a fictional runtime
end to end, the fixture convention, the checklist, and the honesty rule: an adapter is unverified
until it has been run against real data and has to say so in three places. Adding a runtime is
three files in one directory plus one line in the registry and one union member inRuntimeId—
nothing else in the product names a runtime.- Lights out: one card at the end of the day. At 22:00 — or as soon as the last live session
ends, if the evening is already under way — the floor dims to night and a single card appears:
"Friday. 40 turns across 6 rooms.orbital-apishipped 6,checkout-flowwaited 4h 3m. 6
agents still up. ≈ $39.46 list price, rate card 2026-09-04. Longest wait today: 1d 2h → still
standing." Every number is a replay of the event ledger. It appears once per local day,
Escape or a click dismisses it,Ssaves it as a PNG with a small photograph of the floor it is
about, and it never comes back on its own — Stardew Valley's day-end save, not a summons. The
hour issettings.lightsOutHourin the settings sheet's Floor section, and⌘K→ "Today's
card" shows it again without spending the day's. Nothing in it addresses you, and that is a test
rather than a convention: the copy generator is driven over synthetic ledgers and every string
literal in the file is scanned for a second person.docs/DEVIATIONS.md§118. - Wrapped, weekly and annual. Monday morning, and from 1 December the year so far. Turns per
room, tokens, an estimated spend that names its dated rate card, the longest wait and whether it
fell against the week before, the room that never slept, the session sent the most messages, the
busiest hour — and the count of "You're absolutely right" across the week's assistant turns.
Every line carries the window it was computed over, and a ledger younger than the window says
where it actually starts instead of claiming a week it did not live through. Generated on the
machine, from the machine: no email, no server, no account, no request of any kind leaves the
box. One key puts it on the clipboard as a PNG, andShift+Sswaps every project name for its
MK tag first.⌘K→ "Wrapped".docs/DEVIATIONS.md§119. GET /api/wrapped?kind=week|annual, and awindowfield onGET /api/stats— what
happened between two timestamps, room by room, from one walk over the ledger. Both cards read the
same function, so a day and a week cannot disagree about what a turn is.deckhq doctor --shareprints the report as a fenced block you can paste anywhere. The same
numbers as the report — transcripts, running now, on the floor, waiting on you, hooks, egress —
with everything that belongs to you taken out: no paths, no project names, no machine name, no
hook port, no free-text error message...
v1.2.0 — installable
The release that can actually be installed. 1.1.0 called itself the first public release and was
then never pushed to the registry, so npx deckhq — the README's only install instruction —
returned E404 for the whole of its life. Every other improvement in this project was academic
while that was true, so this release is mostly the unglamorous work of making one command work.
Packaging
- The package is publishable without a private-by-default accident.
publishConfig.accessis
nowpublic. A scoped or first-time publish that omits it fails at the registry, or worse
succeeds as a private package on an account that has no private plan. - A broken build can no longer reach the registry.
prepublishOnlyrunsnpm run lintand
npm testbefore anything is uploaded. Publishing is the one operation in this project that
cannot be undone — npm unpublish is time-boxed and the version number is burned either way — so
it is the one that gets the gate. - The description is the pitch again. It used to end with "(Codex adapter included but
unverified.)", which is honest and belongs in the README's Honest limits, where it still is. The
description is the single line that appears in npm search results next to a dozen competitors;
spending its last forty characters on a caveat about a secondary adapter was a bad trade. The
caveat has not been softened, only moved. control-planedropped from the keywords. DeckHQ does not orchestrate anything and should not
turn up when someone searches for a tool that does.claude,local-firstandprivacyadded,
because those are what the intended user actually types.- A
fundingfield pointing at GitHub Sponsors, matching the new.github/FUNDING.yml. package-lock.jsonsaid1.0.0. It had not been regenerated for the 1.1.0 bump, so the one file
whose job is to describe exactly what gets installed was describing a version two releases old.
Now correct, and*.tgzis ignored so a straynpm packcannot commit a tarball of the package
into the package.
The tarball is 42 files and 225 kB: bin, src, public, the README and the licence. It grew by
three files because deckhq doctor added src/cli/. No state, no logs, no tests, no docs/, no
.claude/.
Repository
Everything a stranger looks for before they open a pull request, and none of which existed.
CONTRIBUTING.md, leading with the two things that get a change rejected regardless of how good
it is: the invariant indocs/01-PRODUCT.md§2, and network egress. Both were only written down
in the README's footer, where a contributor finds them after they have written the code.SECURITY.md, describing the actual model rather than a template one — loopback bind with no
--hostflag, why that is not sufficient on its own and what the CSRF guard adds, path-confined
static serving, argv-array spawns, conversation text rendered as text — plus a private route to
report something that is wrong with it.CODE_OF_CONDUCT.md(Contributor Covenant 2.1).- Issue forms for bugs and features, and a pull request template. The bug form asks for the output
ofdeckhq doctor, so an environment report arrives with the first message instead of after
three round trips. .github/FUNDING.yml.docs/plan/RELEASE-CHECKLIST.md, the ordered commands for cutting a release, written down
because the thing that went wrong with 1.1.0 was a step nobody had written down.
Added
deckhq doctor. One command that answers "what does DeckHQ actually know about this
machine": how many sessions are on disk, how many the runtime reports as running, whether hooks
are installed and — separately, which matters — whether they are being delivered, and whether
state can be written.--jsonfor scripting. The bug report form asks for its output, so an
environment report now arrives with the first message instead of after three round trips.deckhq doctor --capture-proofwrites a PNG comparing what the runtime reports against what
DeckHQ holds. It renders the number of finished sessions still waiting on you, which is the only
version of that comparison that survives a reader checking it — seedocs/DEVIATIONS.md§74.
Changed
- The interface chrome is cold now, and the floor reads as lit. The neutrals were tinted
toward the accent hue, which put warm chrome around a warm floor: herringbone, carpet and warm
light sitting on a ground of the same temperature, so the floor never looked illuminated, only
brown. The neutrals moved to a violet-blue bias, taking hue separation from the floor from about
66° to about 169°. The seven state colours are untouched — they are a measured contract with the
renderer, and the rule when something failed was that the ground moves, not the state colour.
Fixed
- The desktop archive flag was being written into cached session summaries. In memory this was
masked, because a fresh read re-applied the flag on every poll and only while that read kept
succeeding. It would not have stayed masked:archiveddriveslet_go, so a persisted copy
would have re-fired a deliberately rehired agent on every poll, for ever. The flag is now
stripped both when an entry is written and when one is read off disk, because a cache file can
arrive from a backup, another machine, or an older build. A cache hit carries noarchivedkey
at all rather thanarchived: false— the two mean different things to the registry, and
neither is a decision a cache is entitled to make. - Five interface surfaces set small text in a state or accent colour, all of them below the
4.5:1 floor the stylesheet's own header already required. The worst was the error toast at
2.39:1 — the surface that tells you a send has failed. Contrast is now asserted in the test
suite against every ground the text can actually land on, reading the literal values back out of
the stylesheet rather than a copy. deckhq doctoraborted with exit 127 after printing a correct report.process.exit()tore
down the event loop while a loopback socket was still closing. Worth recording how it survived:
364 tests passed against a binary that could not exit, because every one of them called the
function and asserted its return value and none spawned the command. A command's contract
includes how it ends.
Performance
- The summary cache persists across restarts, so a daemon start no longer re-parses every
transcript on disk. Measured on 66 real sessions across 307 MB of transcripts: a second start
falls from 780–854 ms to 59–90 ms. Cold start is unchanged; the only addition is one 62 KB
atomic write. - Only entries that are provably current are served. Painting a stale summary and reconciling
afterwards was specified, built, and rejected: a staleturnEndedreaches the code that writes
reviewSince, a user-owned field nothing observed is allowed to clear, and the likeliest reason
a transcript moved while the daemon was down is that you replied to it in a terminal. That would
have manufactured a review debt that then survives for ever.
Known gaps
Carried forward from docs/DEVIATIONS.md §8–9, unchanged by this release:
- Codex support is unverified. The adapter is written against documented rollout-file
conventions and has never run against real Codex data. openInTerminal()is verified on Windows only. The macOS and Linux paths are implemented and
reviewed but have not been run.