DK
← Back to home

Program Desk

An operating console for technical program managers. Raw workplace signal goes in; a defensible program record and the documents that hang off it come out.

Role
Product design, architecture, build
Type
Self-directed prototype
Stack
Vanilla JS, LLM extraction, document store
State
Working prototype

The problem

The record of a program lives in the wrong place

A technical program manager's real job is to hold a coherent, current, defensible model of a program in their head, and to be the person who noticed. Everything else - the standups, the trackers, the decks - is instrumentation for that.

The instrumentation is badly placed. The moments that change a program almost never happen in the tracker. They happen in a sentence inside a reply-all chain, in a Slack thread that scrolls past, in the ninth minute of a call where a vendor says "that's moved to the October drop". The tracker is updated afterwards, from memory, by the one person who was paying attention, if they had time that day.

So the record decays in a specific and predictable way. Commitments made verbally never get an owner. Risks are logged once at kickoff and never rescored. Schedule slips are recorded as a new date with no note of what caused them, which is why the same milestone slips three times before anyone asks the right question. And the artifacts leadership actually reads - the status report, the exec update - get rewritten from scratch every week, by hand, from the parts of the program the author happened to remember.

The work isn't tracking. The work is reconciling - turning scattered signal into one record you'd be willing to defend in a steering committee.

Why existing tools miss it

Every tool assumes the record already exists

Project tools are excellent at storing a structured record and useless at producing one. Jira will hold your action items beautifully once someone has typed them in. That typing is the entire cost, and it is paid by the most expensive person on the program, at the end of a day when they are already behind.

The wave of AI meeting notetakers gets closer - they at least start from the signal - but they stop at summary. A summary of a meeting is a fourth artifact to read, not one fewer. It does not know that the vendor slip you just described is the same risk that was logged in week 4, or that the date it mentions is eight days past a baseline that nobody has re-cut.

The gap sits between the two: something that reads the signal and holds the structured record, so it can reconcile one against the other.

Product thesis

One record, fed by signal, defended by a human gate

Program Desk takes raw workplace text - an email chain, a chat export, a meeting transcript, a vendor quote - and decomposes it into the six things a program is actually made of: actions, risks, decisions, dependencies, milestones and money. Each extracted item carries the sentence that produced it. The program manager accepts, edits or discards each one. Nothing enters a log automatically.

Once the record exists and is trusted, the documents are close to free. A status report is not a writing task; it is a query against the record, rendered in the shape a steering committee expects. Same for a RAID review, an escalation memo, a PRD, a story map, a cutover runsheet.

The loop

Signal, proposal, record, artifact

Signal Email threads Chat exports Transcripts Extraction Typed items with source sentence, confidence, dates Review gate A person accepts, edits or discards every proposal. Nothing is automatic. Program record Actions · Risks Decisions · Deps Schedule · Budget Artifacts Status · RAID PRD · Story map Cutover plan A status report becomes an email, which becomes signal again every item keeps its source sentence from here to the end →
The gate is the load-bearing element. Remove it and this becomes an unauditable tracker that occasionally invents commitments - which is worse than no tracker, because people stop reading it and nobody announces that they have.

Design decisions

Four calls that shaped the product

1. Nothing is written to a log without a human accepting it

The obvious version of this product auto-populates the tracker. It demos better and it is the wrong product. A program manager who finds one fabricated commitment in their action log stops trusting the whole log - and, critically, they stop trusting it silently. There is no error state that surfaces; the tool just quietly becomes decoration.

So every extracted item lands in a review queue as a proposal, rendered in a distinct colour, carrying the verbatim sentence that produced it and a confidence indicator. Accept, edit or discard. The colour is not decoration: it is the only thing in the interface that says "a machine believes this and a person has not yet agreed".

Trade-off: this is real work for the user - roughly ten seconds per item. It caps how much signal one person can process, and it means the product cannot honestly claim to run unattended. I took that cost deliberately: the queue is the thing that makes the record defensible, and a defensible record is the entire value proposition.

2. Provenance travels with the item, permanently

Every record keeps the sentence it came from and the source it came from, and both survive into the generated documents as bracketed item IDs. When a steering committee asks "where did the $14,000 number come from", the answer is one click, not an archaeology exercise in someone's sent folder.

This also solves a subtler problem. Extraction quality is impossible to improve if you cannot see what the model saw. Keeping the source sentence means every accepted and every discarded proposal is a labelled training example, for free, as a by-product of normal use.

Trade-off: storing verbatim excerpts of email and chat raises the sensitivity of the datastore considerably. It moves the product from "stores metadata about your work" to "stores fragments of your correspondence", with everything that implies for retention, access control and jurisdiction. The architecture document treats this as a first-class constraint rather than a footnote.

3. Two logs nobody asked for

The brief named four trackers: actions, risks, schedule, budget. I added decisions and cross-team dependencies.

Dependencies because that is where program slip actually originates. A program rarely fails because its own team was slow; it fails because something owed by another team arrived late, and the four named logs would not have caught it - the risk log might carry a generic "vendor delivery risk" while the specific commitment, its date and how much you believe it goes untracked. Confidence scoring on dependencies is the earliest honest warning a program gets.

Decisions because programs relitigate. Week 19 reopens a question settled in week 4, and without a record of who decided what and on what basis, the program pays for the debate twice. A decision log is cheap to keep and expensive to lack.

Trade-off: six logs is more surface than four, and every additional log is another thing that can go stale and quietly erode trust in the whole record. The extraction pipeline is what makes this affordable - the marginal cost of a sixth log is a prompt instruction and a table, not a sixth thing for a human to maintain by hand.

4. Documents are queries, not templates

Every one of the 28 document types is generated from the live program record rather than from a blank form. A status report cites the actual overdue action IDs. A budget review computes real variance. Where the record genuinely cannot support a claim, the generator is instructed to write the best-judgement content and mark it assumption, rather than emitting "TBD" or inventing a fact silently.

That last instruction matters more than it looks. The failure mode of document generation is not a wrong sentence; it is a confident, plausible, unverifiable sentence sitting between two correct ones. Forcing assumptions to be labelled makes the document's own uncertainty legible to whoever reads it next.

Trade-off: generation quality is now bounded by record quality. A thin record produces a thin PRD, and the user may reasonably blame the tool. I decided that was the honest failure - the alternative is a generator that writes a confident document about a program it knows nothing about.

What I built

Prototype scope

AreaBuiltDeliberately not built
IngestionPaste-based intake for email, chat, transcript and document textLive inbox and calendar polling
ExtractionTyped item extraction with relative-date resolution, confidence, and verbatim provenanceEntity resolution against a people directory
ReviewAccept / edit / discard queue with confidence displayBulk accept, keyboard triage
LogsSix logs with derived exposure scoring, slip calculation and budget varianceBaseline history and re-baseline narrative
ViewsBrief, risk exposure grid, baseline-vs-current timeline, budget rollupGantt with dependency edges
Documents28 templates generated from the live record, with citation and assumption markingRound-trip editing back into the record
QueryNatural-language questions answered from the record onlyCross-program portfolio queries

The prototype ships a worked example - an instant-payouts launch for a courier marketplace at week 9 of 20, with a bank partner running late, two pilot states without licensing sign-off, an overdue unowned action and an unowned high-exposure risk. Prototypes demoed on empty state hide exactly the problems that matter, because an empty tracker is well-behaved and a messy one is not.

How I'd judge it

Metrics that would actually falsify the thesis

Adoption metrics would flatter this product. Weekly active users and items created both go up if the extraction is merely plausible, which is precisely the failure mode I care about. The measures below are chosen because a bad version of the product would fail them.

QuestionMeasureWhat a bad result means
Is extraction trustworthy?Proposal acceptance rate, and edit rate among acceptedHigh discard means noise. High edit rate means the model is close but unreliable - worse for trust than obvious errors
Does the record stay current?Median age of the oldest un-reviewed item in the queueA growing backlog means the gate has become a chore and the record is drifting
Are documents used or rewritten?Share of generated documents exported without edit, versus heavily rewrittenHeavy rewriting means generation is a first draft at best, and the time saving is illusory
Does it catch what people miss?Items accepted that the user confirms they had not already tracked elsewhereIf everything was already known, the product is a nicer tracker, not a new capability
Does it change outcomes?Time between a slip occurring and it appearing in a status artifactThe whole thesis is early detection. If this does not shrink, nothing else matters

What I'd change

Three things I got wrong or left open

The review queue needs to be keyboard-first and it is not. I built it as cards with buttons, which is fine for eleven items and miserable for eighty. Triage interfaces live or die on how fast a practised user can move through them, and mine assumes a mouse. A single-item focused view with accept/edit/skip on three keys would change the ceiling on how much signal one person can process - which is the constraint the whole product design leans on.

I modelled a program, not a portfolio. The data model assumes one program with one record. Most TPMs at the level this is built for run three to six simultaneously, and the interesting question - which two programs are competing for the same dependency - is unanswerable in the current shape. Retrofitting that is a data model change, not a view change, which is why it belongs in the next version rather than a later one.

Write-back is the real product and I only built read. Accepting an action here creates a row in this tool. In practice it should create the ticket in whatever system the team already lives in, and track its status back. Without that, this is a second place to look, and a second place to look is how tools die. It is also by far the hardest piece, which is exactly why a prototype that skips it should say so rather than imply the problem is solved.