Skip to content

Composition Graphs

Composition graphs are JSON files that wire stages together. Noether type-checks the entire graph before execution.

Graph Format

{
  "description": "What this composition does",
  "version": "0.1.0",
  "root": { "op": "Sequential", "stages": [ ... ] }
}

Node Types

Op Description
Stage Call a single stage by hash ID
Sequential Pipe output of each stage to the next
Parallel Run branches concurrently, merge outputs
Branch Conditional: if/then/else

sprint_tick.json

The main loop. Run every 60 seconds by the scheduler.

Input:  { sprint_id, repo, stall_threshold_m }
Output: { actions_taken, dag_complete }

Flow:
1. Parallel: load DagState + last_poll + agents from KV
2. Poll GitHub events
3. Save last_poll
4. Evaluate DAG → produce actions
5. Save DagState
6. Parallel: health checks + completion check
7. Execute actions (spawn, merge, comment, escalate)

kickoff.json

One-shot. Generates a DAG and creates GitHub issues.

Input:  { brief, repo, num_agents }
Output: { sprint_id, dag, issues_created }

Flow:
1. Fetch repo context
2. Generate DAG from brief
3. Validate DAG
4. Save to KV
5. Create issues

retro.json

One-shot. Collects feedback and generates a report.

Input:  { sprint_id, repo }
Output: { report_path }

Flow:
1. Load final DagState from KV
2. Parallel: collect feedback + compute KPIs
3. Write report

spawn_agent.json

Called by the sprint tick when a task is ready.

Input:  { sprint_id, task_id, agent_id, repo, worktree_base }
Output: { pid, started_at }

Flow:
1. POST to caloron-shell /spawn
2. Save PID to KV

Type Checking

Validate a graph without executing:

noether run --dry-run compositions/sprint_tick.json \
  --input '{"sprint_id": "x", "repo": "o/r", "stall_threshold_m": 20}'

This catches type mismatches between stages before any side effects occur.