Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,59 @@ CLK_ROBUSTNESS_MAX_QA_DEPTH=3
CLK_ROBUSTNESS_PLATEAU_WINDOW=3
CLK_ROBUSTNESS_PLATEAU_ACTION=escalate_then_reframe

# Adversarial debate panel: instead of a single critic, spawn N critics
# with distinct lenses that try to break the work and debate each other
# across rounds before the worker revises.
# off | careful_only (default) | all
CLK_ROBUSTNESS_DEBATE=careful_only
# Comma-separated adversarial lenses (one critic per lens, run in parallel).
CLK_ROBUSTNESS_DEBATE_LENSES=correctness,security,simplicity
# Cap on debate rounds (each round = panel critique + worker revision).
CLK_ROBUSTNESS_DEBATE_MAX_ROUNDS=2

# ----------------------------------------------------------------------
# Autonomous missions, done-gate, no-op guard, deliberation
# (clk run drives a full mission to a code-gated done; see README
# "Autonomous missions"). Every check has a kill switch here.
# ----------------------------------------------------------------------
# Mission loop bounds + behavior.
CLK_MISSION_MAX_PHASES=12
CLK_MISSION_MAX_ITERATIONS_PER_PHASE=3
CLK_MISSION_MAX_TOTAL_CYCLES=60
CLK_MISSION_PHASE_GATE=true
CLK_MISSION_REFINE_REQUIRED=true
CLK_MISSION_AUTO_CONSENSUS_ON_STALL=true
CLK_MISSION_CHARTER_FIRST=true
CLK_MISSION_COMMIT_TRACE=true
CLK_MISSION_COMMIT_GRANULARITY=batch
CLK_MISSION_MIN_CYCLES_BEFORE_DONE=1
CLK_MISSION_TELEMETRY_STDOUT=true
CLK_MISSION_ON_BUDGET_EXHAUSTED=advance
# Comma-separated default lifecycle phases (used when planning can't parse).
CLK_MISSION_DEFAULT_PHASES=discovery,product,engineering,validation,deployment
# Machine-checkable done-gate: ACTION:done is only granted when these pass.
CLK_DONE_GATE_ENABLED=true
CLK_DONE_GATE_REQUIRE_TESTS_GREEN=true
CLK_DONE_GATE_REQUIRE_DELIVERABLES=true
CLK_DONE_GATE_MIN_DELIVERABLE_FILES=1
CLK_DONE_GATE_REQUIRE_QA_PASS=true
CLK_DONE_GATE_REQUIRE_RALPH_PASS=true
CLK_DONE_GATE_FORBID_TODO_MARKERS=false
CLK_DONE_GATE_MAX_FINISH_ATTEMPTS=5
# No-op guard: re-dispatch a producing stage that changed no files.
CLK_NOOP_GUARD_ENABLED=true
CLK_NOOP_GUARD_MAX_REDISPATCH=2
CLK_NOOP_GUARD_PRODUCING_AGENTS=engineer,ralph
CLK_NOOP_GUARD_TREAT_OUTPUTS_STAGE_AS_PRODUCING=true
# Deliberation: self-reflection + blocking peer Q&A before a phase passes.
CLK_DELIBERATION_ENABLED=true
CLK_DELIBERATION_ENCOURAGE_QUESTIONS=true
CLK_DELIBERATION_REQUIRE_OPEN_QUESTIONS_RESOLVED=true
CLK_DELIBERATION_SELF_REFLECT_PREAMBLE=true
CLK_DELIBERATION_MIN_DEBATE_ROUNDS=1
# Auto-derive a real validation command when a producing stage has none.
CLK_VALIDATION_AUTO_DERIVE=true

# ----------------------------------------------------------------------
# Prior-knob reference (already supported; documented here for parity)
# ----------------------------------------------------------------------
Expand Down
11 changes: 10 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,20 @@ jobs:
pip install -e ".[api,telegram]"
pip install pytest pytest-asyncio httpx

- name: Run tests
- name: Run unit tests
run: pytest tests/ -v
env:
CLK_WORKSPACES_DIR: /tmp/clk-workspaces

- name: Run offline autonomous-mission e2e (shell provider, no network)
# Exercises the single-prompt mission, the done-gate / no-op guard, the
# charter-first ordering, and the commit trace end to end using the
# shell provider — no API keys or network access required.
run: pytest user_tests/test_mission_e2e.py -v
env:
CLK_PROVIDER: shell
CLK_WORKSPACES_DIR: /tmp/clk-workspaces

webui:
name: Web UI (build + unit tests)
runs-on: ubuntu-latest
Expand Down
158 changes: 152 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,19 @@ committed automatically.

If you've used CLK before, the highlights of this release:

- **Autonomous missions — one prompt to done.** `clk run` (and the TUI's first
message) now drive the whole lifecycle autonomously: the chief writes a
**charter**, authors a **living plan**, and walks discovery → … →
deployment through chief-evaluated phase gates to a **code-gated** done.
Reliability is enforced, not hoped for: a machine-checkable **done-gate**
(tests/qa/ralph/deliverables, adaptive for test-less projects) makes
`ACTION:done` a *request*; a **no-op guard** re-dispatches stages that changed
no files; evaluation **auto-derives** a real command instead of vacuously
passing; refinement is on for every producing stage by default; agents
**deliberate** (blocking Q&A + self-reflection); and every boundary leaves a
structured **git commit trace** with a per-cycle telemetry line. Use
`clk mission "<idea>"` for the explicit form or `clk run --once` for a single
cycle. See [Autonomous missions](#autonomous-missions).
- **Web dashboard (`clk web`).** A beautiful browser UI that mirrors the
TUI: configure every feature and `.env` setting, kick off workflows,
and watch the agents work in real time with live cards, a colour-coded
Expand Down Expand Up @@ -1247,9 +1260,12 @@ quality. Use this table to pick a regime:
| Knob | Worst-case multiplier per affected dispatch | Recommended starting point |
|----------------------------------------|--------------------------------------------------------------------------|----------------------------|
| `robustness.auto_consensus` | `off` → ×1; `on_careful` → ×(N+1) on careful stages only; `always` → ×(N+1) on every dispatch (where N = `consensus.max_samples`, default 6) | `on_careful` (default) |
| `robustness.auto_refine` | `off` → ×1; `careful_only` → ×(1 + 1 worker revision + 1 critic) on careful stages; `all` → that on every stage | `careful_only` (default) |
| `robustness.max_quality_retries` | At most this many extra dispatches when a response fails the quality check; 0 disables | 2 (default) |
| `robustness.refine_max_rounds` | Cap on critic↔worker round-trips inside a refine loop | 3 (default) |
| `robustness.auto_refine` | `off` → ×1; `careful_only` → ×(1 + 1 worker revision + 1 critic) on careful stages; `all` → that on every producing stage | `all` (default — every producing stage refines) |
| `robustness.max_quality_retries` | At most this many extra dispatches when a response fails the quality check; 0 disables | 4 (default) |
| `robustness.refine_max_rounds` | Cap on critic↔worker round-trips inside a refine loop | 10 (default) |
| `robustness.debate` | `off` → ×1; `careful_only` → an adversarial panel (one critic per lens) on careful stages; `all` → on every producing stage | `careful_only` (default) |
| `robustness.debate_lenses` | Adversarial lenses (one parallel critic each) — more lenses = more critic dispatches per round | `[correctness, security, simplicity]` |
| `robustness.debate_max_rounds` | Cap on debate rounds (panel critique + worker revision) per stage | 2 (default) |
| `robustness.max_qa_depth` | Cap on inter-agent Q&A chain depth (each peer answer can ask one peer) | 3 (default) |
| `robustness.plateau_window` | How many no-improvement Ralph/autoresearch iterations before escalation | 3 (default) |
| `robustness.plateau_action` | `off` disables adaptive loop termination entirely | `escalate_then_reframe` |
Expand Down Expand Up @@ -1660,6 +1676,98 @@ blackboard) so `git log` in the kickoff dir tells the project's story
without harness chatter. Deleting `.clk/` resets the harness without
touching the project tree.

## Autonomous missions

Give CLK one objective and it drives the **whole lifecycle to a code-gated
"done" on its own** — no babysitting with separate `plan` / `run` / `loop`
commands. This is the plan→execute→evaluate→refine→iterate loop made
*reliable*: the guarantees that used to live only in prompt text are now
enforced in the harness.

**Autonomy is the default.** `clk run` (and the TUI's first message, and the
web/REST single-prompt flow) drive the full mission. `clk mission "<idea>"`
(alias `clk auto`) is the explicit form; `clk run --once` restores the legacy
single-workflow pass.

```bash
clk mission "a local-first journaling app that summarizes my week"
# charter → plan → discovery → product → engineering(+ralph) → validation
# → deployment → done-gate → done_granted.md
```

### Charter first, then a living plan

1. **Charter** — before any work, the chief authors `.clk/state/charter.md`
(+ `charter.json`): mission statement, scope, explicit non-goals, success
criteria, constraints. The plan and the done-gate are *derived from it*, so
"done" is judged against an up-front commitment instead of drifting.
2. **Living plan** — the chief emits a `PROPOSE_PLAN` block; the harness
persists an ordered phase plan to `.clk/state/mission.json` (human mirror
`MISSION.md`). After each phase a chief **phase-gate** returns
`pass | repeat | revise | done`; `revise` re-plans the remaining phases, so
the chief can reorder, insert, or skip phases as it learns.

Three nested loops: the per-stage **supervise/ralph** loops (unchanged) inside a
per-phase **repeat** loop inside the **phase-sequencing** loop — bounded by
`mission.max_phases` and `mission.max_total_cycles`.

### Reliability reinforcements (enforced in code, not prose)

- **Machine-checkable done-gate.** `ACTION:done` / `done.md` is now a *request*.
The loop only stops when `done_gate.evaluate_done_gate` passes and writes
`.clk/state/done_granted.md`. Default checks: tests green, deliverables on
disk, a `POST: qa` PASS, a ralph refinement pass, plus any file-named charter
success criteria. **Adaptive:** the tests-green check is auto-relaxed when no
real test command can be derived (docs / research / content projects), so the
gate is strict where it's meaningful but never deadlocks. Each `require_*` is
an independent switch; `done_gate.enabled: false` restores legacy behavior.
- **No-op guard.** A producing stage (engineer/ralph, or any stage with an
`outputs` contract) whose response changed **no files** is re-dispatched with
an escalating "emit ACTION blocks now" preamble — descriptions stop counting
as work. Kill: `noop_guard.enabled: false`.
- **Evaluation never silently skips.** A producing stage with no `validation:`
no longer auto-passes — the harness derives a real command from the project
shape (`pytest` / `npm test` / a `compileall` smoke). Kill:
`validation.auto_derive: false`.
- **Ungated refinement.** `robustness.auto_refine` defaults to `all`, so every
producing stage gets a critic pass without the chief having to mark it
`careful`.
- **Deliberation — the team thinks.** Producing dispatches get a
self-reflect preamble and an invitation to ask peers
`POST: question TO: <peer> URGENCY: blocking`; a phase gate cannot `pass`
while a blocking question is unanswered. Kill: `deliberation.enabled: false`.
- **Execution trace.** Structured `[clk:charter|plan|phase-start|phase-gate:*|done]`
commits land at every boundary, so the git log *is* the audit trail. Kill:
`mission.commit_trace: false`.
- **Observability.** Each cycle prints a one-line summary and writes a
`loop_cycle_summary` event to `.clk/logs/activity.jsonl`, e.g.
`cycle 3/60 | phase engineering | stages 5 (4 ok) | actions 7 | refine 1r | eval FAIL(2) | done-gate REJECT(no_qa_pass)`.

### Mission config (`clk.config.json`)

```jsonc
"mission": { "max_phases": 12, "max_iterations_per_phase": 3,
"max_total_cycles": 60, "phase_gate": true,
"refine_required": true, "charter_first": true,
"commit_trace": true, "telemetry_stdout": true,
"default_phases": ["discovery","product","engineering","validation","deployment"] },
"done_gate": { "enabled": true, "require_tests_green": true,
"require_deliverables": true, "min_deliverable_files": 1,
"require_qa_pass": true, "require_ralph_pass": true,
"forbid_todo_markers": false },
"noop_guard": { "enabled": true, "max_redispatch": 2,
"producing_agents": ["engineer","ralph"] },
"deliberation": { "enabled": true, "encourage_questions": true,
"require_open_questions_resolved": true,
"self_reflect_preamble": true, "min_debate_rounds": 1 }
```

Every knob above is also overridable from the environment via the matching
`CLK_MISSION_*`, `CLK_DONE_GATE_*`, `CLK_NOOP_GUARD_*`, and
`CLK_DELIBERATION_*` variables (see `.env.example`; `kickoff.sh` maps them into
`clk.config.json`). CLI overrides: `clk run --max-phases N --max-cycles M`,
`clk run --once`, `clk mission "<idea>" --resume` (continue a persisted plan).

## Chief supervisor loop

The default `engineering` workflow ends with a `supervise` stage where
Expand Down Expand Up @@ -1992,8 +2100,8 @@ decides whether one round runs anyway:
| `auto_refine` | Behavior |
|----------------------------|---------------------------------------------------------|
| `off` | Only stages with `refine:` use the inner loop. |
| `careful_only` *(default)* | Stages marked `careful: true` get one critic pass. |
| `all` | Every non-chief, non-qa, non-critic stage gets one pass.|
| `careful_only` | Stages marked `careful: true` get one critic pass. |
| `all` *(default)* | Every non-chief, non-qa, non-critic stage gets a critic pass — so refinement fires without relying on the chief marking stages careful. |

The critic's last two lines must be:

Expand Down Expand Up @@ -2048,14 +2156,52 @@ iteration is recorded with `improved=False`.
`autoresearch_step_skipped_low_quality`, `autoresearch_revert`
- Kill switch: `robustness.plateau_action: "off"`

### 11. Adversarial debate panel (new)

Instead of a single critic, a stage can be refined by a **panel of
adversarial critics** that each take a distinct lens, try to *break* the work,
and engage with each other across rounds before the worker revises. This
catches failure modes a single reviewer misses (a correctness reviewer won't
think like a security reviewer).

Each round fans out one critic per lens **in parallel** (reusing the
`critic` agent with a lens-specific adversarial prompt); the worker output is
kept only when a **majority of lenses accept** and the mean score clears
`refine_accept_threshold`. Otherwise the combined critiques drive a revision,
and the next round's critics see the prior panel transcript (posted to the
blackboard as `post_type: debate`) so they can reinforce, refute, or concede
each other's points. Bounded by `debate_max_rounds`.

```yaml
- id: implement
agent: engineer
refine:
mode: debate
critics: [correctness, security, performance]
max_rounds: 2
objective: Implement the slice.
```

When a stage has no explicit `refine: {mode: debate}`, `robustness.debate`
decides whether the panel runs anyway (`off` | `careful_only` *(default)* |
`all`). The debate panel takes precedence over the single-critic loop
(layer 9) when both would apply. Built-in lenses: `correctness`, `security`,
`simplicity`, `performance`, `robustness`, `tests`, `ux` (configure via
`robustness.debate_lenses`).

- Code: `workflow.py::WorkflowRunner._debate_loop` / `_dispatch_lens_critic`
- Config: `robustness.{debate, debate_lenses, debate_max_rounds}`
- Logged events: `debate_round`
- Kill switch: `robustness.debate: "off"` AND remove any `refine: {mode: debate}` blocks.

### Putting it together

A typical "careful" engineering stage now runs:

1. Stage dispatched with `careful: true`.
2. `auto_consensus=on_careful` → N samples fan out in parallel.
3. Chief coalesces the samples.
4. `auto_refine=careful_only` → critic scores the coalesced output;
4. `auto_refine=all` (default) → critic scores the coalesced output;
the worker is revised until critic accepts or `max_rounds`.
5. Stage validation runs.
6. Checkpoint (if enabled) — chief CONTINUE / REDIRECT / ABORT
Expand Down
2 changes: 1 addition & 1 deletion clk_harness/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def get_bind_port() -> int:
return DEFAULT_PORT


COMMANDS = ["init", "idea", "plan", "run", "loop", "status"]
COMMANDS = ["init", "idea", "plan", "run", "mission", "auto", "loop", "status"]
MAX_TASK_LINES = 10_000


Expand Down
Loading
Loading