Greenpen · design commission from Khoa via Will · 31 Jul 2026

The Writers’ Room

Pack v2 — the IA changed. Khoa reviewed v1 against OwnerMind /inapp and redirected §9 twice on 31 July: the table form read as many rooms. The room is now one chronological lane per project, with a single focal seat at the top. Open the v2 room → — the pages below are v1 and several are superseded.

Every project can convene a staffed table: named agents with roles, temperaments and faces, running a task through the paces while you sleep. In the morning you get minutes, a row of notes to camera, a diff, and a tray of proposals that have not been applied to anything.

It lives as a drawer on the Studio you already have. The Studio stays the writing surface — the room comes to it.

Start here · v2 The lane is the room

One chronological lane per project. Focal seat at the top (default the Showrunner), other seats a switchable row beneath; tapping one filters and addresses without ever changing rooms. Sessions are collapsible segments, the paces shrink to a progress chip, and three things never scroll away.

v1 · superseded IA, live mechanics The table form

Superseded as an IA, but it is still where the gate tray and the continuity lane are designed in full — both carry over into v2 unchanged and the dock opens them.

The point of it The morning after

What you walk into: what stopped it, what needs you, the notes, the diff, the minutes.

v3 · the Story Department The Script Doctors

Six style seats bound to measured grammars — Greenpen’s sibling to Wideshot’s Fourth Unit. A doctor consults or operates: measured deltas for free, or a pass that rewrites your pages with the grammar embedded. Coverage worn openly, no author or title names anywhere.

Before it runs The brief

Task, boundaries, who sits in, rounds, budget. Boundaries are the product.

The people The roster

Seven seats designed in full, the persona-pack template, and the Tavus face direction.

Small screens Mobile

A bottom sheet with three snap points. Peek never closes, because a closed panel that stops telling you things is the failure mode.

What Khoa asked for, and where it is

1Drawer collapsed A 46px rail of seat faces with presence (idle / reading / writing / has-notes) and the waiting count. Tapping a face reopens onto that seat. Open →
2Drawer open — the table Seat cards with a stance chip and the latest note; tapping one opens full notes, the clip, the temperament brief and the credential. Open →
3The paces rail Eight ticks, the round counter, a loop marker on READ–NOTES–REVISE, and — for overnight — where it stopped and why. Open →
4The notes round Faces are play buttons on text cards, not video tiles. One sticky stage, so at most one moving image is ever on screen. A failed render leaves a complete note. Open →
5The gate Two lanes. Proposals carry per-seat provenance and commit the moment you tap them; reject captures its reason first. Continuity flags are a separate lane with Mark read / Resolve / Dismiss, and a badge saying how many still keep the room looping. Finish gate closes the pace once everything is decided. Open →
6Morning-after view One walk-in: what stopped it, the batch, the notes row, the diff, the minutes. Open →
7Session setup Task, canon-locked versus open, tone red lines, who sits in, rounds cap, per-seat budget, and the two ruleset switches. Open →
8Persona packs and the roster Six-field template, seven seats written out, sprite sheet, face direction. Open →
9Two-writer competing takes Routed into the Draft compare that already ships. The room adds one thing: each column is labelled with the seat that wrote it, and carries that seat stance. Open →
10Mobile Bottom sheet, three snap points, gate buttons under the thumb. Open →

What this is built on

Every value, colour and layout dimension is read from the shipped product rather than chosen. I did not get the staging demo gate, so this is grounded in source and in the running architecture — not in screenshots of the live app.

Taken fromWhat it gave
apps/web/components/fd-room.tsx The Studio shell: 248px drafts and scenes rail, the format tabs, the FD palette (#e9e9e9 #efefef #c4c4c4 #2f7be6), the review-hunk row with per-hunk accept and reject, compare mode and its four-colour legend, and the dock that already collapses with dockOpen.
apps/web/components/fd-agent-dock.tsx The seam. A 300px right dock with a role picker, run history carrying role chips, and a library-references block. The room becomes a sixth tab beside agent, memory, markup, insights, history — not a new panel.
apps/web/app/globals.css Warm Playbook: paper #F4EFE7, ink #221A14, accent #2D5BD0, Figtree, Newsreader, Courier Prime, 10px control radius, warm-tinted shadows.
docs/ROLE_AGENTS_SPEC.md The role registry the seats are built on, and the restrictions kept verbatim: editor never invents a scene, continuity never mutates.
docs/IDEA_PITCHER_SPEC.md The guest seat and its present-do-not-rank rule.
docs/WRITERS_ROOM_SPEC.md
branch will/writers-room-spec · PR #26
The paces, the seatNote artifact, the hard rules, and the Tavus phasing. Re-read from the branch at delivery rather than the scratchpad copy I was first given: that copy had moved under me (181 lines → 186). I diffed them — §3 roster, §4 paces, §5 hard rules, §6 Tavus and §9 UI brief are byte-identical, so nothing in this pack changes. The five new lines are the status header and §11 blockers.
The room is grey; the room drawer is warm paper. The Studio is a Final-Draft-faithful desktop surface and the rest of Greenpen is warm paper. Rather than invent a third palette I let the product identity into the one place in the Studio where people and agents talk. It also does something useful: the room reads as a different kind of place without a single new colour.

What the mechanics check changed

Will reviewed this against the spec and the shipped platform, and found one thing I had designed wrong. Both of my judgement calls survived; the gate did not.

Corrected · the gate

I designed an atomicity the platform does not have

My first gate had one Apply button that stayed disabled until every proposal was decided. That reads as a batch transaction. There isn’t one: approve_pending and reject_pending are individual calls that take effect when made, and there is no un-approve. Holding decisions in the UI and firing them at the end would lose them on a crash and let the queue move underneath.

So the gesture stays and its meaning changes: each decision commits on tap and the row locks; the end button is Finish gate, which completes the GATE pace rather than the writes. Partial triage is now first-class — decide 3 of 12, leave, come back. One consequence I had to design for: because commit is irreversible, reject captures its reason before the call, since reject_pending(reason) takes it as an argument and there is no later.

Sharpened · continuity

It is not an approval at all

I had continuity annotations as a row in the approval tray, with approving meaning read rather than fixed. Right instinct, wrong lane: annotations never touch the approval queue. I checked the shipped registry — resolve_annotation is kind:"action", requiresApproval:false.

They are now a visibly different group with a different verb (Continuity flags), and the word approve never appears on them. The source gave me one more than Will specified: three terminal states, not two — acknowledged, resolved, dismissed, with a resolution required for the last two. Dismiss earns its place: without it, a human who thinks a flag is wrong has no move but to leave it open, and an open blocking annotation keeps the room looping for ever. A badge now says exactly that.

Four judgement calls I made

These are decisions, not defaults. The first two were put to Will and he endorsed both as designed; the rest still stand open to you.

Call 1 · endorsed by Will

Stances are words, so I did not colour them like a traffic light

The obvious treatment is green ship it, amber another pass, red structural concern. I did not do that. Six coloured chips in a column reads as a leaderboard of seats — exactly the ranking the product law forbids, arriving through the palette instead of the text.

So colour marks what needs you, not what is good: only structural concern is coloured. The other two are neutral chips. You lose a little scanability and you lose the ability to read a ranking off the row, which I think is the right trade.

Call 2 · the notes round

Faces are buttons on text cards, and there is only ever one stage

A row of six talking heads is a video wall, and it also quietly inverts the rule that text is the source of record. So the note is a text card, the face on it is the play affordance, and every clip plays into one sticky stage at the top of the panel.

At most one moving image is on screen at any time, the notes stay readable underneath it, and a seat whose render failed simply has no play badge and a line saying the note is the record. Nothing is missing when video is missing.

Call 3 · the morning after

What needs you comes before what explains it

The commission lists minutes, notes, diff, batch. I put the approval batch second, straight after a single line saying what stopped the session — before the notes, the diff and the minutes.

At 8am the question is not “what happened”, it is “what is waiting on me”. The minutes are the best-written thing on the page and they are at the bottom, on purpose. Say the word and I will lead with them instead.

Call 4 · endorsed by Will

The competing-takes view is the shipped compare, not a new surface

Greenpen already has draft-versus-draft compare with a four-colour legend and a side-by-side mode. Building a second comparison surface for the room would give you two things that drift.

So the room routes into the existing one and contributes exactly one thing: each column is labelled with the seat that wrote it and carries that seat stance. The drawer gets out of the way so the stage has the width.

Things I want a decision on

QuestionWhoWhy it matters now
Does the fold-on-first-response behaviour carry over? The room header folds into one rail when the body gets heavy, and never re-folds once you have opened it by hand. KhoaSame rule I shipped on the OwnerMind drawer. If you did not like it there, it should not be here either.
Is the guest seat off by default? I have the Idea Pitcher unseated until you add it in the brief.KhoaSeven faces in a 46px rail is a lot; six is comfortable.
Does dismissed clear the convergence blocker, or only resolved? I have both clearing it and acknowledged not.Will Will’s ruling named resolve; the shipped enum also has dismiss. If a dismissed flag still blocks, a human who disagrees with Continuity can never let the room converge.
The MCP handler hardcodes resolvedBy:"agent". In the room it is the human resolving from the drawer.Will · Adam Minor, but it would misattribute every human resolution in the record, and the room’s whole point is that provenance is legible.
Paces rail — answered. Tap always views, any pace, live or done. Moving a live session is human-only and there are exactly three moves, now in the rail: Pause/Resume, Run another round, Abort to wrap.Will · ruled No forward jumps ever — a pace consumes the previous pace’s artifacts, so NOTES without READ is undefined. Seats never move the rail; the chair advances it; you interrupt it.
Staging demo-gate pass. Will did not transmit it, correctly.Khoa Everything here is grounded in source. A pass would let me do a fidelity pass against the running app and catch anything the source does not show.
Does the Better Auth clean reset change whose ownerId a seat token carries? New blocker in §11 of the spec, added after I built this. Will · Adam Not a design change — the seat detail panel says a seat is project-scoped and cannot approve, and that still holds. But it names an owner, and post-reset that identity follows the reset contract rather than the legacy backfill. Worth settling before anyone builds Phase 2.

Scope

Design only. No build, no backend, no Tavus provisioning — those are out of my lane and out of this pack. Nothing here is committed to the Greenpen repo; the fleet hold stands and this proceeds only because it is a Khoa direct instruction. QA risk tier: T3 — non-executable mocks, no product behaviour change.

Names, pages and figures are illustrative. The seats, the paces, the lane restrictions and the approval behaviour are the design. Portraits are placeholders and must be replaced by stills taken from the Tavus replicas — see assets/seat-manifest.json.