ChainWeaver CLI Reference

June 15, 2026 · View on GitHub

ChainWeaver ships a chainweaver console script built on typer.

chainweaver <command> [options]

Exit codes

All commands share the same top-level exit-code contract:

CodeMeaning
0Success / all flows valid
1Logic error: flow not found, validation failure, execution error, or malformed input
2Input file or directory not found

Machine-readable output (--format json)

The result-producing commands — inspect, validate, check, profile, diff, attest, and flows list — wrap their --format json payload in a stable, versioned envelope so automation and CI can branch on status / error codes instead of scraping human-readable text:

{
  "schema_version": "1",
  "status": "ok",
  "data": { "...": "command-specific payload" },
  "errors": [{ "code": "CW-E017", "message": "…" }]
}
  • schema_version versions the envelope itself — distinct from a flow's SemVer version and from the trace_schema_version of a trace. A MAJOR bump signals an incompatible envelope-shape change.
  • status is "ok" or "error"; on failure, errors carries {code, message} entries using the stable error codes.
  • Trace-bearing commands (profile, diff) include the source trace_schema_version in data.

run and dump-schema keep their existing (un-enveloped) JSON output.


Shell completion

The CLI ships tab-completion for bash, zsh, and fish (provided by typer). It covers every command and option. Install it once per shell:

chainweaver --install-completion          # auto-detect the current shell
chainweaver --show-completion bash        # print the script without installing

Restart your shell (or re-source its rc file) after installing.


Flow file format

The file-oriented commands (run, validate, check, doctor, attest, suggest) load a flow definition from disk. Accepted extensions are .flow.yaml, .flow.yml, and .flow.json.

Reading .flow.yaml / .flow.yml requires the YAML extra:

pip install 'chainweaver[yaml]'

.flow.json works with no extra. Without pyyaml, the YAML commands fail with FlowSerializationError: YAML support requires 'pyyaml' to be installed.

The type: discriminator

Every flow file must declare a top-level type: key — either Flow (linear) or DAGFlow (directed-acyclic). It tells the loader which model to build; without it you get:

chainweaver: Missing or invalid 'type' discriminator (got None); expected 'Flow' or 'DAGFlow'

A minimal hand-authored linear flow (examples/double_add_format.flow.yaml, shipped in the repo) looks like this:

type: Flow
name: double_add_format
version: "0.1.0"
description: Doubles a number, adds 10, and formats the result.
steps:
  - tool_name: double
    input_mapping:
      number: number
  - tool_name: add_ten
    input_mapping:
      value: value
  - tool_name: format_result
    input_mapping:
      value: value

The required fields are type, name, description, and steps; version defaults to "0.1.0" on Flow but is required on DAGFlow. See AGENTS.md §5 for the full field table. The --tools modules supply the actual Tool implementations referenced by tool_name.


Commands

inspect

Print the structure of a flow.

chainweaver inspect <flow_name> [--format table|json] [discovery flags]
FlagDefaultDescription
--format / -ftableOutput format: human-readable table or machine-readable JSON
--fileLoad the flow directly from a .flow.yaml / .flow.json file
--discover-dirDiscover flows by scanning a directory for .flow.* files
--discover-entry-pointsfalseDiscover flows from installed packages via the chainweaver.flows entry points

Without a discovery flag, the flow is resolved from the registry installed via set_default_registry (see Programmatic registration). Discovery precedence is --file--discover-dir--discover-entry-points → the default registry; a no-match error names the source consulted and the flows it found. Use chainweaver flows list to preview what is discoverable.

Exit codes: 0 = success, 1 = flow not found or no registry configured, 2 = a supplied file/directory does not exist.

Example:

chainweaver inspect my_etl_flow                          # from the default registry
chainweaver inspect my_etl_flow --discover-dir flows/    # no Python setup needed
chainweaver inspect my_etl_flow --file flows/etl.flow.yaml --format json
chainweaver flows list --discover-dir flows/             # see what is discoverable

viz

Render a flow as ASCII art, DOT (Graphviz), or Mermaid text.

chainweaver viz <flow_name> [--format ascii|dot|mermaid] [discovery flags]
chainweaver viz --result <trace.json> --format mermaid
FlagDefaultDescription
--format / -fasciiVisualization format: terminal-friendly ASCII, Graphviz DOT, or Mermaid
--resultRender an ExecutionResult JSON file as a Mermaid status/timing overlay (file-only; no registry or flow name needed). Requires --format mermaid
--fileLoad the flow directly from a .flow.yaml / .flow.json file
--discover-dirDiscover flows by scanning a directory for .flow.* files
--discover-entry-pointsfalseDiscover flows from installed packages via the chainweaver.flows entry points

Flow resolution works exactly like inspect. Mermaid renders natively on GitHub and MkDocs Material, so it is the lowest-friction format for PR descriptions and docs.

Exit codes: 0 = success, 1 = flow not found or no registry configured, 2 = usage error (no flow and no --result, or --result without --format mermaid) or a supplied file/directory does not exist.

Example:

chainweaver viz my_etl_flow --discover-dir flows/
chainweaver viz my_etl_flow --format dot | dot -Tpng -o my_etl_flow.png
chainweaver viz my_etl_flow --discover-dir flows/ --format mermaid
chainweaver viz --result trace.json --format mermaid    # overlay a real run

explain

Render a deterministic, LLM-free explanation of a flow — steps, input/output mappings, branching conditions, governance/safety attributes, and an embedded Mermaid diagram — suitable for pasting into a pull-request description or a review. Output is stable across runs (diff-friendly).

chainweaver explain <flow_name> [--format md|text] [--result trace.json] [discovery flags]
FlagDefaultDescription
--format / -fmdmd (Markdown for PRs) or text
--resultOverlay actual step outcomes from an ExecutionResult JSON file
--file / --discover-dir / --discover-entry-pointsFlow resolution, exactly like inspect

Exit codes: 0 = success, 1 = flow not found or no registry configured, 2 = a supplied file/directory does not exist.

Example:

chainweaver explain my_etl_flow --discover-dir flows/ > flow-review.md
chainweaver explain my_etl_flow --file flows/etl.flow.yaml --result trace.json

init

Scaffold a runnable first flow project — tool definitions, a flow file, and a run script — in one command.

chainweaver init [directory] [--template linear|dag|mcp] [--with-tests] [--force]
FlagDefaultDescription
--template / -tlinearProject template: linear flow, fan-in DAG, or MCP-ready starter
--with-testsfalseAlso scaffold a passing pytest module (test_flow.py)
--forcefalseOverwrite existing files instead of aborting on a collision

The command prints the exact next commands after generating the files.

Exit codes: 0 = success, 1 = a target file already exists and --force was not given, 2 = directory exists but is not a directory.

Example:

chainweaver init my-first-flow --template linear --with-tests
cd my-first-flow && python run.py

validate

Validate a single flow definition file (.flow.yaml, .flow.yml, or .flow.json).

chainweaver validate <file> [--format table|json]
FlagDefaultDescription
--format / -ftableOutput format: human-readable line or machine-readable JSON

Exit codes: 0 = valid, 1 = validation error, 2 = file not found.

Example:

chainweaver validate flows/etl.flow.yaml
chainweaver validate flows/etl.flow.json --format json

check

Validate every flow file in a directory (recursive).

chainweaver check <directory> [--format table|json] [--quiet]
FlagDefaultDescription
--format / -ftableOutput format
--quiet / -qFalseSuppress per-file output; only exit code is meaningful

Exit codes: 0 = all valid, 1 = at least one invalid file, 2 = directory not found.

Example:

chainweaver check flows/
chainweaver check flows/ --quiet  # CI-friendly: exit code only

run

Load a flow definition file from disk, register tools from one or more Python modules, and execute the flow with optional JSON input.

chainweaver run <flow_file> [--tools module] [--input file] [--format table|json]
FlagDefaultDescription
--tools / -t(none)Python module path to import tools from (repeatable)
--input / -i(none)JSON file containing the initial input dict
--format / -ftableOutput format

Exit codes: 0 = success, 1 = execution error or tool not found, 2 = file not found.

Example:

# Runnable from the repository root — the flow file and tools both ship in examples/:
chainweaver run examples/double_add_format.flow.yaml --tools examples.simple_linear_flow --input '{"number": 5}'

chainweaver run flows/etl.flow.yaml --tools my_package.tools --input input.json --format json

serve

Expose a flow as MCP tools over a chosen transport. Loads a flow file and its tool modules (exactly like run), mounts the flow on a FlowServer, and serves it so MCP-aware agents call the whole compiled flow as a single deterministic tool. Requires the mcp extra (pip install 'chainweaver[mcp]').

chainweaver serve <flow_file> [--tools module] [--transport stdio|sse|streamable-http] [--name NAME] [--prefix PREFIX]
FlagDefaultDescription
--tools / -t(none)Python module path to import tools from (repeatable)
--transportstdioMCP transport: stdio, sse, or streamable-http
--namechainweaverServer name advertised to MCP clients
--prefix(none)Prefix for exposed tool names (e.g. cwcw__my_flow)

The startup banner is written to stderr, keeping stdout a clean MCP wire channel under stdio. The process blocks serving the transport until interrupted (Ctrl-C).

Exit codes: 0 = clean shutdown, 1 = malformed flow file or missing mcp extra, 2 = flow file not found or tools module not importable.

Example:

# Runnable from the repository root — flow file and tools both ship in examples/:
chainweaver serve examples/double_add_format.flow.yaml --tools examples.simple_linear_flow

See Use ChainWeaver as an MCP server for the full guide.


profile

Analyze one or more ExecutionResult JSON files. For a single file, surfaces per-step duration and bottlenecks. For multiple files, adds p50/p95/p99 statistics across runs. Every output (single or multi) also carries per-step and per-tool reliability aggregates — retries, skips, fallbacks, failures, and cache hits — so you can see at a glance which step or tool is responsible for instability.

chainweaver profile <traces...> [--top N] [--format table|json]
FlagDefaultDescription
--top / -n5Number of slowest steps to surface
--format / -ftableOutput format

Exit codes: 0 = success, 1 = malformed trace input, 2 = file not found.

Reliability fields (issue #176, stable JSON contract):

Every entry in steps[] carries these in addition to step_index, tool_name, duration_ms, success:

FieldTypeMeaning
retry_countintRetries beyond the initial invocation. In multi-trace mode this is the sum across the N traces at the same step index.
skippedbool (single) / skip_count int (multi)Step was on_error="skip"-ed.
fallback_usedbool (single) / fallback_count int (multi)Step's on_error="fallback:<tool_name>" policy invoked a fallback tool — set regardless of whether the fallback itself succeeded.
cachedbool (single) / cached_count int (multi)Outputs served from the executor's step_cache.
error_typestr | null (single only)Exception class name when the step failed.

The top-level aggregates object rolls these up:

{
  "aggregates": {
    "retry_count":    3,
    "skip_count":     0,
    "fallback_count": 1,
    "failure_count":  0,
    "cached_count":   0,
    "by_tool": {
      "fetch": {
        "invocation_count": 2,
        "retry_count": 3,
        "skip_count": 0,
        "fallback_count": 0,
        "failure_count": 0,
        "cached_count": 0
      },
      "store": { "...": "same shape" }
    }
  }
}

The table view appends a Reliability: footer with the same data, plus a per-tool table sorted by failures → fallbacks → retries. The footer is suppressed for clean runs (every count zero) so happy-path output stays compact.

Example:

chainweaver profile trace.json
chainweaver profile trace_a.json trace_b.json trace_c.json --top 10
chainweaver profile trace.json --format json

doctor

doctor is a command group. doctor flow runs flow diagnostics against the currently registered tools; doctor vscode / doctor claude / doctor opencode inspect a workspace's coding-agent setup for the observe → suggest → compile workflow.

doctor flow

Diagnose ChainWeaver flows against the currently registered tools. With --check-drift, walks every flow file under path (single file or recursive directory), imports tools from the modules passed via --tools, and reports per-flow missing_tool / schema_mismatch issues. With --preflight, runs structural validation (tool existence and resolvable input mappings). With --profile first-run, skips flow analysis and checks environment readiness instead — Python version, optional-extra availability (with the exact install command), writable paths, and core import health — for a "is my install ready?" first check (no path required).

chainweaver doctor flow <path> --check-drift [--tools MODULE...] [--format table|json]
chainweaver doctor flow --profile first-run [--format table|json]

doctor vscode / doctor claude / doctor opencode

Read-only inspectors that report what a workspace has configured for the observe → suggest → compile workflow and what is missing. They never modify files; --fix-dry-run prints the config that would be written. Each detects the editor's MCP config and whether a ChainWeaver FlowServer is exposed, plus a trace directory (.chainweaver/traces/) and discoverable macro-flows. doctor claude additionally checks config scope (.mcp.json / .claude/settings*.json) and a PostToolUse observe hook; doctor opencode additionally checks for a ChainWeaver plugin and reminds about tool-name collisions.

chainweaver doctor vscode   [--workspace DIR] [--format table|json] [--fix-dry-run]
chainweaver doctor claude   [--workspace DIR] [--format table|json] [--fix-dry-run]
chainweaver doctor opencode [--workspace DIR] [--format table|json] [--fix-dry-run]
Editor flagDefaultDescription
--workspace / -w.Workspace directory to inspect.
--format / -ftableOutput format: human-readable table or structured JSON.
--fix-dry-runAlso print the config that would fix detected gaps, without modifying any files.

Editor-inspector exit codes: 0 when the workspace is inspectable (a missing config is reported as a finding, not an error), 2 when --workspace is missing or is not a directory.

FlagDefaultDescription
--check-driftCompare each step's tool reference and schema fingerprint to the current registry.
--preflightValidate flow structure: tool existence and resolvable input mappings.
--profileNamed diagnostic profile. first-run checks environment readiness (no path needed).
--tools / -t(empty)Python module path that exposes Tool instances at top level. Repeatable.
--format / -ftableOutput format: human-readable table or structured JSON.

One of --check-drift, --preflight, or --profile is required.

First-run JSON shape (when --profile first-run --format json): a top-level ok flag plus python, writable_paths, import_health, and an extras array where each entry carries extra, available, missing_modules, and a copy-paste install command.

Exit codes: 0 = no drift / ready, 1 = drift detected, malformed flow file, or not ready, 2 = path or --tools module missing.

JSON output shape (when --format json):

{
  "path": "flows/",
  "flow_count": 2,
  "drift_count": 1,
  "load_errors": [],
  "results": [
    {
      "path": "flows/ok.flow.yaml",
      "flow_name": "etl",
      "flow_version": "0.1.0",
      "fingerprints_present": true,
      "ok": true,
      "missing_count": 0,
      "drift_count": 0,
      "issues": []
    },
    {
      "path": "flows/legacy.flow.yaml",
      "flow_name": "legacy_etl",
      "flow_version": "0.1.0",
      "fingerprints_present": true,
      "ok": false,
      "missing_count": 0,
      "drift_count": 1,
      "issues": [
        {
          "step_index": 0,
          "tool_name": "fetch",
          "issue_type": "schema_mismatch",
          "detail": "Tool 'fetch' schema hash changed: expected 'abc123…', got 'def456…'."
        }
      ]
    }
  ]
}

fingerprints_present: false means the flow file was saved without a tool_schema_hashes snapshot — only missing_tool issues are detectable for those flows.

Example:

chainweaver doctor flow flows/etl.flow.yaml --check-drift --tools my_pkg.tools
chainweaver doctor flow flows/ --check-drift --tools my_pkg.tools --format json

diff

Compare two ExecutionResult JSON files step-by-step.

Aligns step records by position and checks outputs, error_type, error_message, and success for each paired step. Non-deterministic fields (trace_id, started_at, ended_at, total_duration_ms, per-step duration_ms) are ignored unless --perf-tolerance is set.

chainweaver diff <a.json> <b.json> [--perf-tolerance N] [--format table|json]
FlagDefaultDescription
--perf-tolerance(off)Flag steps whose duration_ms changed by more than N %. Integer, e.g. 25 = 25%.
--format / -ftableOutput format: human-readable table or structured JSON diff

Exit codes:

CodeMeaning
0Traces are identical (modulo ignored fields)
1Traces differ, or malformed trace input
2File not found

JSON output shape (when --format json):

{
  "identical": false,
  "flow_name": null,
  "step_count": null,
  "success": null,
  "final_output": {
    "values_changed": {
      "root['key']": { "old_value": 42, "new_value": 99 }
    }
  },
  "steps": [
    {
      "step_index": 1,
      "tool_name": "store",
      "outputs": {
        "values_changed": {
          "root['key']": { "old_value": 42, "new_value": 99 }
        }
      }
    }
  ]
}

Fields flow_name, step_count, success, and final_output are null / {} when that dimension is identical between the two traces. The steps list contains only steps where at least one field differed.

Example:

chainweaver diff baseline.json current.json
chainweaver diff baseline.json current.json --perf-tolerance 25
chainweaver diff baseline.json current.json --format json

Use cases:

  • A flow misbehaves in production — compare a known-good trace with today's failing trace to isolate the diverging step.
  • A replay run (#21) finishes — was final_output byte-identical to the original?
  • A schema drift event (#50) occurred — what was the functional impact on recorded traces?

attest

Run an observed-determinism attestation against a flow: generate --runs distinct inputs (or read them from --seed-input), run the flow --repeats times per input, and emit a JSON attestation report. When all repeats agree the attestation passes; any divergence fails it.

This produces observed-deterministic evidence, not a formal proof — re-running with the same --seed and ChainWeaver version yields a byte-identical aggregate_fingerprint.

chainweaver attest <flow_file> [--tools module] [--runs N] [--repeats N] [--seed N] [--seed-input file] [--format json|table]
FlagDefaultDescription
--tools / -t(none)Python module path exposing Tool instances at top level. Repeatable.
--runs100Number of distinct inputs to generate (ignored when --seed-input is set).
--repeats3Executions per input. Must be ≥ 2.
--seed0Integer seed for the input generator. Same seed → same inputs.
--seed-input(none)JSON file containing a list of input objects to use directly (bypasses the generator).
--format / -fjsonOutput format: json (the attestation artifact) or table.

Exit codes: 0 = observed-deterministic across all inputs, 1 = divergence detected / execution / argument error, 2 = flow file or tools module not found.

Example:

chainweaver attest examples/double_add_format.flow.yaml --tools examples.simple_linear_flow --runs 50 --repeats 3

suggest

Emit advisory static optimization suggestions for a flow file. A successful run always exits 0 (the suggester is advisory); machine consumers should gate on the suggestions array length in --format json.

Suggestion families (stable codes):

  • CW001 — wasteful-passthrough (empty input_mapping).
  • CW002 — parallelizable-pair (adjacent steps reading disjoint context keys). Requires --tools.
  • CW003 — dead-step (step outputs are not read downstream). Requires --tools.
  • CW004 — cacheable-step (identical outputs across observed traces). Requires two or more --trace files.
chainweaver suggest <flow_file> [--tools module] [--trace file] [--format table|json]
FlagDefaultDescription
--tools / -t(none)Python module path exposing Tool instances at top level. Required for CW003 (dead-step). Repeatable.
--trace(none)Path to a recorded ExecutionResult JSON file. Two or more required for CW004 (cacheable-step). Repeatable.
--format / -ftableOutput format: human-readable table or machine-readable JSON.

Exit codes: 0 = ran successfully (regardless of suggestion count), 1 = malformed input, 2 = file not found.

Example:

chainweaver suggest examples/double_add_format.flow.yaml --tools examples.simple_linear_flow
chainweaver suggest flows/etl.flow.yaml --tools my_pkg.tools --trace run_a.json --trace run_b.json --format json

record

Mine candidate flows from a recorded JSONL tool trace (issue #226). Replays the trace through ChainObserver, detects repeated tool sequences offline (no LLM), and emits candidate .flow.yaml files ranked by projected LLM calls avoided (len(tools) * occurrences). Without --output-dir the command is a dry run that only reports candidates.

Each non-blank line of the trace file is a JSON object describing one tool call. Calls are grouped into traces by trace_id (file order preserved); lines without a trace_id join a single default trace:

{"trace_id": "req-1", "tool": "fetch", "inputs": {"url": "..."}, "outputs": {"body": "..."}}

tool (or its alias tool_name) is required; inputs defaults to {} and outputs to null.

chainweaver record <trace.jsonl> [--output-dir DIR] [--min-occurrences N] [--min-length N] [--max-length N] [--include-ignored] [--format table|json]
FlagDefaultDescription
--output-dir / -o(none)Directory to write candidate .flow.yaml files into. Omit for a dry run.
--min-occurrences3Minimum contiguous appearances for a pattern to be suggested.
--min-length2Minimum pattern length (number of tools).
--max-length(none)Maximum pattern length. Omit for no upper bound.
--include-ignoredFalseReport persisted ignored candidates instead of suppressing them. Ignored files are never overwritten.
--format / -ftableOutput format: human-readable table or machine-readable JSON.

Exit codes: 0 = ran successfully (regardless of candidate count), 1 = malformed trace or serialization error, 2 = file not found.

Example:

chainweaver record examples/agent_tool_trace.jsonl
chainweaver record examples/agent_tool_trace.jsonl --output-dir candidates/ --format json

New files are persisted with lifecycle draft; repeated runs preserve an existing candidate's governance state. Promote a candidate deterministically:

chainweaver flows promote candidates/suggested__fetch__validate.flow.yaml --to reviewed --reviewed-by alice
chainweaver flows promote candidates/suggested__fetch__validate.flow.yaml --to active
chainweaver flows ignore candidates/suggested__noisy.flow.yaml --reason "Not useful for this workspace"

The lifecycle is observed → suggested → draft → reviewed → active. ignored candidates are suppressed by later record runs, and archived flows remain auditable but are not exposed by default.


traces

Import coding-agent tool-use traces and run the observe → mine → score → draft → backtest loop for the coding-agent token-reduction use case (issues #254, #256, #257, #266, #267). The richer JSONL format carries both tool_call and model_call events plus token/latency/status metadata; all analysis is offline (no LLM). See the Daily Driver guide.

chainweaver traces mine <trace.jsonl> [--min-occurrences N] [--min-length N] [--max-length N] [--limit N] [--format table|json]
chainweaver traces draft-flows <trace.jsonl> [--output-dir DIR] [--min-occurrences N] [--min-length N] [--max-length N] [--format table|json]
chainweaver traces backtest <flow.yaml> --trace <trace.jsonl> [--format table|json]
  • mine — mine repeated tool sequences and score each by support, success rate, schema stability, determinism, and safety; prints a ranked, human-friendly report (or JSON).
  • draft-flows — generate draft-lifecycle .flow.yaml files (with a .json metadata/warnings sidecar) from the scored candidates. Without --output-dir it is a dry run.
  • backtest — replay past traces against a draft flow (shape + sequence only, no tool execution); exits non-zero if any window fails to reproduce.

Exit codes: 0 = ran successfully (for backtest, all examples reproduced), 1 = malformed trace / mismatches found, 2 = file not found.

Example:

chainweaver traces mine coding-agent.jsonl --limit 5
chainweaver traces draft-flows coding-agent.jsonl --output-dir flows/drafts/
chainweaver traces backtest flows/drafts/draft__fs_search__fs_read.flow.yaml --trace coding-agent.jsonl

dump-schema

Emit the JSON Schema for .flow.json / .flow.yaml files, derived from the Pydantic models in chainweaver.flow. Editors that consume JSON Schema (VS Code via redhat.vscode-yaml, JetBrains, …) get autocomplete, hover docs, and inline validation once they point yaml.schemas at the published schema.

chainweaver dump-schema [--output PATH] [--check]
FlagDefaultDescription
--output / -ostdoutWrite the JSON Schema to this path. Recommended in-repo path: schemas/flow.schema.json.
--checkFalseWrite nothing; exit 0 if the file at --output already matches the current schema, 1 if it would change. Useful as a CI guard.

Exit codes: 0 = written / printed successfully (or --check match), 1 = --check mismatch or --output unwritable, 2 = --check used without --output.

Example:

chainweaver dump-schema --output schemas/flow.schema.json
chainweaver dump-schema --check --output schemas/flow.schema.json   # CI: fails if the checked-in schema is stale

fuzz

Property-based fuzzing for a flow file (issues #220, #221, #222). Generates --runs cases — either from the flow's input_schema or by mutating a --input base — executes the flow, and checks each --property (a generic invariant over the ExecutionResult) against the result. Optionally injects malformed tool outputs (--output-fault-prob), shrinks failing inputs to a minimal reproducer (--minimize, issue #221), and saves failing traces as replayable JSON, redacted by default (--save-failures / --redact, issue #217). With --redact (the default) the failing and minimized inputs printed in the summary/table are redacted too, so secrets do not leak into CI logs; pass --no-redact for raw values. Each --property must resolve to a unique name.

A run is reproducible: re-running with the same --seed, --runs, flow, and tools yields the same cases and failures.

chainweaver fuzz <file> [--tools MODULE...] [--property NAME|module:attr ...] [--runs N] [--seed S] \
                        [--input JSON | --input-file PATH] [--output-fault-prob P] \
                        [--minimize] [--save-failures DIR] [--redact/--no-redact] [--format table|json]
FlagDefaultDescription
--tools / -t(empty)Python module path that exposes Tool instances at top level. Repeatable.
--property / -pflow_succeedsA built-in property name (flow_succeeds, final_output_present) or a module:attr path to a FlowProperty or a Callable[[ExecutionResult], bool]. Repeatable.
--runs / -n100Number of cases to generate (>= 1).
--seed0Deterministic RNG seed.
--input / -i(off)JSON object used as the base input to mutate instead of generating from the schema.
--input-file(off)Path to a JSON object used as the base input.
--output-fault-prob0.0Probability in [0,1] of corrupting a tool's output per call (0 disables).
--minimize / --no-minimize--no-minimizeShrink each failing input to a minimal reproducer.
--save-failures(off)Directory to write failing ExecutionResult traces to (created if absent).
--redact / --no-redact--redactRedact saved traces and emitted failing/minimized inputs with the default RedactionPolicy. Use --no-redact for raw values.
--format / -ftableOutput format: human-readable table or structured JSON.

Exit codes: 0 = no property violated, 1 = one or more violations found or a CLI-level error (bad arguments, malformed flow/input, unknown property), 2 = flow file, tools module, or property module not found / not importable.

JSON output shape (when --format json):

{
  "flow": "my_flow",
  "runs": 1000,
  "seed": 42,
  "properties": ["flow_succeeds"],
  "failures": 1,
  "failure_cases": [
    {
      "property": "flow_succeeds",
      "case_index": 17,
      "initial_input": {"number": 5, "junk": "x"},
      "check_error": null,
      "minimized_input": {"junk": "x"},
      "saved": "failures/my_flow.flow_succeeds.case17.json"
    }
  ]
}

minimized_input is present only with --minimize; saved only with --save-failures. check_error is set when a property check itself raised (treated as a violation).

Example (CI integration):

chainweaver fuzz flows/my_flow.flow.yaml \
  --tools my_pkg.tools \
  --property my_pkg.props:no_unauthorized_action \
  --runs 1000 --seed 42 \
  --minimize --save-failures failures/
# exits non-zero when a property is violated, failing the CI job;
# minimized, redacted reproducers land in failures/ as build artifacts.

service

Run one ChainWeaverService analysis pass and report the proposals it would queue (issue #101). The service ties together the static schema analyzer (--tools) and the runtime observer (--trace), surfaces candidate flows as pending proposals, and prints service metrics. Proposals are reported, never auto-registered — promotion stays a governed, in-process action.

A long-running daemon with cross-invocation approve / reject requires proposal persistence (#16) and is intentionally out of scope for the CLI; drive that loop via the ChainWeaverService Python API instead.

chainweaver service [--tools module...] [--trace trace.jsonl] [--min-occurrences N] [--min-length N] [--format table|json]
FlagDefaultDescription
--tools / -t(none)Python module path exposing Tool instances at top level. Enables the static-analysis pass. Repeatable.
--trace(none)JSONL tool-trace file (same format as chainweaver record) feeding the runtime-observation pass.
--min-occurrences3Minimum runtime occurrences before an observed pattern is proposed.
--min-length2Minimum pattern / flow length (number of tools).
--format / -ftableOutput format: human-readable table or machine-readable JSON.

Exit codes: 0 = ran successfully, 1 = malformed trace / input, 2 = trace file not found.

Example:

chainweaver service --tools examples.simple_linear_flow
chainweaver service --trace examples/agent_tool_trace.jsonl --min-occurrences 2 --format json

Programmatic registration (inspect, viz)

inspect and viz read from a process-scoped registry installed via cli.set_default_registry:

from chainweaver import FlowRegistry, cli

registry = FlowRegistry()
registry.register_flow(my_flow)
cli.set_default_registry(registry)
cli.main(["inspect", "my_flow"])

validate, check, run, profile, diff, attest, suggest, doctor, and fuzz read directly from disk and do not consult the default registry. dump-schema takes no flow input.