{"id":51314488,"url":"https://github.com/aigengame/cli-agentic-workflow","last_synced_at":"2026-07-01T06:05:23.355Z","repository":{"id":364217689,"uuid":"1265794381","full_name":"aigengame/cli-agentic-workflow","owner":"aigengame","description":"A lightweight local-first CLI that orchestrates AI agent CLIs (claude, codex) into powerful workflows with a simple YAML.","archived":false,"fork":false,"pushed_at":"2026-06-12T05:04:02.000Z","size":2613,"stargazers_count":0,"open_issues_count":20,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-12T07:04:58.328Z","etag":null,"topics":["agentic-workflows","ai-agents","cli","workflow-orchestration"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aigengame.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-06-11T04:53:38.000Z","updated_at":"2026-06-12T05:01:40.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/aigengame/cli-agentic-workflow","commit_stats":null,"previous_names":["aigengame/cli-agentic-workflow"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/aigengame/cli-agentic-workflow","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aigengame%2Fcli-agentic-workflow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aigengame%2Fcli-agentic-workflow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aigengame%2Fcli-agentic-workflow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aigengame%2Fcli-agentic-workflow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aigengame","download_url":"https://codeload.github.com/aigengame/cli-agentic-workflow/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aigengame%2Fcli-agentic-workflow/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34994884,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-01T02:00:05.325Z","response_time":130,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agentic-workflows","ai-agents","cli","workflow-orchestration"],"created_at":"2026-07-01T06:05:18.221Z","updated_at":"2026-07-01T06:05:23.338Z","avatar_url":"https://github.com/aigengame.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# cli-agentic-workflow(caw)\n\n![caw title image](assets/caw-hero.png)\n\n\u003e A lightweight, local-first CLI that orchestrates AI agent CLIs like `claude -p` and `codex exec` into powerful, inspectable workflows — define a DAG in simple YAML, then validate, run, resume, and report with zero infrastructure.\n\n[![Status: pre-release](https://img.shields.io/badge/status-pre--release-orange.svg)](https://github.com/aigengame/cli-agentic-workflow/issues/1)\n[![Python 3.12+](https://img.shields.io/badge/python-3.12%2B-blue.svg)](https://www.python.org/)\n[![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv)\n[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)\n\n\n`caw` is not another chat UI and not an agent model provider. It is a local workflow kernel\nthat turns agent invocations into structured, repeatable workflow runs: every graph is\nvisible before execution, every node output is persisted, and every run can be resumed and\naudited.\n\n## Project status\n\n**Pre-release — v0.1 specification complete, implementation in progress.**\n\nThe product scope, architecture, and vocabulary are fully specified and frozen in\n[PRD #1](https://github.com/aigengame/cli-agentic-workflow/issues/1), with implementation\nbroken into tracer-bullet issues ([#2–#17](https://github.com/aigengame/cli-agentic-workflow/issues)).\n[Installation](#installation) and [Quickstart](#quickstart) cover what runs **today**; the\n[Example](#example), [CLI at a glance](#cli-at-a-glance), and [Built-in patterns](#built-in-patterns)\nsections describe the full specified v0.1 surface, which becomes runnable as those issues land.\n\n## Installation\n\ncaw needs **Python ≥ 3.12** and [uv](https://docs.astral.sh/uv/). It is not on PyPI yet\n(planned — [#34](https://github.com/aigengame/cli-agentic-workflow/issues/34)), so install it\nfrom the repository.\n\nInstall the CLI globally with uv:\n\n```bash\nuv tool install git+https://github.com/aigengame/cli-agentic-workflow\ncaw --help\n```\n\nOr work from a clone (recommended if you want to develop or read the source):\n\n```bash\ngit clone https://github.com/aigengame/cli-agentic-workflow.git\ncd cli-agentic-workflow\nuv sync\nuv run caw --help\n```\n\nBoth give you the `caw` CLI — globally as `caw`, or as `uv run caw` inside a clone. The\nexamples below use `caw`; prefix them with `uv run` when working from a clone.\n\n## Quickstart\n\nA workflow is a YAML file of nodes and the `needs` edges between them. This one runs two\nshell nodes in order — no agent CLI, no tokens, nothing to configure. Save it as\n`hello.yaml`:\n\n```yaml\nname: hello-caw\nversion: 1\nnodes:\n  - id: greet\n    kind: shell\n    inputs:\n      command: echo \"hello from caw\"\n  - id: announce\n    kind: shell\n    needs: [greet]\n    inputs:\n      command: echo \"ran after greet\"\n```\n\nValidate it, inspect the plan, then run it:\n\n```bash\ncaw validate hello.yaml   # workflow hello.yaml is valid (2 nodes)\ncaw graph hello.yaml      # the planned DAG, printed before anything runs\ncaw run hello.yaml        # node greet attempt 1 exited 0 ... run \u003crun-id\u003e succeeded\n```\n\nEvery run is persisted under `.caw/runs/\u003crun-id\u003e/`: `state.sqlite` (node status, outputs,\nresume eligibility), `events.jsonl` (the append-only trace), and `workflow.normalized.json`\n(the exact graph that ran). Continue an interrupted or failed run — re-running only its\nincomplete nodes — with `caw resume \u003crun-id\u003e`.\n\n**Run an agent step offline.** Switch a node to `kind: agent` with the built-in `mock`\nadapter to exercise the agent path with no real CLI and no tokens: it replays a fixture file\nas the node's result (the same seam the test suite uses). Add to `nodes:`:\n\n```yaml\n  - id: summarize\n    kind: agent\n    needs: [greet]\n    inputs:\n      adapter: mock\n      prompt: \"summarize the greeting\"\n      fixture: summary.fixture.json\n```\n\nwith `summary.fixture.json` next to the workflow file:\n\n```json\n{ \"exit_status\": 0, \"stdout\": \"a one-line summary\" }\n```\n\n`caw run hello.yaml` now runs the shell and agent nodes together. Swapping `adapter: mock`\nfor a real adapter (e.g. `claude.print`) is the only change needed to drive a real agent CLI.\n\n### Fan-out synthesis: the end-to-end sample\n\nThe first complete end-to-end sample is a **hand-written** workflow that fans the **same\ntask** out to two agent branches in parallel and joins both answers in a `synthesize` node —\nthe fan-out-synthesis shape. It ships under [`examples/fanout-synthesis/`](examples/fanout-synthesis/)\nin two variants: an **offline mock** variant (every node uses the built-in `mock` adapter, so\nit runs with no real Agent CLI and no tokens) and a **real** variant that fans the same task\nto `claude.print` and `codex.exec` side by side.\n\nRun the offline variant from the repo root — clone-to-completed in well under ten minutes\n(the full walkthrough is in the sample's\n[QUICKSTART.md](examples/fanout-synthesis/QUICKSTART.md)):\n\n```bash\ncaw validate examples/fanout-synthesis/fanout-synthesis.mock.yaml\ncaw graph    examples/fanout-synthesis/fanout-synthesis.mock.yaml   # two branches → one synthesize node\ncaw run      examples/fanout-synthesis/fanout-synthesis.mock.yaml   # runs offline — no tokens\ncaw report \u003crun-id\u003e --format markdown                               # conclusion (## Nodes) vs trace (## Trace)\n```\n\nThe real variant ([`fanout-synthesis.real.yaml`](examples/fanout-synthesis/fanout-synthesis.real.yaml))\npoints the two branches at `claude.print` and `codex.exec`, requires both CLIs on PATH and\nauthenticated, and is exercised end-to-end by the e2e suite\n(`tests/e2e/test_fanout_synthesis_runs.py`). The Markdown report keeps the final conclusion\n(each node's outcome, including the synthesize node's) in its own `## Nodes` section, distinct\nfrom the `## Trace` of events.\n\n## Why caw\n\n- **Validate before you spend tokens.** `caw validate` catches schema errors, broken\n  references, and dependency cycles before any agent CLI is invoked.\n- **See the graph before it runs.** `caw graph` renders the execution plan; the normalized\n  workflow snapshot is immutable once a run starts.\n- **Vendor-neutral by design.** `claude -p` and `codex exec` are adapters with symmetric\n  capabilities — switch an agent node between them by changing one `uses` value.\n- **Resume instead of re-run.** Run state, events, and artifacts persist locally\n  (SQLite + JSONL); interrupted runs continue without repeating completed nodes.\n- **Human gates for high-impact steps.** A `human_gate` node parks the run durably until\n  you approve — interactively or via `caw resume --approve`.\n- **Reusable agentic patterns.** Pipeline, parallel, classify-and-act, generate-and-filter,\n  fan-out synthesis, adversarial verification, tournament, and loop-until-done ship as\n  built-ins that scaffold complete, runnable examples.\n- **Reports you can hand to a reviewer.** Markdown, JSON, JSONL, or plain-text reports\n  separate final conclusions from trace evidence.\n- **Local-first, zero infrastructure.** One machine, one process, inspectable files on\n  disk. No server, no control plane, no external workflow engine.\n\n## How it works\n\nA workflow is a YAML file describing nodes (agent calls, shell commands, Python functions,\nclassifiers, verifiers, synthesizers, reports, human gates) and the edges between them.\ncaw normalizes it into an acyclic, immutable intermediate representation, schedules ready\nnodes concurrently on an asyncio event loop, and persists everything under `.caw/runs/\u003crun-id\u003e/`:\n\n```text\n.caw/runs/\u003crun-id\u003e/\n  state.sqlite                # node status, attempts, outputs, resume eligibility\n  events.jsonl                # append-only machine-readable trace\n  workflow.normalized.json    # the exact graph that ran, with checksum\n  artifacts/\u003cnode-id\u003e/        # stdout, stderr, structured outputs\n```\n\nIterative behavior (loops, regeneration, tournament rounds) never mutates a running graph:\na pattern controller evaluates a finished run and materializes the next immutable run,\nlinking them into a run group that reports and resumes as a unit.\n\nConditional behavior lives in node-level `when` predicates; structured outputs are\nvalidated against JSON Schema (draft 2020-12) output contracts; env vars reach a node only\nwhen explicitly declared and are never persisted.\n\n## Example\n\n```yaml\nname: review-and-fix\nversion: 1\n\ninputs:\n  task:\n    type: file\n\nnodes:\n  - id: diagnose\n    kind: agent\n    uses: codex.exec\n    inputs:\n      prompt: \"Diagnose the failure described in ${inputs.task}\"\n    output_schema: schemas/diagnosis.json\n\n  - id: verify\n    kind: agent\n    uses: claude.print\n    needs: [diagnose]\n    inputs:\n      prompt: \"Review the diagnosis and identify gaps.\"\n\n  - id: report\n    kind: report\n    needs: [diagnose, verify]\n    inputs:\n      format: markdown\n```\n\n```bash\ncaw validate review-and-fix.yaml   # fail fast, before tokens\ncaw graph review-and-fix.yaml      # inspect the plan\ncaw run review-and-fix.yaml --input task.md\ncaw report \u003crun-id\u003e --format markdown\n```\n\n\u003e ℹ️ This example uses the full specified surface (`uses:`, top-level `inputs:`,\n\u003e `caw run --input`, a `report` node) — not all of it runs yet. For a workflow that runs\n\u003e **today**, see [Quickstart](#quickstart).\n\n## CLI at a glance\n\n| Command | Purpose | Status |\n| --- | --- | --- |\n| `caw validate \u003cfile\u003e` | Check schema, references, adapters, and acyclicity without executing | ✅ now |\n| `caw graph \u003cfile\u003e` | Render the planned DAG as text or JSON | ✅ now |\n| `caw run \u003cfile\u003e` | Execute a workflow run | ✅ now |\n| `caw resume \u003crun-id\u003e` | Continue an interrupted or failed run, re-running only incomplete nodes | ✅ now |\n| `caw init [path]` | Create a minimal starter workflow | ✅ now |\n| `caw report \u003crun-id\u003e` | Render a report (markdown, json, jsonl, text) from persisted state | ✅ now |\n| `caw patterns list` | List built-in workflow patterns | ✅ now |\n| `caw patterns init \u003cname\u003e [path]` | Scaffold a complete runnable example of a pattern | ✅ now |\n| `caw loop run \u003cspec\u003e` | Run a loop-until-done run group from a controller spec | ✅ now |\n| `caw loop resume \u003cgroup-id\u003e` | Resume an interrupted run group at the group level | ✅ now |\n| `caw loop report \u003cgroup-id\u003e` | Aggregate every iteration of a run group into one report | ✅ now |\n| `caw loop init [path]` | Scaffold a complete runnable loop-until-done example | ✅ now |\n| `caw verify run \u003cspec\u003e` | Run an adversarial-verification run group from a controller spec | ✅ now |\n| `caw verify resume \u003cgroup-id\u003e` | Resume an interrupted adversarial-verification run group | ✅ now |\n| `caw verify report \u003cgroup-id\u003e` | Aggregate an adversarial-verification run group into one report | ✅ now |\n| `caw verify init [path]` | Scaffold a complete runnable adversarial-verification example | ✅ now |\n| `caw tournament run \u003cspec\u003e` | Run a tournament run group from a controller spec | ✅ now |\n| `caw tournament resume \u003cgroup-id\u003e` | Resume an interrupted tournament run group | ✅ now |\n| `caw tournament report \u003cgroup-id\u003e` | Aggregate a tournament run group into one report | ✅ now |\n| `caw tournament init [path]` | Scaffold a complete runnable tournament example | ✅ now |\n\n## Built-in patterns\n\nA built-in pattern is authored as a top-level `pattern:` block (mutually exclusive with\n`nodes:`) that compiles to plain IR at normalize time, so the expanded workflow validates\nand runs identically to the hand-authored equivalent (see\n[ADR 0008](docs/adr/0008-pattern-expanders-compile-to-plain-ir.md)). Scaffold a runnable\nexample of any shipped pattern with `caw patterns init \u003cname\u003e`.\n\n| Pattern | Shape | Status |\n| --- | --- | --- |\n| Pipeline | Linear node chain | ✅ now |\n| Parallel | Independent branches joined downstream | ✅ now |\n| Classify and act | Classifier routes to one of several `when`-gated branches | ✅ now |\n| Generate and filter | N candidate generators, then a scoring/validation filter | ✅ now |\n| Fan-out synthesis | Parallel agents, then a synthesis node (the reference sample runs `claude.print` and `codex.exec` side by side) | ✅ now |\n\nThese are pattern **expanders** (`pattern:` blocks scaffolded by `caw patterns init`). The\niterative **pattern controllers** — loop-until-done, adversarial verification, and\ntournament — are a distinct axis ([ADR 0009](docs/adr/0009-pattern-controller-infrastructure.md))\nand live in the next section, not the `caw patterns init` registry.\n\n### Run Groups and pattern controllers\n\nIterative patterns are realized by a **pattern controller**, a distinct axis from pattern\nexpanders ([ADR 0009](docs/adr/0009-pattern-controller-infrastructure.md)): an expander\nshapes one run's graph, a controller sequences multiple runs. Per\n[ADR 0002](docs/adr/0002-pattern-iteration-as-run-groups.md) the kernel only ever executes\nacyclic runs — `loop until done` lives above the executor, in Python, re-running an\nordinary single-iteration workflow until the done Predicate holds. Each iteration is a\n*separate immutable run*; successive runs link into a **Run Group** that reports and\nresumes as one unit (under `.caw/groups/\u003cgroup-id\u003e/`).\n\nA controller spec file declares the loop:\n\n```yaml\nworkflow: loop-iteration.yaml   # an ordinary single-iteration workflow\nmax_iterations: 5\nevaluate_node: verdict          # the node whose output the done Predicate reads\ndone:                           # the done Predicate — the same `when` predicate algebra\n  ref: { node: verdict, field: stdout }\n  op: contains\n  value: FINISHED\nfeedback:                       # iteration N's output fed into iteration N+1 (optional)\n  to_node: verdict\n  to_field: fixture\n  from_field: next_fixture\n```\n\nThe loop stops on the done Predicate holding, an iteration failing, or `max_iterations`.\nFeedback flows by **structural substitution** of the prior run's output into a named node\ninput (not string templating). Drive and inspect a Run Group with:\n\n- `caw loop init` — scaffold a complete, runnable loop-until-done example (offline).\n- `caw loop run \u003cspec\u003e` — run the loop; exit 0 (done/exhausted), 1 (an iteration failed).\n- `caw loop resume \u003cgroup-id\u003e` — resume an interrupted group without re-running completed\n  iterations (the Run Group is the resumption unit; a succeeded iteration is never re-run).\n- `caw loop report \u003cgroup-id\u003e` — aggregate every iteration into one report.\n\nTwo further controllers ship on the same Run Group infrastructure, each driven from its own\ncontroller spec file and exposing the same `init` / `run` / `resume` / `report` commands as\n`caw loop`:\n\n- **Adversarial verification** (`caw verify`) — runs a generator, then verifier nodes, and\n  **accepts**, **rejects**, or feeds verifier feedback into a regeneration run, until an\n  accept (or optional reject) Predicate holds or the round cap is reached.\n- **Tournament** (`caw tournament`) — runs candidates in rounds, promotes each round's\n  winner into the next, and reports the final winner with per-round comparison evidence.\n\n## Positioning\n\n- **vs. Claude Code dynamic workflows** — caw is not natively integrated and has no\n  background agent fleet, but it is vendor-neutral, config-as-code, source-controlled, and\n  portable across agent CLIs.\n- **vs. Airflow / Dagster / Prefect / Temporal** — caw has none of their distributed\n  durability, and deliberately so: it is far lighter, models agent-specific concerns\n  (prompts, output contracts, approval gates, token usage), and needs no service.\n- **vs. ad hoc shell scripts** — more structure to learn, in exchange for validation,\n  resume, state, reports, and reusable patterns.\n\n## Documentation\n\n- Product spec: [`docs/prd/0001-cli-agentic-workflow.md`](docs/prd/0001-cli-agentic-workflow.md)\n- Architecture decisions: [`docs/adr/`](docs/adr/) — local-first kernel (0001), run-group\n  iteration (0002), asyncio executor (0003), Python stack (0004), release model (0005),\n  Adapter interface (0006), `when` predicates and skip semantics (0007), pattern expanders\n  compile to plain IR (0008), pattern controller infrastructure and run groups (0009)\n- Domain vocabulary: [`CONTEXT.md`](CONTEXT.md)\n- CI and release flow: [`docs/release-flow.md`](docs/release-flow.md)\n\n## Development\n\nPython \u003e= 3.12, managed with [uv](https://docs.astral.sh/uv/):\n\n```bash\nuv sync                      # install\nuv run pytest                # full suite (includes the local-only e2e tier)\nuv run pytest -m \"not e2e\"   # non-e2e tier only (exactly what CI runs)\nuv run ruff check \u0026\u0026 uv run ruff format --check\nuv run mypy\n```\n\nTests exercise external behavior only — what a user observes through the CLI, the on-disk\nrun directory, or a real agent-CLI run — never internal objects or call sequences. Coverage\nspans seams that are **co-weighted**: the CLI itself, the on-disk run directory, a\nfixture-replaying mock adapter (for behaviors a fixture can verify completely offline, no\ntokens), and a real agent-CLI **e2e** tier (for behaviors whose correctness depends on the\nreal CLI). The mock complements the e2e tier; it does not replace it.\n\n### Two-tier test suite: non-e2e and e2e\n\nThe **non-e2e** tier runs everywhere with no real Agent CLI. The **e2e** tier\n(`tests/e2e/`, marked `e2e`) drives a real Agent CLI end to end — a real `claude -p` or\n`codex exec` run flowing through `caw run` into the Output Contract and State. The suite\nis agent-neutral: the same workflow shape runs under either agent, exercising the\ncapability symmetry of the two adapters. Because most real usage runs agent CLIs as nodes,\ne2e is mandatory coverage that grows as features land (new adapters, multi-node graphs,\npatterns) — not an afterthought.\n\n- **Local only, for now.** Cloud agent auth is not provisionable in GitHub Actions yet,\n  so CI runs `pytest -m \"not e2e\"` and the e2e tier is a local gate. It migrates into CI\n  once cloud auth is arranged ([#86](https://github.com/aigengame/cli-agentic-workflow/issues/86)).\n- **One selected agent.** `CAW_E2E_AGENT` chooses the agent (default `claude`; `codex`\n  also wired). Run the tier against an authenticated CLI with\n  `CAW_E2E_AGENT=claude uv run pytest -m e2e` or `CAW_E2E_AGENT=codex uv run pytest -m e2e`.\n- **Fail, never skip.** When the selected agent's CLI is unavailable the e2e tests\n  **FAIL** — they never skip — so a missing or unauthenticated CLI is never silent green.\n- **Robust assertions.** e2e checks are contract/structure-based (exit status, Output\n  Contract validation, persisted State shape), never exact model text, and a transient\n  network/5xx/rate-limit failure gets a bounded retry while assertion failures never do.\n\n## Contributing\n\nWork is tracked as GitHub issues with a triage-label workflow; issues labeled\n`ready-for-agent` are fully specified and independently grabbable. Start from\n[PRD #1](https://github.com/aigengame/cli-agentic-workflow/issues/1) for the big picture.\nCommits follow [Conventional Commits](https://www.conventionalcommits.org/).\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faigengame%2Fcli-agentic-workflow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faigengame%2Fcli-agentic-workflow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faigengame%2Fcli-agentic-workflow/lists"}