Files

340 lines
17 KiB
Markdown

# agent-workflow
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![Node.js](https://img.shields.io/badge/node-%3E%3D20-green.svg)](https://nodejs.org)
**Codex or Claude hosted autonomous implementation loop with Reasonix, Claude Code, Agy, and Codex executors.**
`agent-workflow` orchestrates a stateful implement-review-fix cycle where:
- **Codex or Claude** acts as the host planner, reviewer, and final acceptance authority
- **Reasonix, Claude Code, Agy, or Codex** executes implementation and fixes in the same session
- The workflow maintains atomic state, VCS baseline gates, scope enforcement, and convergence limits
- Supports both **Git** and **SVN** working copies with strict validation
## Prerequisites
- Node.js >= 20
- Git repository or SVN working copy
- At least one executor: [Reasonix](https://reasonix.ai), [Claude Code](https://claude.ai/code), [Agy](https://agy.dev), or Codex
## Installation
```bash
npm install -g agent-workflow
```
Or use locally in a project:
```bash
npm install --save-dev agent-workflow
```
## Host Skill Installation
The `agent-workflow-host` skill provides the instructions for Codex or Claude to act as the workflow host.
### Codex
Codex uses `~/.codex/skills/agent-workflow-host`.
```bash
mkdir -p ~/.codex/skills/agent-workflow-host
cp node_modules/agent-workflow/skills/agent-workflow-host/SKILL.md ~/.codex/skills/agent-workflow-host/
```
### Claude Code
Claude uses `~/.claude/skills/agent-workflow-host`.
```bash
mkdir -p ~/.claude/skills/agent-workflow-host
cp node_modules/agent-workflow/skills/agent-workflow-host/SKILL.md ~/.claude/skills/agent-workflow-host/
```
## Quick Start
1. Create a plan (WorkflowPlanV1 JSON):
```json
{
"version": "1",
"title": "Add user authentication",
"planMarkdown": "Implement JWT-based authentication with login and logout endpoints.",
"scope": ["src/auth/", "src/routes/auth.ts"],
"acceptanceCriteria": [
"Login endpoint returns valid JWT",
"Protected routes reject unauthenticated requests",
"All tests pass"
],
"verificationCommands": [
["npm", "test"],
["npm", "run", "lint"]
]
}
```
2. Start a workflow:
```bash
agent-workflow start --plan plan.json --executor reasonix
```
3. Review the implementation:
```bash
agent-workflow review --run <run-id> --reviewer <codex|claude>
```
4. Submit a decision (fix, accept, or needs_human):
```bash
agent-workflow decide --run <run-id> --input decision.json --reviewer <codex|claude>
```
## Commands
### `agent-workflow start`
Start a new workflow run. Requires a clean working tree.
```bash
agent-workflow start --plan <plan.json|-> --executor <reasonix|claude|agy|codex> [--reviewer <codex|claude>] [--vcs <git|svn|none>] [--max-cycles <n>] [--new-task]
```
- `--vcs` - Explicitly specify VCS kind (`git`, `svn`, or `none`). If omitted, auto-detects from the working directory. If neither Git nor SVN is detected, it automatically falls back to `none` (snapshot mode).
- When `CODEX_THREAD_ID` is available, runs in the same Codex thread and repository share a current task. Each executor is created lazily on first use and its reliable session handle is reused by later plans in that task.
- `--new-task` creates a new task boundary and clears all three lazy executor bindings. Use it only when the conversation has moved to a materially different task.
- Claude, Reasonix, Agy, and Codex bindings remain separate. Selecting another executor does not switch an active run; it starts or resumes that executor only in a later run after the repository is clean.
- Agy sessions without a captured conversation ID are not shared because `--continue` cannot guarantee which conversation will be selected.
- Git and SVN working copies are automatically detected when `--vcs` is not provided.
- SVN working copies must be in a clean, consistent state (no mixed revisions, switched paths, externals, or conflicts).
- None (snapshot) mode skips clean checks, capturing the directory state of the working directory and storing it in the run directory.
### `agent-workflow review`
Generate a host review bundle after executor completion. Checks HEAD stability and scope compliance.
```bash
agent-workflow review --run <run-id> --reviewer <codex|claude>
```
Once the run is at or past the guidance threshold — the executor cycle about to start is `>= 3` (i.e. reviewing cycle 2, so the next fix cycle would be the third round) — the bundle sets `detailedGuidanceRequested: true` and includes a `reviewerInstructions` string. This asks the host, if it decides `fix`, to return a concrete step-by-step implementation plan so the executor can converge quickly.
### `agent-workflow decide`
Submit a host decision (fix, accept, or needs_human). A fix decision resumes the same executor session.
```bash
agent-workflow decide --run <run-id> --input <decision.json|-> --reviewer <codex|claude>
```
A `fix` decision may include an optional `implementationGuidance` string (up to 20000 characters). When present, it is injected verbatim into the executor's fix prompt under a `## Detailed Implementation Guidance` section, and the frozen plan's `planMarkdown` and acceptance criteria are re-sent alongside it so the executor has full context. This is the channel the host uses to answer the bundle's `detailedGuidanceRequested` signal, and it flows through the normal fix, `retry-execute`, and `extend` paths.
### `agent-workflow retry-review`
Retry review after the executor has removed approved out-of-scope artifacts.
```bash
agent-workflow retry-review --run <run-id> --reviewer <codex|claude>
```
### `agent-workflow retry-execute`
Retry executor resume after clearing an external session conflict.
```bash
agent-workflow retry-execute --run <run-id>
```
If a failed Claude launch recorded a session ID that was never created, explicitly bind a known persisted Claude session from the same repository and frozen plan while retrying:
```bash
agent-workflow retry-execute --run <run-id> --session <claude-or-codex-session-id>
```
The override is accepted only for Claude and Codex runs. For Claude the session JSONL must exist under `~/.claude/projects`; for Codex it is searched under `~/.codex/sessions` and `~/.codex/archived_sessions`. The session must belong to the run repository and contain the frozen plan title. Baseline, scope, and review-artifact gates still apply, and the old/new session IDs are appended to the workflow audit log.
For Reasonix runs blocked after a session handle was not captured, `retry-execute` automatically recovers the persisted session only when its project directory, frozen plan title, and execution time window match the run. The recovery is recorded in the workflow audit log.
### `agent-workflow status`
Display current workflow status.
```bash
agent-workflow status --run <run-id> [--json]
```
When the workflow is executing, additional live fields are shown:
- **Executor PID** — process ID of the running executor
- **Elapsed** — running time
- **Activity** — current operation being performed
- **Last activity** — timestamp of most recent output
- **Log bytes** — bytes written to the attempt log so far
- **Live log** — path to the streaming log file
### `agent-workflow logs`
Tail and follow live executor output for a running workflow.
```bash
agent-workflow logs --run <run-id> [--follow] [--tail <lines>]
```
- **`--follow` / `-f`** — continuously follow new output. Automatically switches to new retry attempt logs when a retry begins.
- When `CODEX_THREAD_ID` is set, only one `--follow` process for a given Run is allowed per Codex thread. A duplicate follower is rejected without affecting the executor; stale locks from dead followers are cleaned automatically. Different threads and manual viewers without `CODEX_THREAD_ID` remain allowed.
- **`--tail <lines>`** — number of lines to show from the end of the current log (default: 50).
Examples:
```bash
# Show the last 50 lines of the current attempt log
agent-workflow logs --run <run-id>
# Follow new output (like tail -f)
agent-workflow logs --run <run-id> --follow
# Show the last 200 lines
agent-workflow logs --run <run-id> --tail 200
```
### `agent-workflow web`
Start a local web console to monitor agent executions, runs, cycles, and logs in real-time, and to manage host-wide executor model overrides.
```bash
agent-workflow web [--port <n>]
```
- **`--port <n>`** — specify a custom port to listen on (default: `4317`).
- **Security & Scope** — The server binds exclusively to the loopback interface (`127.0.0.1`) for local-only access. It refuses any external or remote listener configurations. Since executor logs can contain sensitive code, configuration details, or tokens/credentials, binding to `127.0.0.1` ensures that the console remains local. Mutation endpoints require same-origin localhost requests, JSON content type, bounded bodies, and validated model values. Credentials are never returned to the browser.
- **Workflow monitoring remains read-only** — The console provides no endpoints to start, stop, decide, or otherwise control workflow runs. It parses and displays execution progress, cycles, timeline, and stdout/stderr output. It cannot recover or display private reasoning tokens/processes of underlying models that are not output to the console.
- **Writable global model settings** — The Chinese “全局执行器模型配置” view can independently set Claude, Agy, Reasonix, and Codex models. Discovery uses the current CLI environment: Claude via Anthropic `/v1/models` (with configured-default fallback), Agy via `agy models`, and Reasonix via `reasonix doctor --json` provider/model entries. Reasonix candidates use the CLI-compatible `provider/model` form, with provider-only fallback when no concrete model is listed. CLI discovery allows up to 15 seconds for executor startup; HTTP model discovery remains bounded separately. Discovery failures are isolated per executor, and manual entry always remains available. Saving atomically updates only `executors.<kind>.model` in `~/.agent-workflow/config.json`, preserves unrelated fields, and clears an override when the value is emptied. Active executors are not interrupted; saved models take effect on later cycles, scope remediation, extensions, and executor retries through the existing reload path. Project configuration continues to override global values.
- **Interaction with `logs --follow`** — The web server directly reads the persisted run files without taking any logs follow locks or interfering with the main executor loop, allowing you to use both the CLI `logs --follow` and the web console concurrently.
### `agent-workflow abort`
Terminate an active workflow.
```bash
agent-workflow abort --run <run-id> --reason "requirements changed"
```
### `agent-workflow extend`
Extend a `budget_exhausted` run with additional cycles. The run must have ended at `budget_exhausted` status with a valid session handle and a final `fix` decision.
```bash
agent-workflow extend --run <run-id> --additional-cycles <n>
```
This allows continuation of the same executor session after reaching the cycle limit, preserving all audit history and convergence checks.
## Configuration
Create `agent-workflow.json` in your repository root, and optionally create `~/.agent-workflow/config.json` for host-wide defaults. Settings are merged per field with the following precedence:
1. CLI flags (`--executor`, `--vcs`, `--max-cycles`)
2. `agent-workflow.json` in the project root
3. `~/.agent-workflow/config.json`
4. Built-in defaults
```json
{
"version": "1",
"defaultExecutor": "reasonix",
"defaultVcs": "auto",
"maxCycles": 5,
"timeoutSeconds": 1800,
"executors": {
"reasonix": {
"binary": "reasonix",
"model": "claude-opus-4"
},
"claude": {
"binary": "claude"
},
"agy": {
"binary": "agy",
"agent": "code-assistant"
}
}
}
```
`timeoutSeconds` is an inactivity timeout, not a total runtime limit. The host resets the timeout whenever the executor emits stdout/stderr progress, so an active task may run longer than the configured window. A continuously silent executor is terminated after the configured number of seconds. Agy receives a 24-hour internal print-mode ceiling while the host inactivity timeout remains the primary stuck-process guard.
- `defaultVcs` - Default VCS kind: `"auto"` (detect), `"git"`, `"svn"`, or `"none"`. Default is `"auto"`.
- `model` - Executor model identifier (accepted as any non-empty string). When set, it is passed to Claude, Agy, Reasonix, and Codex. The effective model is reloaded from the latest config before each later cycle, scope remediation, cycle extension, and executor retry, so mid-run model changes take effect without starting a new run. Binary path, agent, profile, budget, timeout, and other executor settings are locked at run start.
Configuration files are forbidden from storing secrets (`apiKey`, `token`, `secret`, `password`, `credential`, etc.). If the latest config is invalid or the reloaded `model` is empty, the run enters a `blocked` state before launching the executor. After correcting the config, the same run can continue with `agent-workflow retry-execute --run <run-id>`.
The path used to load `agent-workflow.json` is persisted with the run so later model reloads use the same config source for Git, SVN, and snapshot-mode repositories.
## Environment Variables
- `AGENT_WORKFLOW_DIR` — Override state root (default: `~/.agent-workflow/workflows`)
- `AGENT_WORKFLOW_META_STDOUT` — Emit metadata to stdout instead of stderr (set to `1`)
- `CODEX_THREAD_ID` — Supplied by Codex. Enables task-level executor session reuse for the current Codex thread and repository. Without it, each workflow run keeps the previous standalone behavior.
Task bindings are stored under the workflow state root, outside the target repository. Before reuse, the host checks the owning Codex thread, repository, task, executor kind, and persisted executor session. A missing or mismatched session blocks reuse instead of silently selecting a recent session. Start with `--new-task` only when a fresh task is intended.
The Agy adapter runs its non-interactive implementation sessions with
`--dangerously-skip-permissions`. This is required because Agy cannot prompt for
tool approval in `--print` mode. The workflow's frozen scope, Git gates, and
executor safety prompt remain the authorization boundary. Its internal
`--print-timeout` is set to a 24-hour internal ceiling so active tasks do not
fall back to Agy's five-minute default; the workflow inactivity timeout remains
the primary guard.
## State Machine
```
executing → awaiting_review → awaiting_host → executing (next cycle)
↘ awaiting_scope_resolution ↗
Any active state → completed | needs_human | blocked | budget_exhausted | aborted
```
## Scope Gates
All file modifications must stay within the approved scope. Out-of-scope changes trigger `awaiting_scope_resolution`, where the host inspects each violation and decides whether to remove it or escalate to `needs_human`.
## VCS Support
### Git
Standard Git repositories are fully supported with baseline HEAD tracking and diff generation.
### SVN (Strict Mode)
SVN working copies are supported with strict validation:
- **Requires**: Single consistent revision (no mixed revisions)
- **Rejects**: Switched paths, externals, conflicts, incomplete states, locked files
- **Baseline**: Repository URL, UUID, and working revision
- **Diff**: Tracks modifications, additions (including unversioned), deletions, and property changes
- The workflow never runs `svn commit`, `svn switch`, or `svn update`
### None (Snapshot Mode)
Used for directories without any version control system.
- **Trigger**: Runs automatically when no Git or SVN repository is found, or when forced using `--vcs none` (or config `defaultVcs: "none"`).
- **Clean Checks**: Skips standard VCS cleanliness checks.
- **Baseline**: Captures and writes metadata, file paths, size/content hashes, text contents, and symlink targets into `baseline-snapshot.json` in the workflow run directory.
- **Diff**: Generates clean unified diffs by comparing active file systems with the captured baseline.
- **Ignores**: Automatically honors POSIX relative rules in `.gitignore` and `.agent-workflowignore`. Directories like `.git` and `.svn` are always ignored. Only files outside the ignore boundaries are checked against scope gates.
- **Safety constraints**: Dynamic executor safety prompts are adapted so that executors do not attempt to run `git status` or `svn status`.
## Convergence Limits
The workflow stops with `needs_human` when:
- The same finding persists across 2+ consecutive cycles
- Findings oscillate (disappear then reappear)
## Development
```bash
npm install
npm run build
npm test
npm run check
```
## License
MIT — see [LICENSE](./LICENSE) and [NOTICE](./NOTICE) for details.