<!-- codeharness:readme -->
# lilflow

Repo-native workflow engine CLI. Define multi-step workflows in YAML, execute them with step-level persistence, and resume from failure -- all stored under `.flow/` in your repo. No external services, no databases, no daemon.

## What it does

lilflow turns YAML workflow definitions into executable, resumable pipelines that live inside your repository. It persists every step's start, completion, and failure as append-only JSONL events, so you can resume a failed run from exactly where it broke. It has first-class support for LLM coding agents (Claude Code and OpenCode) as step types, with session management across steps and two execution modes: classic (one agent process per step) and session (the entire workflow runs inside a single long-lived agent session for prompt-cache efficiency). It's for developers who want CI-like orchestration without leaving the repo.

## Key features

- **Step-level resumability** -- append-only JSONL event logs let you resume from the exact point of failure
- **LLM agent steps** -- run Claude Code or OpenCode as workflow steps with session continuation and cost tracking
- **Session mode** -- run the whole workflow inside one agent session; agent calls `flow session-bridge` CLI to advance steps. Keeps the prompt cache warm for the entire run
- **Conversational agent mode** -- `agent.mode: conversational` lets the agent iterate with the user until the step is complete, then advance
- **Structured JSON output** -- `output_file` + `output_format: json` on agent steps extracts and validates JSON from the agent's stdout, no parsing scripts required
- **Parallel execution** -- mark steps with `parallel: true` or group them with `parallel_group` for concurrent batches
- **For-each loops** -- expand a step across an array of items with `{{item}}` templating
- **Quality gates** -- conditional checkpoints that halt or warn based on expressions
- **Subflow composition** -- call child workflows with parameter passing
- **Wait triggers** -- block on file existence or external signals with `flow signal`
- **Hierarchical config** -- global, project, workflow-local, env vars, and CLI flags merge in order

## Tech stack

- **Runtime:** Node.js >= 22
- **Language:** JavaScript (ES modules)
- **Dependencies:** js-yaml (single runtime dependency)
- **Test runner:** node:test (built-in)
- **Coverage:** c8

## Getting started

### Install

```bash
npm install -g lilflow
```

### Run the simplest possible example

```bash
flow init && flow run
```

Expected output:
```
Initialized .flow/ and workflow.yaml
Running workflow 'hello-world'...
[setup] echo "Hello from flow"
Hello from flow
Workflow completed.
```

### Next step

See [Usage](#usage) for common workflows or [docs/index.md](./docs/index.md) for full docs.

## Usage

### Define and run a multi-step workflow

```yaml
name: build-and-test
steps:
  - name: install
    run: npm ci
  - name: lint
    run: npm run lint
  - name: test
    run: npm test
```

```bash
flow run
```

### Run steps in parallel

```yaml
steps:
  - name: lint
    run: npm run lint
    parallel: true
  - name: test
    run: npm test
    parallel: true
  - name: build
    run: npm run build
```

Parallel step output streams in real time with `[lint] ...` / `[test] ...` prefixes.

### Resume a failed run

```bash
flow status <run-id>    # see what failed
flow resume <run-id>    # pick up from the failed step
```

### Use LLM agents as steps

```yaml
steps:
  - name: implement
    agent:
      provider: claude-code
      prompt: "Implement the dashboard component"
  - name: review
    agent:
      provider: claude-code
      prompt: "Review the implementation"
      session: continue
```

### Agent interaction modes

Agent steps take an optional `mode` field:

- `autonomous` (default) -- agent works alone, runs headless, reports when done
- `conversational` -- agent works with the user iteratively in a TTY, advances only after user approval

```yaml
steps:
  - name: build
    agent:
      provider: claude-code
      prompt: "Build the feature described in spec.md"
      mode: conversational
```

### Extract JSON output from an agent step

```yaml
steps:
  - name: analyze
    agent:
      provider: claude-code
      prompt: ./analyze.md
      output_file: out/analysis.json
      output_format: json
```

lilflow strips markdown fences, finds the first balanced JSON object/array in stdout, validates it parses, and writes the cleaned JSON to the file. The step fails with a structured error code if the output isn't valid JSON.

### Run the entire workflow in one agent session

```yaml
name: iterative-dev
mode: session
session:
  provider: claude-code       # or: opencode (via oh-my-opencode)
  model: claude-opus-4-6
  allow_tools: [Bash, Read, Write, Edit, Grep, Glob]
  plugins: [lilflow]
steps:
  - name: scaffold
    run: mkdir -p src/components
  - name: implement
    agent:
      provider: claude-code
      prompt: "Build dashboard components"
      mode: conversational
  - name: test
    run: npm test
```

`flow run` spawns one `claude` (or `opencode`) process, injects a workflow-aware system prompt, and exposes the `flow session-bridge` CLI through the bundled `lilflow` skill. The agent drives the workflow (`flow session-bridge next` -> execute -> `flow session-bridge update`) without per-step process spawns, keeping the prompt cache warm for the entire run.

OpenCode sessions work through [oh-my-opencode](https://github.com/opensoft/oh-my-opencode)'s Claude Code compatibility layer -- the same bundled plugin loads unmodified.

### Iterate with for-each

```yaml
steps:
  - name: deploy
    run: ./deploy.sh {{item}}
    for_each: [dev, staging, prod]
```

### Wait for external input

```yaml
steps:
  - name: await-approval
    wait:
      trigger: signal
      timeout: 1h
```

Then from another terminal: `flow signal <run-id> await-approval --data '{"approved": true}'`

## CLI

```
flow init [--template <name>]
flow config
flow run [<workflow>]
flow resume <run-id>
flow set-step <run-id> <step-index>
flow signal <run-id> <step-name> [--data '{}']
flow status <run-id>
flow list
flow logs <run-id> [--step <step>]
flow session-bridge <subcommand>     # agent-facing bridge for session-mode workflows
```

## Claude Code plugin

This repo is also a Claude Code plugin. `.claude-plugin/plugin.json` is the marker file; `skills/` holds the `lilflow-workflow-driver` skill used by session mode. The plugin version is kept in lock-step with the npm package version via the `npm version` lifecycle hook, so a single `v{version}` tag releases both.

Install as a plugin from a Claude Code session:
```bash
claude plugin install github:iVintik/lilflow
```

OpenCode users install the same plugin via [oh-my-opencode](https://github.com/opensoft/oh-my-opencode)'s Claude Code compatibility layer.

## Project structure

```
lilflow/
├── src/                    # Application source (ES modules)
│   ├── cli.js              # Entry point, command router
│   ├── run-workflow.js     # Core workflow engine
│   ├── config.js           # Hierarchical config system
│   ├── init-project.js     # Project scaffolding
│   ├── session-bridge.js   # Agent-facing CLI for session mode
│   ├── session-runner.js   # Single-process execution path
│   ├── session-prompt.js   # System prompt generator
│   └── agents/             # LLM agent provider adapters + output extraction
├── .claude-plugin/         # Claude Code plugin manifest
│   └── plugin.json
├── skills/                 # Claude Code skills bundled with the plugin
│   └── lilflow-workflow-driver/SKILL.md
├── scripts/                # Release helpers (sync-plugin-version.js)
├── tests/                  # Test suite (node:test)
├── docs/                   # Generated documentation + requirements specs
└── .github/workflows/      # CI/CD (lint + test + npm publish)
```

## Documentation

- [Documentation Index](./docs/index.md)
- [Architecture](./docs/architecture.md)
- [Component Inventory](./docs/component-inventory.md)
- [Source Tree Analysis](./docs/source-tree-analysis.md)
- [Development Guide](./docs/development-guide.md)
- [Session Mode Spec](./docs/requirements/session-mode.md)

## License

MIT
<!-- /codeharness:readme -->
