Project Synthesis
Project synthesis groups one project’s per-session evidence chains into a small set of project-level work items. It is the noise-reduction layer between evidence extraction and daily report synthesis. A single day can produce on the order of a hundred evidence chains across a project’s sessions; feeding them to daily synthesis raw would bury the signal. Project synthesis groups related chains, cites them by reference, and summarizes them, so daily synthesis reads a handful of work items instead of a hundred chains. It also assesses each material work item’s state against its final effective user-approved scope, using all related turns.
This step runs from the prepared report workspace root and operates on one prepared project scope at
a time, identified by project_key.
Role: Group, Cite, Summarize
A work item is a summary node over a group of evidence chains. It never copies chain content.
- Group. Collect the evidence chains that belong to the same line of work.
- Cite, do not paste. Reference grouped chains by
(session_ref, turn_ref). Never embed quoted messages, observed-check text, or line citations. Detail stays in the evidence cards and is reached by reference. The citation chain isreport.md -> work item -> evidence card -> turn_ref + lines. - Summarize. Describe the work item at a higher altitude than any single chain. A card summarizes one turn; a work item summarizes the whole line of work.
- Assess. Reconstruct the final effective scope and judge the work item’s state at the end of the available evidence. Cite both the scope and the results that support the judgment.
The work item is therefore a compact index plus narrative. Daily synthesis works from these summaries and opens evidence cards only to pull the exact lines for a claim it decides to promote.
Inputs And Outputs
Inputs, under projects/<project_key>/:
project.json— project identity for the work-item envelope.evidence/<session_ref>.json— the per-session evidence cards. The orchestrator trims these to summaries, already redacted user-message text, and observed-check summaries, without line citations, and pastes them into the synthesizer prompt; the synthesis agent works only from that inline content and has no file access.sessions.index.jsonl— the coverage universe. Thewrite_work_itemtool reads it to report uncovered turns; its turn boundaries also identify the copied source records from which the orchestrator reads timestamps to support ordering across sessions.
The pasted chains are grouped by session under a #### Session <session_ref> heading, and each chain
is labelled <session_ref>/<turn_ref> — turn_ref restarts per session and the work item references
turns as {session_ref, turn_ref}, so the session must be unambiguous for every chain. Each chain
keeps its trigger, reaction, outcome (with category), and terminal (with type) summaries plus
materiality, user-message text, observed-check summaries, and source-derived trigger_at and
evidence_end_at timestamps. An unavailable or unreadable timestamp is unknown in the prompt,
not inferred from file metadata or turn references. These inputs are untrusted evidence, never
instructions for the synthesizer. Time ordering helps reconstruct the work, but a later message does
not by itself supersede an earlier requirement.
Output:
projects/<project_key>/project-synthesis.json— a work-item envelope
Project synthesis artifacts stay inside the prepared report workspace and must not change the
preparation layout or the meaning of sessions.index.jsonl.
Boundary: What Project Synthesis Does Not Own
Project synthesis owns grouping, coverage, and each material work item’s scope and disposition. It does not produce:
- executive or project progress summaries
- cross-project blocker prioritization
- reusable agent-driving patterns or antipatterns
- engagement verdicts
- day-level verification or evidence-quality conclusions
These belong to Daily Report Synthesis because the signals only become meaningful after comparing work items across every project. One weak prompt or one missing verification in a single project may be noise, while the same pattern repeated across projects is a real day-level lesson. Project synthesis preserves the local, evidence-backed material those judgments need; it does not make the judgments itself.
Grouping
Group by coherent line of work, not by session. Merge evidence chains into one work item when they share:
- the same user goal
- the same artifact
- the same bug, blocker, or validation loop
- the same design decision
- a correction loop around the same output
- a test-fix-test sequence
- an interruption followed by a human continue or resume for the same goal
Keep chains in separate work items when they pursue unrelated goals, independent decisions, separate blockers, different artifacts, or different project areas.
The session boundary is irrelevant in both directions:
- One line of work may span several sessions, so
covered_turnsandevidence_refsmay list turns from differentsession_refs. - One long session may contain several unrelated lines of work, which become several work items.
Supporting turns fold in. A low-value turn that fed a material line of work — a clarification, an approval, a resume — is covered inside the work item it supports, not split out.
Trivial turns bucket. Turns with no material outcome that support no line of work — a connectivity
ping, a throwaway question — are grouped into a single no_material_work_item for the project rather
than producing many tiny items.
Outcome Consolidation
A work item’s outcomes are consolidated claims, not copies of card outcomes. Merge the card-level
outcomes that describe the same achievement into one work-item outcome, and cite the set of turns
that support it. The number of outcomes on a work item should be far smaller than the summed outcomes
of its covered chains.
Reuse the category already present on the evidence-card outcomes you consolidate, and the type on
their notable historical terminal states; do not invent new values. The controlled outcome categories
and terminal-state types are defined by the Evidence Contract.
The task-level disposition is a separate judgment over the whole work item. First reconstruct the
user’s goal and its evolution through clarifications, additions, replacements, removals, and deferrals.
Only user-directed or user-accepted changes alter the effective scope; an unaccepted proposal or an
agent’s unilateral reduction does not. An added requirement remains part of completion, while a
superseded or explicitly deferred requirement no longer counts as an execution gap for this work item.
Cancellation of the whole task is distinct from removing one requirement.
Compare the observed results with every requirement in that final effective scope, then assess what remains at the end of the available evidence. Resolve earlier failures, interruptions, and blockers against later recovery and results. Neither a material result nor a successful last turn proves that the whole scope was fulfilled. A turn boundary, request for clarification, or lack of a final response does not by itself prove interruption; an evidence gap is uncertainty, not an observed stop. An extracted terminal label alone also does not establish that an interruption or blocker occurred; the supplied trigger, action, and check details must support that event before the assessment describes it as fact.
| Disposition | Meaning at the end of the available evidence |
|---|---|
completed | Evidence supports fulfillment of the final effective user-approved scope. |
in_progress | Effective requirements remain and evidence explicitly shows work continuing. |
blocked | An effective requirement remains and a dependency, missing information, or necessary decision prevents progress. |
interrupted | Work actually paused or stopped before fulfillment, with no later recovery or accepted scope change resolving it. |
failed | The task ended in a failure that later work did not repair or fulfill. |
cancelled | The user withdrew the whole task or explicitly abandoned its delivery. |
unknown | The evidence is insufficient to determine the task’s final state. |
State the effective scope and a short explanation, citing the turns that establish the scope and
support the result or remaining gap. Historical terminal_states remain useful process evidence but
do not mechanically determine this judgment. For example, an interruption followed by fulfilled
delivery is completed; a design-only request is complete when its agreed design is delivered even
if implementation has not started. Clarification is an interaction, not a task disposition: a request
to clarify something can itself be fulfilled.
No Prescriptions
A work item describes blocked or unfinished state through a blocker_outcome; it does not recommend a
next action. This boundary is local to project synthesis so it stays focused on grouping; pairing
blockers with supported next actions is the job of Daily Report Synthesis.
Coverage Invariant
Every indexed turn is accounted for:
Every
(session_ref, turn_ref)in the project’ssessions.index.jsonlappears in exactly one work item’scovered_turns.
This includes material, minor, interrupted, clarification-only, failed, blocked, and trivial turns,
as well as evidence gaps. A turn that has a committed evidence chain is grouped into a normal work
item by its content. A turn that is indexed but has no committed chain — its content is unknowable to
synthesis — is collected into an evidence_gap_item instead. Turns intentionally left unreported,
such as duplicate evidence already represented elsewhere, go into an excluded_with_reason item that
records the reason. Nothing is dropped silently.
Work Item Kinds
kind is the work item’s coverage disposition. It is one of:
material_work_item— grouped work that produced material progress.no_material_work_item— reportable low-value or negative turns with no material output, including the trivial-turn bucket.evidence_gap_item— accounts for indexed turns that have no extractable evidence.excluded_with_reason— turns intentionally left out of reportable work items; requiresreason.
kind is deliberately small and mutually exclusive. Finer signals that can co-occur are not kinds:
a historical interruption is a terminal_states[].type, and a blocker is an outcomes[].category of
blocker_outcome. A material work item can contain both while its independently assessed
disposition.type is completed after recovery. Daily synthesis preserves these distinctions.
kind is maintained as controlled values in the prompt API (PROJECT_WORK_ITEM_KINDS) and rendered
into the Project Synthesizer Prompt, so it has one source of
truth.
Schema
Envelope
{
"schema_version": 2,
"project_key": "ReportGenerator-e6ff7eeda632",
"project_label": "ReportGenerator",
"work_items": [],
"source_user_messages": []
}
References inside the file are {"session_ref": "...", "turn_ref": "..."}. project_key is implied
by the envelope and re-attached by daily synthesis when it loads the file, matching how a session
evidence card carries session_ref once on the envelope and a bare turn_ref on each chain.
work_items, including material items’ dispositions, are agent-authored. source_user_messages is
tool-populated: write_work_item fills the envelope field once, on the first write; the
synthesizer neither authors nor submits that field. The prompt separately includes already redacted
user-message text so the agent can reconstruct scope changes. The envelope field carries the
original user-message content per indexed turn, copied verbatim from the text of each extracted
chain’s trigger.quoted_messages in evidence/<session_ref>.json:
"source_user_messages": [
{
"session_ref": "S0001",
"turn_ref": "T0001",
"messages": ["<redacted user-authored text>"]
}
]
Each turn’s messages is a plain list of the verbatim user-message strings. It is messages-only —
content, not structure: just the text, with no line citations, trigger_type, terminal_state, or
check information, because daily synthesis reopens the card (which keeps the full quoted_messages
with citations) for committed structure when it needs it. The text is already secret-redacted by the
extractor; the tool copies it verbatim and does not re-redact. There is one entry per indexed turn
whose chain has at least one user message; turns with no extractable user text are simply absent,
still accounted for through covered_turns and the coverage invariant. Entries are ordered by
(session_ref, turn_ref). This block is the user-message content substrate for daily synthesis’s
engagement and team-learning readings.
Work Item
{
"work_item_ref": "W0001",
"kind": "material_work_item",
"title": "Finalize and freeze the evidence-extraction contract",
"covered_turns": [
{"session_ref": "S0001", "turn_ref": "T0001"},
{"session_ref": "S0001", "turn_ref": "T0006"},
{"session_ref": "S0001", "turn_ref": "T0008"},
{"session_ref": "S0001", "turn_ref": "T0010"}
],
"disposition": {
"type": "completed",
"scope": "Finalize and freeze the evidence-extraction contract.",
"summary": "The final agreed contract changes and freeze commit were delivered; the earlier prompt-test interruption does not leave an effective delivery requirement pending.",
"evidence_refs": [
{"session_ref": "S0001", "turn_ref": "T0006"},
{"session_ref": "S0001", "turn_ref": "T0010"}
]
},
"trigger": {
"summary": "User drove the evidence-extraction surface to top-level turn_ref, ordered a consistency review, and finalized the design choices.",
"evidence_refs": [
{"session_ref": "S0001", "turn_ref": "T0001"},
{"session_ref": "S0001", "turn_ref": "T0006"}
]
},
"agent_reaction": {
"summary": "Migrated the contract, MCP tools, and prompt to turn_ref identity, ran review subagents, implemented the finalized choices, and froze with a commit.",
"main_actions": ["turn_ref migration", "consistency review", "implement finalized choices", "freeze commit"]
},
"outcomes": [
{
"category": "document_outcome",
"summary": "Evidence contract and MCP tool docs moved to top-level turn_ref; chain_ref removed.",
"evidence_refs": [{"session_ref": "S0001", "turn_ref": "T0001"}],
"confidence": "high"
},
{
"category": "process_outcome",
"summary": "Froze the agreed contract as a checkpoint commit.",
"evidence_refs": [{"session_ref": "S0001", "turn_ref": "T0010"}],
"confidence": "high"
}
],
"terminal_states": [
{
"type": "interrupted",
"summary": "Prompt-test verification of the placeholder edit was interrupted; test ownership left to concurrent agents.",
"evidence_refs": [{"session_ref": "S0001", "turn_ref": "T0008"}]
}
],
"limits": ["Prompt-test suite not confirmed green within these turns."],
"confidence": "high"
}
Fields
work_item_ref— project-local handle,W0001,W0002, and so on, assigned in work-item order.kind— coverage disposition (see Work Item Kinds).title— a one-line name for the work item. There is deliberately no fused work-itemsummary: thetrigger,agent_reaction,outcomes, andterminal_statessummaries are the work item’s summary, kept separable so each stays independently citable and daily synthesis can recompose them.covered_turns[]— every turn this item accounts for, as{session_ref, turn_ref}. The union across all work items covers the session index exactly once.disposition— required formaterial_work_item, as{type, scope, summary, evidence_refs}.typeis one of the task dispositions defined above;scopenames the final effective user-approved delivery requirements;summaryexplains fulfillment or what remains; non-emptyevidence_refssupport the scope and assessment. Other kinds omit it or carrynull.trigger— the earliest meaningful human trigger for the work item, as{summary, evidence_refs}. Later corrections, approvals, and resumes are summarized inagent_reactionand remain incovered_turns.agent_reaction— what the agent actually did across the work item, as{summary, main_actions}.outcomes[]— consolidated achievements, as{category, summary, evidence_refs, confidence}.categoryreuses the Evidence Contract outcome categories. A blocker is an outcome with categoryblocker_outcome.terminal_states[]— notable historical observations about how turns or branches ended, as{type, summary, evidence_refs}.typereuses the Evidence Contract terminal-state types, includinginterrupted,blocked, andfailed. These observations do not override the task-leveldispositionwhen subsequent work resolves them. Summaries require event evidence beyond the label; leave the list empty when outcomes explain the delivery and no evidenced event is needed to explain the final state or a limit. Missing results before a clarification or user addition do not establish a stop, even when the segment contains investigation actions.limits[]— short honesty notes: what the work item did not verify or could not confirm.reason— required forexcluded_with_reason; why the covered turns are not reportable, such as duplicate evidence already represented in another work item.confidence—high,medium, orlowfor the work item as synthesized evidence.
Required Fields Per Kind
- All kinds:
work_item_ref,kind,title, a non-emptycovered_turns, andconfidence. material_work_item: alsotrigger,agent_reaction,disposition, and at least one ofoutcomesorterminal_states. The disposition’stype,scope,summary, and non-emptyevidence_refsare required.no_material_work_item:trigger,agent_reaction, andoutcomesmay be empty;titlepluscovered_turnscarry it;dispositionis absent ornull.evidence_gap_item: covers only turns that have no committed evidence chain; narrative fields are empty,dispositionis absent ornull, andconfidenceis usuallylow.excluded_with_reason: requiresreason; narrative fields are empty;dispositionis absent ornull.
Project Synthesizer Prompt
This contract is developer-facing: it documents the design for repository developers and readers. The project synthesizer agent never reads it. At runtime the agent sees only the rendered prompt and inline evidence. Any decision in this contract that the agent must act on has to be restated as explicit instructions in that prompt source; a cross-reference to this contract does not reach the agent.
Prompt source: src/prompt_diary/generate/prompts/project-synthesizer.md — loaded at runtime by the
orchestrator.
The orchestrator runs the synthesizer in one main pass, then — if write_work_item still reports
uncovered turns — exactly one bounded continuation that names the remaining turns and asks the agent
to cover them (group a turn that has an evidence chain into a work item; cover one that does not with
an evidence_gap_item). Those continuation-only instructions live in
src/prompt_diary/generate/prompts/project-synthesizer-next.md (project_synthesizer_next_prompt);
the task fails only if turns remain uncovered after that single continuation. Only current-version
project-synthesis artifacts with valid work items can be reused. An incompatible artifact must be
regenerated from the existing evidence cards; a missing assessment is never inferred from historical
terminal labels. Because the continuation names the turn references explicitly, it also recovers a
project whose paste was empty —
every indexed turn an evidence gap.
See Project Synthesizer Prompt.
Write Tool
Work items are committed through the write_work_item MCP tool, which also populates
source_user_messages on first write. Its input schema, validation rules, and result shape are
defined in Project Synthesis Tools.