Skip to content

State

All of CVSM’s workflow state lives in GitHub: issues, sub-issues, dependencies, linked branches, PRs, checks and closed states. The repo holds no plan, progress or notes files, and a session holds nothing, so any session can end at any moment and the next one reads where things stand.

Humandecides in a session
Agentsfour skills; Claude Code or Codex
RecordGitHub and MLflow, written as it happens

01 Plan

Human
Agents
plandiscuss, draft
Record

Issues

  • study #10
  • code #11
  • run #12
  • Decision:

02 Implement

Human
Agents
implementcode to a PR
Record

Pull request

  • Closes #11
  • guard · test
  • Decision:

03 Review

Human
Agents
reviewfresh session
Record

Review

  • Verdict: pass
  • @ 3f9c2a1

04 Merge

Human
Agents
merge.pythe only merge
Record

main

  • squash merge
  • of that head
  • Decision:

05 Run

Human
Agents
runlaunch, check
Record

MLflow runs

  • cvsm.* cfg.*
  • artifacts
  • Decision:

06 Analyze

Human
Agents
reportthree lines
Record

Results

  • per-issue table
  • spec check
  • study table
  • Decision:

01Publish

When
New or changed approved work: publishing a plan; changing a task’s Goal, Scope, Acceptance or Merge, or a study’s Arms, Controlled or Adaptable; changing a protected path.
You say
“publish”, or approve the change
Recorded
The parent and its sub-issues, created wave by wave, and a Decision: comment on the parent.

Blocker

When
The same failure 3 times in a row, 3 changes verdicts in a row, an ambiguity that would change the deliverable, or a Controlled setting that can’t be met without changing the comparison.
You say
one of at most 3 options, e.g. “option 2”
Recorded
needs-decision and a four-line comment (Blocked:, Evidence:, Options:, Recommend:) when you’re away; then your Decision: comment.

02Merge

When
A PR is merge-ready: guard and test green and Verdict: pass on the current head. Under Merge: agent the agent merges it itself with merge.py, which refuses protected paths and unreviewed heads.
You say
“merge”, or “merge #15”
Recorded
merge.py --human squash-merges that head; the task closes, with a Decision: comment.

03Budget

When
The next step would exceed the budget in tokens, time or GPU hours.
You say
“continue”, with a new budget if you like
Recorded
A Decision: comment with the budget you set.

04Conclude

When
All of a study’s sub-issues are closed and it awaits analysis.
You say
your conclusion, e.g. “conclude #10: …”
Recorded
The study closes with your conclusion, recorded as a Decision: comment.

Hover or focus a gate

A parent issue holds the why; its sub-issues hold the work.

  • study: a research question. Its body is the study form, including the spec.
  • plan: development work, with ### Goal and ### Context.
  • code: one change inside a fixed Scope, done in one branch and one PR.
  • run: a set of runs, closed with a results comment. A run task has no PR.

The only other label is needs-decision. Parents and dependencies are native GitHub fields, set when the issue is created and never written into the body:

Terminal window
gh issue create --label run --title "<title>" --parent 10 --blocked-by 11 --body "..."

For example, study #10 has code task #11 and run task #12, and #12 is blocked by #11 because its runs need the merged code.

Every state below is something GitHub already shows.

State How GitHub shows it
Waiting Blocked by an issue that is still open
Ready Open, not blocked, no linked branch
In progress Has a linked branch
Needs decision Label needs-decision plus a blocker comment
In review PR open, checks or review not finished
Merge-ready guard and test green, and the latest review is Verdict: pass @ <head SHA> for the current head
Done A code issue closes when its PR merges (Closes #N); a run issue is closed by the agent with its results comment
Abandoned Closed as not planned, on the human’s explicit instruction
State How GitHub shows it
In progress Open, with open sub-issues
Awaits analysis Open, all sub-issues closed
Closed Completed with the conclusion, or not planned, on the human’s explicit instruction

Concluding a study is gate 04.

Every instruction starts by reading state from GitHub, never from chat memory: open study and plan issues with their sub-issue summaries, open PRs with their checks, and issues labelled needs-decision.

A session claims a ready issue by creating a linked branch, then checks that no other branch got linked at the same time:

Terminal window
gh issue develop 11 --name t/11-<slug> --base main
gh issue develop --list 11

If another branch is linked too, the session deletes its own and picks other work. A session continues an in-progress issue only if the instruction names it or the session claimed it itself. That is what makes parallel sessions safe.

One task is one issue, one branch t/<N>-<slug>, one worktree ../worktrees/<N>-<slug> beside the main clone, and one PR. After the squash merge, each commit on main maps to one issue.