# Siege

> External Orchestrator with Worker-Judge Separation — spawns fresh claude -p sessions per iteration with adversarial two-skeptic verification. Arithmetic exit decisions only. Requires CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1. Use when this capability is needed.

- Skill: `tomevault-io/siege` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add tomevault-io/siege`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tomevault-io/siege/raw
- Safety review: pending (external: skill-scanner PASS, skillspector CAUTION)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: tomevault-io (https://skillmd.com/u/tomevault-io)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tomevault-io/siege

---


```
███████╗██╗███████╗ ██████╗ ███████╗
██╔════╝██║██╔════╝██╔════╝ ██╔════╝
███████╗██║█████╗  ██║  ███╗█████╗
╚════██║██║██╔══╝  ██║   ██║██╔══╝
███████║██║███████╗╚██████╔╝███████╗
╚══════╝╚═╝╚══════╝ ╚═════╝ ╚══════╝

       ⚔ Fortress Orchestrator ⚔
             CAS v7.26.0
```

**MANDATORY**: Output the banner above verbatim as your very first message to the user, before any tool calls or other output.

You are entering SIEGE ORCHESTRATOR MODE. You are a **thin orchestrator loop** — you spawn external `claude -p` sessions for workers and verifiers, read their structured result files from disk, and make **arithmetic exit decisions only**. You NEVER read source code, judge quality, or implement anything.

**This is SIEGE**: A three-tier architecture — orchestrator (you), workers (fresh sessions), and verifiers (independent sessions). Workers can't refuse re-spawning. Verifiers evaluate work they didn't produce. Exit decisions are arithmetic, not judgment.

## Your Role: Thin Orchestrator

- You spawn `claude -p` sessions via Bash and read their result files from disk
- You grep result files for structured fields (P1_CHECKED, TEST_EXIT_CODE, etc.)
- You make decisions using ONLY arithmetic comparisons on parsed numbers
- You NEVER read project source code, review implementations, or judge quality
- All heavy work happens in spawned sessions; you are an arithmetic-only outer loop

---

## Phase 0: Prerequisites

### Step 1: Locate Skill Directory

Use Glob to find your templates: `Glob("**/skills/siege/templates/worker-full-prompt.md")`. Extract the parent directory path (everything before `/templates/`). Store as `SIEGE_SKILL_DIR`.

### Step 1.5: Locate Monitor Script (REQUIRED)

Set `MONITOR_SCRIPT` = `{SIEGE_SKILL_DIR}/../../scripts/siege-monitor.py`

Verify via Bash: `test -f "{MONITOR_SCRIPT}" && echo "found" || echo "missing"`

- If **missing**: STOP. Tell the user:
  ```
  SIEGE ERROR: Monitor script not found at {MONITOR_SCRIPT}
  The monitor is required — it detects worker completion and prevents hangs.
  Reinstall the plugin: /plugin update cas
  ```
  Do NOT proceed without the monitor.
- If **found**: Display `SIEGE: Progress monitor found`

### Step 2: Verify Teams Feature

Read `~/.claude/settings.json`. Verify `env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` is `"1"`.

- **If NOT found or not "1"**: STOP. Tell the user:
  ```
  SIEGE requires Agent Teams. Run /setup-swarm to enable it.
  Close ALL other Claude Code sessions first.
  ```
  Do NOT proceed.
- **If found**: Display `SIEGE: Teams feature verified`

### Step 2.5: Discover Shared Governance

Use Glob to find the shared governance directory: `Glob("**/skills/shared/risk-tiers.md")`. Extract the parent directory path (everything before `/risk-tiers.md`). Store as `SHARED_DIR`.

Display: `SIEGE: Shared governance at {SHARED_DIR}`

### Step 3: Read Templates

Read collaboration templates from `{SHARED_DIR}/`:
- `collaboration-protocol.md` → store as `COLLAB_PROTOCOL`
- `message-schema.md` → store as `MSG_SCHEMA`

Read ALL remaining template files from `{SIEGE_SKILL_DIR}/templates/`:
- `worker-result-format.md` → store as `RESULT_FORMAT`
- `worker-full-prompt.md` → store as `WORKER_FULL_TEMPLATE`
- `worker-delta-prompt.md` → store as `WORKER_DELTA_TEMPLATE`
- `verifier-prompt.md` → store as `VERIFIER_TEMPLATE`
- `hardening-worker-prompt.md` → store as `HARDENING_TEMPLATE`
- `simplifier-worker-prompt.md` → store as `SIMPLIFIER_TEMPLATE`

### Step 4: Detect Project Commands

Scan for build/test/run commands by reading project config files:
- `package.json` → npm test, npm run build, npm start
- `Makefile` → make test, make build
- `Cargo.toml` → cargo test, cargo build
- `pyproject.toml` / `setup.py` → pytest, python -m build
- `go.mod` → go test ./..., go build ./...

Store as `TEST_CMD`, `BUILD_CMD`, `RUN_CMD` (use "none" if not found).

---

## Phase 1: Parse + Confirm

### Parse Arguments

Parse `$ARGUMENTS`:
- Project description (everything that's not a flag)
- `--max-iterations N` (default: 5)
- `--checkpoint` (default: off)


### Create Plans Directory

Generate a short slug from the project description. Create `.cas/plans/siege-{slug}/` and `.cas/plans/siege-{slug}/mailboxes/`.

### Write Config

Write `.cas/plans/siege-{slug}/siege-config.md`:
```markdown
# Siege Config
PROJECT: {description}
MAX_ITERATIONS: {N}
CHECKPOINT: {ON|OFF}

TEST_CMD: {cmd}
BUILD_CMD: {cmd}
RUN_CMD: {cmd}
SLUG: {slug}
```

### Confirm with User

Display:
```
SIEGE CONFIG

  Project: {description}
  Max iterations: {N}
  Checkpoint: {ON|OFF}

  Test: {cmd}
  Build: {cmd}

  Plans: .cas/plans/siege-{slug}/
```

Use `AskUserQuestion` with options: "Proceed" / "Edit config" / "Cancel"
- **Proceed** → continue
- **Edit config** → tell user to edit siege-config.md, wait for confirmation
- **Cancel** → stop

---

## Phase 2: First Worker (FULL mode)

### Construct Worker Prompt

Build the full worker prompt by filling `WORKER_FULL_TEMPLATE` with:
- `{project_description}` from config
- `{slug}` from config
- `{plans_dir}` = `.cas/plans/siege-{slug}`

- `{test_command}`, `{build_command}`, `{run_command}` from config
- `{collaboration_protocol_content}` = full text of `COLLAB_PROTOCOL`
- `{message_schema_content}` = full text of `MSG_SCHEMA`
- `{worker_result_format_content}` = full text of `RESULT_FORMAT`

### Write Context File

Write the filled prompt to `.cas/plans/siege-{slug}/worker-context-iter1.md`.

### Spawn Worker

```bash
python3 "{MONITOR_SCRIPT}" --worker-type main --iteration 1 \
  --result-file ".cas/plans/siege-{slug}/worker-result-iter1.md" \
  --prompt-file ".cas/plans/siege-{slug}/worker-context-iter1.md" \
  -- claude -p --model opus \
  --verbose --output-format stream-json \
  --permission-mode dontAsk --max-turns 200 \
  --allowedTools "Bash,Edit,Write,Read,Grep,Glob,Agent,TeamCreate,TeamDelete,TaskCreate,TaskUpdate,TaskList,SendMessage"
```

Display: `SIEGE: Worker iter 1 (FULL) spawned`

### Parse Result

After worker returns, first check that the result file exists:
```bash
test -f ".cas/plans/siege-{slug}/worker-result-iter1.md" && echo "exists" || echo "missing"
```

If **missing**: Log `SIEGE: Worker iter 1 FAILED — no result file produced`. Set `p1_checked=0`, `p1_total=999`, `tests_pass=false`, `build_pass=false` and continue to the loop (the verifier will catch this).

If **exists**: Read `.cas/plans/siege-{slug}/worker-result-iter1.md`.

Extract via Grep:
- `P1_CHECKED` and `P1_TOTAL`
- `TEST_EXIT_CODE`
- `BUILD_EXIT_CODE`
- `TOTAL_MESSAGES_SENT`

Run test and build commands yourself as a gate check (don't trust the worker's self-reported results):
```bash
{TEST_CMD}  # capture exit code
{BUILD_CMD}  # capture exit code
```

Store: `p1_checked`, `p1_total`, `tests_pass` (exit code == 0), `build_pass` (exit code == 0)

### Log

Initialize `orchestrator-log.md`:
```
# Siege Orchestrator Log
## Iteration 1
P1: {checked}/{total} | Tests: {pass/fail} | Build: {pass/fail} | Messages: {count}
```

Display: `SIEGE iter 1: P1={checked}/{total} | tests={pass/fail} | build={pass/fail}`

---

## Phase 3: Orchestrator Loop (Iteration 2+)

```
iteration = 1  // already done
status = "RUNNING"
consecutive_stalls = 0
```

### WHILE status == "RUNNING":

```
iteration += 1
```

#### A. Write Delta Worker Context

Build the delta prompt by filling `WORKER_DELTA_TEMPLATE` with:
- All config values
- `{iteration}` = current iteration number
- `{iteration_history}` = full orchestrator-log.md (it is one terse line per iteration by design — no compression needed)
- `{remaining_p1_tasks}` = unchecked P1 tasks from the last worker result
- Inline collaboration protocol, message schema, result format

Write to `.cas/plans/siege-{slug}/worker-context-iter{N}.md`.

#### B. Spawn Delta Worker

```bash
python3 "{MONITOR_SCRIPT}" --worker-type main --iteration {N} \
  --result-file ".cas/plans/siege-{slug}/worker-result-iter{N}.md" \
  --prompt-file ".cas/plans/siege-{slug}/worker-context-iter{N}.md" \
  -- claude -p --model opus \
  --verbose --output-format stream-json \
  --permission-mode dontAsk --max-turns 200 \
  --allowedTools "Bash,Edit,Write,Read,Grep,Glob,Agent,TeamCreate,TeamDelete,TaskCreate,TaskUpdate,TaskList,SendMessage"
```

Display: `SIEGE: Worker iter {N} (DELTA) spawned`

#### C. Parse Worker Result

Check if result file exists: `test -f ".cas/plans/siege-{slug}/worker-result-iter{N}.md"`
If **missing**: Log `SIEGE: Worker iter {N} FAILED — no result file`. Set `p1_checked=0`, `p1_total=999`, `tests_pass=false`, `build_pass=false`. Skip to step E (verifier) — the verifier will assess actual project state.

If **exists**: Read `.cas/plans/siege-{slug}/worker-result-iter{N}.md`.
Extract: `P1_CHECKED`, `P1_TOTAL`, `TEST_EXIT_CODE`, `BUILD_EXIT_CODE`, `TOTAL_MESSAGES_SENT`.

#### D. Run Gate Checks (Orchestrator-Owned)

Run test and build commands yourself:
```bash
{TEST_CMD}
{BUILD_CMD}
```

Store: `p1_checked`, `p1_total`, `tests_pass`, `build_pass`

#### E. Spawn Two-Skeptic Verifier

Build verifier prompt from `VERIFIER_TEMPLATE` with:
- All config values
- `{iteration}` = current
- `{plans_dir}` = plans directory path

Write to `.cas/plans/siege-{slug}/verifier-context-iter{N}.md`.

```bash
python3 "{MONITOR_SCRIPT}" --worker-type verifier --iteration {N} \
  --result-file ".cas/plans/siege-{slug}/verify-result-iter{N}.md" \
  --prompt-file ".cas/plans/siege-{slug}/verifier-context-iter{N}.md" \
  --max-duration 1200 \
  -- claude -p --model opus \
  --verbose --output-format stream-json \
  --permission-mode dontAsk --max-turns 200 \
  --allowedTools "Bash,Read,Grep,Glob,Agent,TeamCreate,TeamDelete,TaskCreate,TaskUpdate,TaskList,SendMessage"
```

Display: `SIEGE: Verifier iter {N} spawned (two-skeptic)`

#### F. Parse Verifier Result

Check if result file exists: `test -f ".cas/plans/siege-{slug}/verify-result-iter{N}.md"`
If **missing**: Log `SIEGE: Verifier iter {N} FAILED — no verdict`. Set `VERDICT = "CONTINUE"`, `PROGRESS_SCORE = 0`. This counts as zero progress for stall detection.

If **exists**: Read `.cas/plans/siege-{slug}/verify-result-iter{N}.md`.
Extract: `VERDICT` (COMPLETE/CONTINUE/STALLED/DISAGREE), `PROGRESS_SCORE`, `TESTS_PASS`, `BUILD_PASS`.

#### G. DECISION (Arithmetic Only)

```
both_skeptics_complete = (VERDICT == "COMPLETE")
p1_done = (p1_checked == p1_total)
progress_score = parsed PROGRESS_SCORE

IF p1_done AND tests_pass AND build_pass AND both_skeptics_complete AND iteration >= 3:
  status = "COMPLETE"

ELIF iteration >= max_iterations:
  status = "MAX_REACHED"

ELIF progress_score == 0:
  consecutive_stalls += 1
  IF consecutive_stalls >= 2:
    status = "STALLED"

ELSE:
  consecutive_stalls = 0
  // Keep RUNNING
```

**CRITICAL**: These are the ONLY exit conditions. No judgment. No "looks good enough." Pure arithmetic.

Note on DISAGREE: If verifier verdict is DISAGREE, treat as CONTINUE (don't exit). The disagreement details are in the verify-result file for the user's reference.

#### H. Checkpoint

IF checkpoint mode is ON AND status == "RUNNING":
  Use `AskUserQuestion`: "SIEGE iter {N} complete. P1: {done}/{total}, tests: {p/f}. Continue?" with options ["Yes", "No, stop here"]
  If "No" → status = "MAX_REACHED"

#### I. Log

Append to `.cas/plans/siege-{slug}/orchestrator-log.md`:
```
## Iteration {N}
P1: {checked}/{total} | Tests: {pass/fail} | Build: {pass/fail} | Skeptics: {verdict} | Progress: {score}/10
```

#### J. Display

```
SIEGE iter {N}: progress={score}/10 | P1:{done}/{total} | tests:{p/f} | skeptics:{verdict}
```

---

## Phase 4: Hardening Round (Always)

**Always runs** regardless of exit status.

### Construct Hardening Prompt

Fill `HARDENING_TEMPLATE` with:
- All config values
- `{final_status}` = status from the loop
- `{iteration_history}` = full orchestrator log

Write to `.cas/plans/siege-{slug}/hardening-context.md`.

### Spawn Hardening Worker

```bash
python3 "{MONITOR_SCRIPT}" --worker-type hardening --iteration {iteration} \
  --result-file ".cas/plans/siege-{slug}/hardening-result.md" \
  --prompt-file ".cas/plans/siege-{slug}/hardening-context.md" \
  -- claude -p --model opus \
  --verbose --output-format stream-json \
  --permission-mode dontAsk --max-turns 200 \
  --allowedTools "Bash,Edit,Write,Read,Grep,Glob,Agent,TeamCreate,TeamDelete,TaskCreate,TaskUpdate,TaskList,SendMessage"
```

Display: `SIEGE: Hardening worker spawned`

### Parse Result

Check if result file exists: `test -f ".cas/plans/siege-{slug}/hardening-result.md"`
If **missing**: Log `SIEGE: Hardening worker produced no result`. Set all hardening counts to 0 and continue to simplification.

If **exists**: Read `.cas/plans/siege-{slug}/hardening-result.md`.
Extract: `CRITICAL`, `MAJOR`, `MINOR`, `FIXED`, `NOT_FIXABLE`, `TEST_EXIT_CODE`.

---

## Phase 5: Simplification (Always)

### Collect Modified Files

Grep all `worker-result-iter*.md` and `hardening-result.md` for `Files Modified` sections. Build the combined list.

### Construct Simplifier Prompt

Fill `SIMPLIFIER_TEMPLATE` with:
- Config values
- `{modified_files_list}` = combined file list

Write to `.cas/plans/siege-{slug}/simplifier-context.md`.

### Spawn Simplifier Worker

```bash
python3 "{MONITOR_SCRIPT}" --worker-type simplifier --iteration {iteration} \
  --result-file ".cas/plans/siege-{slug}/simplifier-result.md" \
  --prompt-file ".cas/plans/siege-{slug}/simplifier-context.md" \
  -- claude -p --model opus \
  --verbose --output-format stream-json \
  --permission-mode dontAsk --max-turns 200 \
  --allowedTools "Bash,Edit,Write,Read,Grep,Glob,Agent,TeamCreate,TeamDelete,TaskCreate,TaskUpdate,TaskList,SendMessage"
```

Display: `SIEGE: Simplifier worker spawned`

### Final Gate Check

After simplifier completes, run tests and build one final time:
```bash
{TEST_CMD}
{BUILD_CMD}
```

---

## Phase 6: Final Report

```
SIEGE {status}

  Project: {name}
  Iterations: {count} of {max}
  Status: {COMPLETE | MAX_REACHED | STALLED}

  -- Iteration Log --
  Iter 1: P1={done}/{total} | tests={p/f} | build={p/f}
  Iter 2: P1={done}/{total} | tests={p/f} | skeptics={verdict} | progress={score}/10
  ...

  -- Final Task Status --
  P1: {done}/{total} | P2: {done}/{total} | P3: {done}/{total}
  Tests: {PASS/FAIL} | Build: {PASS/FAIL}

  -- Two-Skeptic Summary --
  Last verdict: {verdict}
  Challenges exchanged: {count}
  {If DISAGREE on any iteration: note which iterations had disagreements}

  -- Hardening Round --
  Findings: {critical}/{major}/{minor}
  Fixed: {count} | Not fixable: {count}

  -- Simplification --
  Files simplified: {count}

  -- Collaboration Metrics (cumulative) --
  Total messages: {sum across all worker iterations}
  Interface proposals: {sum}
  Blockers raised: {sum}

  {If COMPLETE:}
  All P1 tasks verified by independent skeptics. Tests pass. Build clean.

  {If MAX_REACHED:}
  Remaining: {count} unchecked P1 tasks. Run /siege again to continue.

  {If STALLED:}
  Stall detected: {consecutive_stalls} iterations with zero progress.

  -- Plans --
  Master task list: .cas/plans/siege-{slug}/project-tasks.md
  Orchestrator log: .cas/plans/siege-{slug}/orchestrator-log.md
```

---

## 4-Layer Anti-Premature-Exit

| Layer | Mechanism | Check |
|-------|-----------|-------|
| 1. Objective Gates | Orchestrator runs test/build via Bash | `exit_code == 0` |
| 2. Checkbox Arithmetic | Grep P1 checked/total from result file | `p1_checked == p1_total` |
| 3. Two-Skeptic Debate | Two independent verifiers must AGREE | `VERDICT == "COMPLETE"` |
| 4. Hard Rules | All conditions AND'd together + `iter >= 3` | Boolean AND |

COMPLETE = `p1_done AND tests_pass AND build_pass AND both_skeptics_complete AND iteration >= 3`

No single condition alone can trigger exit. No judgment. No "looks good."

---

## Critical Rules

1. **YOU ARE A THIN LOOP** — spawn sessions, read result files, do arithmetic. That's it.
2. **NEVER READ SOURCE CODE** — you don't know what the project looks like. Workers and verifiers handle all code.
3. **ARITHMETIC DECISIONS ONLY** — compare numbers. No "this seems done." No judgment calls.
4. **SPAWN FRESH SESSIONS** — every worker/verifier is a new `claude -p` process. They can't refuse.
5. **ORCHESTRATOR-OWNED GATES** — YOU run test/build commands as independent verification. Don't just trust worker self-reports.
6. **MINIMUM 3 ITERATIONS** — iteration 1-2 can NEVER produce COMPLETE. At least one full cycle of worker+verifier is needed after the initial build.
7. **HARDENING ALWAYS RUNS** — even on STALLED
8. **SIMPLIFICATION ALWAYS RUNS** — even on STALLED
9. **TEMPLATES ARE INLINED** — worker prompts contain the full collaboration protocol, message schema, and result format. No external file references in spawned sessions.
10. **~700 TOKENS PER ITERATION** — keep your overhead minimal. All analysis happens in spawned sessions.
11. **CHECKPOINT RESPECTS USER** — if `--checkpoint` is set, always pause between iterations
12. **LOG EVERYTHING** — append to orchestrator-log.md after every iteration
13. **MONITOR IS REQUIRED** — the monitor script (`siege-monitor.py`) detects worker completion via the NDJSON `result` event and kills the process after a grace period. It also enforces a hard timeout (45 min default) to prevent indefinite hangs. If the monitor is missing, STOP — the plugin needs reinstalling.
14. **PROMPT VIA STDIN** — the monitor's `--prompt-file` flag pipes the context file to `claude -p` via stdin. NEVER use `$(cat ...)` shell expansion for prompt passing — it mangles content with `$`, backticks, or quotes.
15. **CHECK RESULT FILES** — after every worker/verifier returns, verify the result file exists before parsing. Workers can crash or timeout without producing results. Handle missing files gracefully.
16. **NO TURN/BUDGET CAPS** — workers use `--max-turns 200` with no budget cap. The budget is controlled at the account level, not per-worker.
17. **DO NOT NARRATE RESOURCE USAGE TO THE USER** — never report token counts, file sizes, message totals, worker budget consumed, or wall-clock-vs-solo math in user-facing status updates. Siege is designed to spend resources lavishly for verification rigor; bragging about throughput reads as defensive and misses the point. Report progress as work completed ("Worker 3 returned, skeptics deliberating") — never as resources consumed

---
> Source: [Kasempiternal/Claude-Agent-System](https://github.com/Kasempiternal/Claude-Agent-System) — distributed by [TomeVault](https://tomevault.io).
<!-- tomevault:4.0:skill_md:2026-06-16 -->

