Skip to content

cxfcxf/siegclaw

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Siegclaw

Siegclaw is a lightweight Rust orchestrator for request-driven coding automation.

Quickstart: docs/quickstart.md Architecture Diagram (SVG): docs/architecture.svg

What It Does

Given an initial request prompt, Siegclaw:

  • loads a flow pack (flow.json, prompts, optional skills, optional agent definitions),
  • starts a local OpenCode server process,
  • runs flow steps through OpenCode in a bounded controller loop,
  • validates structured output plus controller-observable postconditions,
  • stops on verified completion or iteration failure.

Siegclaw no longer runs its own native LLM + shell tool loop. OpenCode is now the coding engine.

Runtime Architecture

  • Siegclaw: supervision, prompt composition, state binding, verification, process control
  • OpenCode server: coding execution, model/tool use, delegation, repository actions
  • Flow pack: workflow schema, prompts, optional specialist agent definitions, optional skills
  • External tools: MCP servers, shell commands, CLIs, HTTP targets, SSH targets, Docker, etc.

In this repo, Siegclaw starts OpenCode server in the same container/process namespace using:

opencode serve --hostname <host> --port <port>

<host>/<port> are derived from OPENCODE_URL (default http://127.0.0.1:4096).

High-Level Lifecycle

  1. Read config, load mcp.json, and load flow.json.
  2. Load flow-local skills and optional flow-local agent definitions.
  3. Inject MCP servers into OpenCode config (opencode.json) as local MCP tools.
  4. Start local OpenCode server.
  5. Build the system prompt from soul.md + optional policy.md + active skills + optional flow-defined agents + task context.
  6. Execute flow steps in order from flow.json.
  7. For each step, run retries (first then retry) until schema validation and controller verification both pass or max_attempts is exhausted.
  8. Stop OpenCode server.
  9. Exit non-zero on unrecoverable errors.

Key Files

  • src/main.rs
    • CLI entrypoint
    • run/doctor mode dispatch
    • local OpenCode process startup/shutdown
  • src/opencode.rs
    • OpenCode HTTP client (/global/health, /session, /session/:id/message, /session/:id/diff)
  • src/engine.rs
    • step loop
    • retry handling
    • schema + verification gating
  • src/verification.rs
    • controller-run verification rules
    • local/ssh/http/docker probes
  • src/state.rs
    • runtime state store
    • payload-to-state binding
  • src/prompting.rs
    • prompt loading
    • prompt context rendering
  • src/capabilities.rs
    • flow-local/global skill loading
    • optional flow-defined agent loading
  • src/readiness.rs
    • MCP config parsing + startup readiness checks (required MCP servers and OpenCode tool visibility)
  • src/config.rs
    • CLI/env config parsing
    • doctor subcommand parsing

Configuration

CLI:

siegclaw --init-prompt "read jira ticket TEST-1 and do the work" \
  [--workdir /workspace] \
  [--mcp-config mcp.json] \
  --flow /path/to/flow/dir \
  [--soul /path/to/soul.md] \
  [--skills-dir /path/to/skills] \
  [--max-iterations 6] \
  [--opencode-url http://127.0.0.1:4096] \
  [--opencode-session-id SESSION_ID] \
  [--opencode-agent AGENT] \
  [--opencode-model MODEL] \
  [--opencode-stream-events] \
  [--opencode-stream-heartbeat] \
  [--log-prompts] \
  [--opencode-home /path/to/opencode/home] \
  [--opencode-auth-json '{...}'] \
  [--opencode-auth-json-path /path/to/auth.json] \
  [--opencode-config-json '{...}'] \
  [--opencode-config-json-path /path/to/opencode.json]

# validate a flow pack without starting OpenCode
siegclaw doctor --flow /path/to/flow/dir [--skills-dir /path/to/skills] [--mcp-config mcp.json]

OpenCode connection env:

  • SIEGCLAW_INIT_PROMPT
  • OPENCODE_URL
  • OPENCODE_SESSION_ID
  • OPENCODE_AGENT
  • OPENCODE_MODEL
  • OPENCODE_STREAM_EVENTS (true/false, default false)
  • OPENCODE_STREAM_HEARTBEAT (true/false, default false)
  • OPENCODE_SERVER_USERNAME
  • OPENCODE_SERVER_PASSWORD
  • OPENCODE_HOME
  • SIEGCLAW_FLOW_DIR (equivalent to --flow)
  • SIEGCLAW_LOG_PROMPTS (true/false, default false)

OpenCode config/auth injection env:

  • OPENCODE_AUTH_JSON
  • OPENCODE_AUTH_JSON_PATH
  • OPENCODE_CONFIG_JSON
  • OPENCODE_CONFIG_JSON_PATH

Notes:

  • If OPENCODE_HOME is not set, Siegclaw uses <workdir>/.opencode-home.
  • If auth/config JSON env/path is provided, Siegclaw writes:
    • ~/.local/share/opencode/auth.json
    • ~/.config/opencode/opencode.json under the selected OpenCode home.
  • If --mcp-config is provided, Siegclaw injects those servers into opencode.json under the mcp key so OpenCode can call them directly.

soul.md as System Prompt

--soul (or default ~/.siegclaw/soul.md) is the global base system prompt for OpenCode. Use it for cross-flow invariants (quality/safety/validation honesty and communication style), not flow-specific policy.

Siegclaw renders these template variables in soul.md before sending the system prompt:

  • {{REQUEST_ID}}
  • {{REQUEST_SUMMARY}}
  • {{REQUEST_DESCRIPTION}}
  • {{WORKDIR}}

Example snippet in soul.md:

Validation policy:
- Never mark compile/tests as passed unless actually observed.

Required Flow Pack (--flow)

Siegclaw requires a flow pack directory. Full schema reference: docs/flow-schema.md

CLI:

--flow /path/to/flow/dir

A flow pack contains:

  • flow.json (canonical JSON flow definition)
  • optional policy.md (referenced by policy_prompt)
  • prompt files referenced by flow.json
  • optional skills/ for flow-local skill prompts
  • optional agents/ for flow-defined specialist agent prompts
  • example specialist agent: flows/jira-flow/agents/jira-agent.md

Shipped flow:

  • flows/jira-flow/
  • flows/deploy-flow/
  • flows/k8s-deploy-flow/
  • In Docker, mount flows/ from host and point --flow at that mounted path.

Notes:

  • step names are dynamic; they are not hardcoded in Rust.
  • each step can set max_attempts; if omitted, Siegclaw uses --max-iterations.
  • flow defaults may define agent, skills, and allowed_subagents.
  • flows may optionally define top-level agents with prompt files for specialist nested-agent patterns.
  • each step may override agent and extend skills / allowed_subagents.
  • each step may export payload values into controller state via bind.
  • each step may declare controller-run verification rules.
  • each step block supports:
    • system (optional)
    • first (required)
    • retry (optional)
    • response_marker (optional)
    • response_json_template (optional)
  • flow-local skills are loaded from <flow>/skills before user/global skill directories.
  • policy_prompt content is injected into the system prompt before skills/task blocks.
  • prerequisites.required_mcp_servers is validated against loaded mcp.json.

Prompt Layering

Siegclaw builds each step prompt from a layered context:

  1. soul.md (global, cross-flow invariants)
  • identity/voice
  • quality and safety standards
  • validation honesty
  1. policy.md (flow-wide policy)
  • phase ordering and ownership model
  • flow-specific policy and workflow rules
  1. active capability blocks
  • selected skills
  • optional flow-defined specialist agents referenced by allowed_subagents
  1. task + step context
  • current request data
  • bound controller state
  • retry feedback
  • current step prompt (first / retry / optional system)

Flow capability routing:

  • agent selection resolves in this order: step override -> flow default -> CLI --opencode-agent
  • skills resolve per step; if the flow does not specify skills, Siegclaw injects no skills for that step
  • allowed_subagents are injected into the current step system prompt as scoped delegation capabilities
  • if an allowed subagent matches a flow-defined agent, Siegclaw injects that agent definition into the system prompt for the current step
  • bind exports response values into controller state for later prompts and verifiers
  • step verification rules run in Siegclaw after the agent replies; controller evidence can block step completion and trigger retries
  • generic probe verification lets a flow define controller-observable postconditions such as SSH checks on a deployed server
  • when lets flows express conditional postconditions like “only verify smoke test URL when it is present” or “only require rollout checks when changes were made”
  • all / any let flows compose postconditions without hardcoding branching logic into Rust
  • doctor validates flow.json, prompt references, flow-local skills, configured skills, and MCP prerequisite references before runtime

Verifier notes:

  • local verifiers now include git_branch, git_status, and git_remote
  • provider-backed verifiers include github_pr and jira_issue_status
  • provider-backed checks require controller-side credentials (GITHUB_TOKEN for GitHub, JIRA_BASE_URL / JIRA_USER_EMAIL / JIRA_API_TOKEN for Jira)
  • probe transports now include local, ssh, http, and docker_exec
  • probe assertions now include HTTP body and JSON-path checks in addition to exit/stdout/stderr checks
  • non-HTTP probes can also use JSON-path assertions against stdout, plus negated/numeric comparisons like stdout_not_contains and stdout_json_path_number_compare

Doctor

Use doctor to validate a flow pack before runtime:

siegclaw doctor --flow /path/to/flow/dir --mcp-config mcp.json [--skills-dir /path/to/skills]

doctor checks:

  • flow.json parses and validates
  • referenced prompt files exist
  • flow-local and configured skills resolve
  • optional flow-defined agent prompts resolve
  • MCP prerequisites referenced by the flow exist in mcp.json

Prompt/state notes:

  • bound state values are available to prompts through generic placeholders like {{namespace}}, {{state.namespace}}, or uppercase aliases like {{NAMESPACE}}
  • probe commands, URLs, headers, bodies, and literal assertions also support {{...}} interpolation from payload/state values

Internal Request ID

  • Siegclaw derives internal run IDs as:
    • <FLOW_NAME>-MMHHMMSS
  • Example:
    • JIRA-FLOW-V2-03101542
  • This is internal run identity and fallback context, not external Jira ticket identity.
  1. steps/*.md (step-local prompts)
    • what to do in that step
    • what not to do in that step
    • exact output marker + JSON contract

MCP Configuration

Minimal shape:

{
  "mcpServers": {
    "jira": {
      "command": "...",
      "args": ["..."],
      "env": {}
    },
    "github": {
      "command": "...",
      "args": ["..."],
      "env": {}
    }
  }
}
  • Use MCP server env for Jira/GitHub credentials.
  • Jira/GitHub MCP tools are called directly by OpenCode (not by Siegclaw).
  • mcp.example.json is wired to the official GitHub MCP server binary:
    • command: github-mcp-server
    • args: ["stdio"]
    • transport: "jsonl"
    • env: GITHUB_PERSONAL_ACCESS_TOKEN
  • For local (non-Docker) runs, install it with:
    • go install github.com/github/github-mcp-server/cmd/github-mcp-server@latest
  • This repo includes:
    • mcp.mock-jira.json
    • mcp.example.json
    • mock/mock_jira_mcp.py

GitHub PAT Permissions (Fine-Grained)

For flows that create branches/files/PRs on GitHub, the GitHub MCP token must allow:

  • Contents: Read and write
  • Pull requests: Read and write
  • Metadata: Read-only (required by GitHub)

If Contents is read-only, branch creation and file updates will fail with 403 Resource not accessible by personal access token.

Logging

JSON structured logs by default.

Primary sources:

  • CORE, AGENT, MCP, OPENCODE

Controller loop behavior:

  • Siegclaw executes each step in flow.json sequentially.
  • For each step attempt:
    • renders prompt placeholders
    • auto-injects response_marker + response_json_template contract (if configured)
    • validates returned JSON against the step template
  • On retry, Siegclaw injects controller feedback and previous response context.
  • Flow completes when all steps pass their configured contract.
  • After each completed step, Siegclaw logs AGENT event=step_completion_verified with:
    • verified response values used to advance, or
    • considered completed since no JSON values are defined for this step.
  • Stream behavior:
    • By default, OpenCode stream event logs are off.
    • Use --opencode-stream-events (or OPENCODE_STREAM_EVENTS=true) to emit OpenCode event/activity logs.
    • With stream events enabled, Siegclaw logs concise activity summaries (event=stream_activity) and OpenCode request/response events.
    • Heartbeat/noise events (session.idle, session.busy, session.diff) are hidden by default.
    • Use --opencode-stream-heartbeat together with --opencode-stream-events to include heartbeat activity logs.
    • Right before stopping the local OpenCode process, Siegclaw logs final aggregate token usage as OPENCODE event=session_usage_summary.
  • Prompt logging behavior:
    • By default, rendered prompts are not logged.
    • Use --log-prompts (or SIEGCLAW_LOG_PROMPTS=true) to log full rendered system_prompt and user_prompt per step attempt (AGENT event=step_prompt_dump).

Permission behavior:

  • Siegclaw writes a default opencode.json with permission: "allow" when no config is provided, so OpenCode runs non-interactively by default inside the container sandbox.
  • If you provide OPENCODE_CONFIG_JSON or OPENCODE_CONFIG_JSON_PATH, your config is used as the base and Siegclaw merges/injects MCP servers from --mcp-config.

Docker

Dockerfile builds siegclaw and installs runtime dependencies including OpenCode CLI.

Build:

docker build -t siegclaw:dev .

Run:

docker run --rm -it \
  -v "$PWD":/workspace \
  -w /workspace \
  -e OPENCODE_URL=http://127.0.0.1:4096 \
  siegclaw:dev \
    --init-prompt "read jira ticket TEST-1 and do the work" \
    --mcp-config /workspace/mcp.example.json \
    --flow /workspace/flows/jira-flow

Ephemeral run (no repository persistence on host):

docker run --rm -it \
  -v "$PWD/mcp.json":/run/config/mcp.json:ro \
  -v "$PWD/flows":/run/flows:ro \
  -v "$PWD/mock":/run/mock:ro \
  -v "$HOME/.local/share/opencode/auth.json":/run/secret/auth.json:ro \
  -v "$HOME/.config/opencode/opencode.json":/run/secret/opencode.json:ro \
  -w /run \
  -e OPENCODE_AUTH_JSON_PATH=/run/secret/auth.json \
  -e OPENCODE_CONFIG_JSON_PATH=/run/secret/opencode.json \
  siegclaw:dev \
    --init-prompt "read jira ticket TEST-1 and do the work" \
    --workdir /workspace \
    --mcp-config /run/config/mcp.json \
    --flow /run/flows/jira-flow

Notes:

  • Relative paths inside mcp.json are resolved against the mcp.json parent directory when they exist.
  • Using -v "$PWD":/workspace persists workspace state between runs.

Development

Requirements:

  • Rust stable
  • git
  • python3
  • node/npm

Commands:

cargo fmt
cargo test
cargo build

Exit Semantics

  • Exit 0: completed (validation + workflow criteria satisfied)
  • Exit non-zero: workflow failure (OpenCode, MCP bootstrap/config integration, flow response-template validation failure)

Limitations

  • OpenCode server is started as a local process; if startup fails, run fails.
  • Siegclaw does not inspect or manage repository state itself; flows must instruct OpenCode to report required lifecycle fields.
  • No persistent DB/state in Siegclaw.

About

Siegclaw is a lightweight Rust orchestrator for request-driven coding automation.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors