Skip to content

Cross-repo workflow grouping: entity, persistence, MCP - #25

Merged
jbachorik merged 2 commits into
mainfrom
feat/groups
Aug 28, 2026
Merged

Cross-repo workflow grouping: entity, persistence, MCP#25
jbachorik merged 2 commits into
mainfrom
feat/groups

Conversation

@jbachorik

Copy link
Copy Markdown
Contributor

A single piece of work — a feature, a refactor, a bug hunt — often spans sessions across several repositories. Today the only link between them is the operator's memory; there is no object that says "these sessions are one workflow," and no shared context that survives a session's context being cleared.

This change introduces a first-class Workflow entity that groups related sessions across repositories and carries a shared brief: the running narrative of the whole effort, written by whichever member session is active and read by the next one opened in any repo. It is the layer above forkedFrom (dead code, never set) and the per-session HandoffBrief (one session's testimony to its in-place successor).

Domain

New records: WorkflowId, WorkflowStatus (OPEN | ARCHIVED), WorkflowBrief, Workflow. WorkflowBrief reuses the HandoffBrief shape minus sessionId (workflow-scoped, not session-scoped) and writtenAtCommit (a workflow spans multiple repos and branches, so a single HEAD is meaningless). ManagedAgentSession gains an optional workflowId (14th field, at-most-one workflow per session). ApplicationState gains a workflows list. All follow the existing record/id/with* patterns.

Persistence

ApplicationStateCodec encodes/decodes the workflows array and the session workflowId leniently — a missing or malformed workflows array recovers to empty, a missing workflowId recovers to Optional.empty(). No schema version bump, the same discipline used for forkedFrom/evalMode when they were added.

Service

SessionManager gains workflow CRUD: createWorkflow, renameWorkflow, setWorkflowStatus, deleteWorkflow, writeWorkflowBrief, setSessionWorkflow, touchWorkflow, applyAgentWorkflowHandoff. prepareSuccessorSession copies workflowId from the outgoing session alongside the fields it already copies (displayName, namePinned, worktreeRoot, branchCreatedHere, evalMode) — a one-line addition, not riding forkedFrom.

MCP

session_handoff gains an optional workflow: true flag that writes the calling session's workflow brief instead of its per-session brief. Refused if the session is not a workflow member. No agent-driven workflow creation — naming the effort is a human act, like naming a session.

Design decisions

  • Single authored brief, not a roll-up of member briefs — one narrative, replaced wholesale.
  • At most one workflow per session — to join a second effort, fork the session into the second workflow.
  • Fork offers three destinations: same-workflow (default if affiliated; brief linked, not copied into the seed), new-workflow, or no-workflow. The per-session brief seed is unchanged in all three cases.

Verification

compileJava + compileTestJava pass. 6 new tests pass: 4 codec round-trip tests (workflow, session-with-workflowId, old-state-without-workflows, old-session-without-workflowId) and 2 MCP tests (workflow-target-writes-workflow-brief, absent-flag-writes-per-session-brief). One pre-existing test failure (adoptingARemoteOnlyBranchMintsATrackingLocalBranchAndReportsBothNames) fails on main at 9a1b84b — a git worktree add environment issue, unrelated to this change.

Not yet implemented

The UI layer — workflow grouping in the session rail, archived-workflow filter toggle, and workflow brief edit dialog. That is the next chunk of work.

Design doc: docs/plans/workflow-grouping-design.md.

jbachorik and others added 2 commits August 28, 2026 13:49
A single piece of work often spans sessions across several repositories.
Today the only link between them is the operator's memory; there is no
object that says 'these sessions are one workflow' and no shared context
that survives a session's context being cleared.

The design introduces a first-class Workflow entity (Alternative B
from the research): it groups sessions across repos and carries a
shared WorkflowBrief. It reuses the existing HandoffBrief shape (minus
sessionId and writtenAtCommit, which have no meaning above a single
session/tree) and the single-writer state model. A session belongs to
at most one workflow; a fork offers same-workflow / new-workflow /
no-workflow, with the brief linked rather than copied into the seed.

An rloop review corrected one critical error: forkedFrom is dead code
(never set, SessionManager explicitly says 'No lineage is recorded'),
so workflowId inheritance was moved to prepareSuccessorSession where
the successor is actually built.

Verification: design-only, no code changed. The rloop ran in-session
because both subagent models (deepseek and GLM-5.2) aborted on every
spawn.

Co-Authored-By: Claude <noreply@anthropic.com>
A workflow groups related sessions across repositories and carries a
shared brief — the running narrative of the whole effort, written by
whichever member session is active and read by the next one opened in
any repo. This is the layer above forkedFrom (dead code, never set)
and the per-session HandoffBrief (one session's testimony to its
in-place successor).

Domain: new WorkflowId, WorkflowStatus, WorkflowBrief, and Workflow
records. ManagedAgentSession gains an optional workflowId (14th
field, at-most-one). ApplicationState gains a workflows list. All
follow the existing record/id/with* patterns.

Persistence: ApplicationStateCodec encodes/decodes the workflows
array and the session workflowId leniently — a missing or malformed
workflows array recovers to empty, a missing workflowId recovers to
Optional.empty(). No schema version bump, same discipline as
forkedFrom/evalMode when they were added.

Service: SessionManager gains workflow CRUD (create, rename, archive,
delete, write brief, affiliate session, touch). prepareSuccessorSession
copies workflowId from the outgoing session alongside the fields it
already copies (displayName, namePinned, worktreeRoot,
branchCreatedHere, evalMode) — a one-line addition, not riding
forkedFrom.

MCP: session_handoff gains an optional 'workflow': true flag that
writes the calling session's workflow brief instead of its per-session
brief. Refused if the session is not a workflow member. No agent-driven
workflow creation — naming the effort is a human act, like naming a
session.

Verification: compileJava + compileTestJava pass. 6 new tests pass
(4 codec round-trip: workflow, session-with-workflowId, old-state-
without-workflows, old-session-without-workflowId; 2 MCP: workflow-
target-writes-workflow-brief, absent-flag-writes-per-session-brief).
1 pre-existing test failure
(adoptingARemoteOnlyBranchMintsATrackingLocalBranchAndReportsBothNames)
fails on main at 9a1b84b — a git-worktree-add environment issue,
unrelated to this change.

Not yet implemented: the UI layer (workflow grouping in the rail,
archived toggle, brief edit dialog).

Co-Authored-By: Claude <noreply@anthropic.com>
@jbachorik
jbachorik marked this pull request as ready for review August 28, 2026 11:55
@jbachorik
jbachorik merged commit d745664 into main Aug 28, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant