From 95b6847939e0badf669135d5eeb8e6ec86e2dfc4 Mon Sep 17 00:00:00 2001 From: Erwan Lee Pesle Date: Sat, 9 May 2026 11:36:37 +0800 Subject: [PATCH 1/2] docs(skills/acpx): update SKILL.md to 0.7 surface The bundled skill currently lags behind the 0.7 release. This PR brings the document up to date with the API and CLI surface that ships today. Additions: - Frontmatter description now mentions system-prompt overrides and the defineFlow/decision/decisionEdge authoring API so triggering reflects what users actually invoke acpx for in 0.7. - New global flags documented: --system-prompt, --append-system-prompt, --no-terminal, --prompt-retries, --allowed-tools, --max-turns, --non-interactive-permissions, --json-strict. - Sessions section gains `sessions ensure` (idempotent get-or-create) and `sessions prune` (--dry-run, --before, --older-than, --include-history) with behavior notes. - New "System prompt override (Claude)" section explaining the _meta.systemPrompt forwarding, persistence into session_options, and the cross-agent ignore semantics. - New "Sessions cleanup" section with retention examples. - "Flow run" mention is replaced by a full "Flows (multi-agent workflows)" section: complete defineFlow example (pr-triage), table of node types (acp/decision/action/compute/checkpoint), three edge shapes (linear, JSONPath switch, decisionEdge), and a short rationale for cross-vendor / replay / permission preflight / typed routing. - Practical workflows gains a Claude reviewer with persistent --system-prompt, an `ensure`-based script bootstrap, a prune retention example, and a flow run example. Sources cross-checked against docs/CLI.md, docs/flows.md, examples/flows/branch.flow.ts, and the 0.7.0 binary --help output. No assertions made about features that are not in 0.7. AI-assisted: drafted with Claude (Opus 4.7). Lightly tested locally: - SKILL.md renders correctly in Claude Code skill loader. - Code samples mirror examples/flows/branch.flow.ts verbatim where applicable; CLI snippets verified against acpx 0.7.0 --help. No source code changed, so build/check/test are unaffected. CI will confirm. --- skills/acpx/SKILL.md | 215 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 205 insertions(+), 10 deletions(-) diff --git a/skills/acpx/SKILL.md b/skills/acpx/SKILL.md index a1e974e..6be75ab 100644 --- a/skills/acpx/SKILL.md +++ b/skills/acpx/SKILL.md @@ -1,13 +1,13 @@ --- name: acpx -description: Use acpx as a headless ACP CLI for agent-to-agent communication, including prompt/exec/sessions workflows, session scoping, queueing, permissions, and output formats. +description: Use acpx as a headless ACP CLI for agent-to-agent communication, including prompt/exec/sessions workflows, session scoping, queueing, permissions, output formats, system-prompt overrides, and multi-agent flows authored with defineFlow/decision/decisionEdge. --- # acpx ## When to use this skill -Use this skill when you need to run coding agents through `acpx`, manage persistent ACP sessions, queue prompts, or consume structured agent output from scripts. +Use this skill when you need to run coding agents through `acpx`, manage persistent ACP sessions, queue prompts, override the Claude system prompt, prune stale sessions, consume structured agent output from scripts, or compose multi-agent workflows declaratively with `acpx/flows`. ## What acpx is @@ -18,6 +18,8 @@ Core capabilities: - Persistent multi-turn sessions per repo/cwd - One-shot execution mode (`exec`) - Named parallel sessions (`-s/--session`) +- Idempotent session creation (`sessions ensure`) +- Session retention controls (`sessions prune` with age filters and history cleanup) - Queue-aware prompt submission with optional fire-and-forget (`--no-wait`) - Cooperative cancel command (`cancel`) for in-flight turns - Graceful cancellation via ACP `session/cancel` on interrupt @@ -31,7 +33,10 @@ Core capabilities: - Stable ACP `authenticate` handshake via env/config credentials - Structured streaming output (`text`, `json`, `quiet`) with optional `--suppress-reads` - Built-in agent registry plus raw `--agent` escape hatch -- Experimental `flow run` support with `acpx/flows` helpers, including constrained-choice `decision()` branching +- Claude system prompt override via `--system-prompt` / `--append-system-prompt` +- Optional terminal capability disable via `--no-terminal` for review-only flows +- Tool whitelist (`--allowed-tools`), turn cap (`--max-turns`), retry on transient failures (`--prompt-retries`) +- Multi-agent flows via `acpx flow run` and the `acpx/flows` authoring API (`defineFlow`, `decision`, `decisionEdge`, `acp`, `action`, `compute`, `checkpoint`) ## Install @@ -53,8 +58,9 @@ acpx [global_options] cancel [-s ] acpx [global_options] set-mode [-s ] acpx [global_options] set [-s ] acpx [global_options] status [-s ] -acpx [global_options] sessions [list | new [--name ] | close [name] | show [name] | history [name] [--limit ]] +acpx [global_options] sessions [list | new [--name ] | ensure [--name ] | close [name] | show [name] | history [name] [--limit ] | prune [--dry-run] [--before | --older-than ] [--include-history]] acpx [global_options] config [show | init] +acpx [global_options] flow run [--input-json '' | --input-file ] [--default-agent ] acpx [global_options] [prompt_options] [prompt_text...] acpx [global_options] prompt [prompt_options] [prompt_text...] @@ -63,7 +69,7 @@ acpx [global_options] cancel [-s ] acpx [global_options] set-mode [-s ] acpx [global_options] set [-s ] acpx [global_options] status [-s ] -acpx [global_options] sessions [list | new [--name ] | close [name] | show [name] | history [name] [--limit ]] +acpx [global_options] sessions [list | new [--name ] | ensure [--name ] | close [name] | show [name] | history [name] [--limit ] | prune [--dry-run] [--before | --older-than ] [--include-history]] ``` If prompt text is omitted and stdin is piped, `acpx` reads prompt text from stdin. @@ -167,17 +173,23 @@ acpx sessions acpx sessions list acpx sessions new acpx sessions new --name backend +acpx sessions ensure +acpx sessions ensure --name backend acpx sessions close acpx sessions close backend acpx sessions show acpx sessions history --limit 20 +acpx sessions prune --dry-run --older-than 7d +acpx sessions prune --older-than 30d --include-history acpx status acpx codex sessions acpx codex sessions new --name backend +acpx codex sessions ensure --name backend acpx codex sessions close backend acpx codex sessions show backend acpx codex sessions history backend --limit 20 +acpx codex sessions prune --before 2026-04-01 --include-history acpx codex status ``` @@ -187,10 +199,15 @@ Behavior: - `new` creates a fresh session for the current `(agentCommand, cwd, optional name)` scope - `new --name ` targets a named session scope - when `new` replaces an existing open session in that scope, the old one is soft-closed +- `ensure` returns the nearest matching active session for the scope, or creates one when none is open. Idempotent — safe to call before every prompt in scripts. - `close` targets current cwd default session - `close ` targets current cwd named session - `show [name]` prints stored metadata for that scoped session - `history [name]` prints stored turn history previews (default 20, use `--limit`) +- `prune` deletes closed session records to reclaim disk space + - `--dry-run` previews what would be deleted without touching disk + - `--older-than ` and `--before ` filter by close time, falling back to last-used time when a record was never explicitly closed + - `--include-history` also removes per-session event stream files (otherwise only the JSON record is removed) ## Global options @@ -199,15 +216,54 @@ Behavior: - `--approve-all`: auto-approve all permission requests - `--approve-reads`: auto-approve reads/searches, prompt for writes (default mode) - `--deny-all`: deny all permission requests +- `--non-interactive-permissions `: when prompting is unavailable, choose `deny` or `fail` - `--format `: output format (`text`, `json`, `quiet`) +- `--json-strict`: strict JSON mode; requires `--format json` and suppresses non-JSON stderr output - `--suppress-reads`: suppress raw read-file contents while preserving the selected format - `--timeout `: max wait time (positive number) - `--ttl `: queue owner idle TTL before shutdown (default `300`, `0` disables TTL) - `--model `: request an agent model during session creation; non-Claude agents must advertise ACP models and support `session/set_model` +- `--system-prompt `: replace the agent system prompt. Forwarded to claude-agent-acp via ACP `_meta.systemPrompt`; persisted in `session_options.system_prompt` so reuse keeps the override. Other agents ignore the field. +- `--append-system-prompt `: append text to the agent system prompt. Forwarded to claude-agent-acp via ACP `_meta.systemPrompt.append`; same persistence rules as `--system-prompt`. +- `--allowed-tools `: comma-separated tool whitelist (use `""` for no tools) +- `--max-turns `: cap session turn count +- `--prompt-retries `: retry failed prompt turns on transient errors (default `0`) +- `--no-terminal`: do not advertise the ACP terminal capability — useful for review-only or sandboxed agent invocations - `--verbose`: verbose ACP/debug logs to stderr Permission flags are mutually exclusive. +## System prompt override (Claude) + +`--system-prompt` and `--append-system-prompt` let you specialize a Claude session without leaving lingering one-off state, while still benefiting from persistent session reuse. + +```bash +# Replace the system prompt for a named session, persisted across reuse +acpx --system-prompt "You are a code reviewer who challenges every implicit assumption." claude -s review + +# Append a guideline on top of the default system prompt +acpx --append-system-prompt "Always explain trade-offs before recommending a fix." claude -s impl +``` + +The override is forwarded via ACP `_meta.systemPrompt` (or `_meta.systemPrompt.append`) on `session/new` and stored in `session_options.system_prompt`. Subsequent `prompt`/`ensure` calls in the same scope keep the override unless you explicitly create a new session. Non-Claude adapters ignore the field, so the same flag is safe inside cross-agent scripts. + +## Sessions cleanup + +Closed session records accumulate on disk by default. Use `sessions prune` to enforce retention: + +```bash +# Preview what would be deleted (no writes) +acpx codex sessions prune --dry-run --older-than 7d + +# Remove records closed more than 30 days ago, including their event-stream files +acpx codex sessions prune --older-than 30d --include-history + +# Remove everything closed before a date +acpx codex sessions prune --before 2026-04-01 +``` + +Without `--include-history`, only the lightweight JSON record is removed; event-stream files are preserved for audit. With it, the per-session event log is also deleted to reclaim disk space. + ## Config files Config files are merged in this order (later wins): @@ -219,6 +275,7 @@ Supported keys: - `defaultAgent` - `defaultPermissions` (`approve-all`, `approve-reads`, `deny-all`) +- `nonInteractivePermissions` (`deny`, `fail`) - `ttl` (seconds) - `timeout` (seconds or `null`) - `format` (`text`, `json`, `quiet`) @@ -245,7 +302,7 @@ Persistence: - Session records are stored in `~/.acpx/sessions/*.json`. - `-s/--session` creates parallel named conversations in the same repo. - Changing `--cwd` changes scope and therefore session lookup. -- closed sessions are retained on disk with `closed: true` and `closedAt`. +- closed sessions are retained on disk with `closed: true` and `closedAt` until pruned. - auto-resume by scope skips closed sessions. Resume behavior: @@ -282,6 +339,7 @@ Use `--format `: - `json`: NDJSON event stream (good for automation) - `quiet`: final assistant text only - `--suppress-reads`: replace raw read-file contents with `[read output suppressed]` in `text` and `json` output +- `--json-strict`: pair with `--format json` to suppress non-JSON stderr noise (logs, banners) for downstream consumers Example automation: @@ -295,9 +353,126 @@ acpx --format json codex exec 'review changed files' \ - `--approve-all`: no interactive permission prompts - `--approve-reads` (default): approve reads/searches, prompt for writes - `--deny-all`: deny all permission requests +- `--non-interactive-permissions `: chosen behavior when no TTY is available to prompt If every permission request is denied/cancelled and none approved, `acpx` exits with permission-denied status. +## Flows (multi-agent workflows) + +Flows let you declare a multi-agent workflow as a graph of typed nodes connected by edges, executed by the `acpx` runtime. The runtime owns persistence, retries, timeouts, and routing — the flow file declares the shape, not the engine. + +### Run a flow + +```bash +acpx flow run ./my-flow.flow.ts --input-file ./flow-input.json +acpx flow run ./my-flow.flow.ts --input-json '{"task":"FIX: add a regression test"}' +acpx --approve-all flow run examples/flows/pr-triage/pr-triage.flow.ts \ + --input-json '{"repo":"openclaw/acpx","prNumber":150}' +acpx flow run ./my-flow.flow.ts --default-agent claude +``` + +Run artifacts persist under `~/.acpx/flows/runs//`. Default per-step timeout is 15 minutes when `--timeout` is unset; flows that declare permission requirements fail fast before starting. + +### Authoring a flow + +The authoring surface lives in `acpx/flows`. The minimal example: + +```ts +import { + acp, + decision, + decisionEdge, + defineFlow, + checkpoint, + extractJsonObject, +} from "acpx/flows"; + +const choices = ["bug", "feat", "doc"] as const; + +export default defineFlow({ + name: "pr-triage", + startAt: "classify", + nodes: { + classify: decision({ + choices, + question: ({ input }) => + `Classify the PR description below. Reply with one of: ${choices.join(", ")}.\n\n${input.description}`, + }), + bug_lane: acp({ + prompt: ({ outputs }) => + `The PR is a bug. Write a regression test that reproduces it.\n\nDecision context: ${JSON.stringify(outputs.classify)}`, + parse: (text) => extractJsonObject(text), + }), + feat_lane: acp({ + prompt: () => "List acceptance criteria for the feature, one bullet per criterion.", + }), + doc_lane: checkpoint({ + summary: "doc change — needs human review", + run: ({ outputs }) => ({ route: "doc", note: outputs.classify }), + }), + }, + edges: [ + decisionEdge({ + from: "classify", + choices, + cases: { + bug: "bug_lane", + feat: "feat_lane", + doc: "doc_lane", + }, + }), + ], +}); +``` + +### Node types + +| Type | Purpose | +| --- | --- | +| `acp({ prompt, parse?, agent?, cwd? })` | Model-driven step. The `prompt` builder receives `{ input, outputs }`. Optional `parse` coerces the raw text (e.g., `extractJsonObject`). | +| `decision({ choices, question })` | Constrained-choice LLM step. `choices` is a `readonly` tuple; the runtime validates the model's reply against it and TypeScript infers the union from `choices`. | +| `action(...)` | Runtime-supervised deterministic operation: shell, GitHub API, test execution, comment posting. | +| `compute(...)` | Pure local data transform: normalization, routing key derivation, signal reduction. | +| `checkpoint({ summary, run })` | Pause point for human or external trigger. `run` returns the outcome to record while paused. | + +### Edge shapes + +```ts +// Linear edge +{ from: "node", to: "next" } + +// JSONPath switch — non-decision routing +{ + from: "node", + switch: { + on: "$.route", + cases: { "value-a": "branch_a", "value-b": "branch_b" }, + }, +} + +// Decision edge — exhaustive at compile time +decisionEdge({ + from: "classify", + choices, // same readonly tuple as decision() + cases: { // every choice must map to a node id + bug: "bug_lane", + feat: "feat_lane", + doc: "doc_lane", + }, +}) +``` + +If a `decisionEdge` omits a case from `choices`, the TypeScript compiler refuses to compile — so a flow can't ship with a forgotten branch when new choices are added. + +### Why use flows + +- **Cross-vendor by construction**: classify with `codex`, write code with `claude`, summarize with `gemini` — same flow file, no glue. +- **Persistence and replay**: every run streams events to disk, replayable via the flow viewer under `~/.acpx/flows/runs/`. +- **Permission preflight**: flows declaring permission requirements fail before any agent starts, instead of mid-run. +- **Typed routing**: the LLM is constrained to a literal union, the compiler verifies exhaustivity, the runtime validates the reply. + +See `examples/flows/` in the repo for working samples (`branch.flow.ts`, `pr-triage/`, `two-turn.flow.ts`, `shell.flow.ts`, `workdir.flow.ts`). + ## Practical workflows Persistent repo assistant: @@ -314,6 +489,20 @@ acpx codex -s backend 'fix API pagination bug' acpx codex -s docs 'draft changelog entry for release' ``` +Specialized Claude reviewer that survives session reuse: + +```bash +acpx --system-prompt "You are a reviewer who refuses to approve untested changes." claude -s reviewer +acpx claude -s reviewer 'review the diff in src/auth/' +``` + +Idempotent session bootstrap (safe to call before every prompt in scripts): + +```bash +acpx codex sessions ensure -s ci +acpx codex -s ci 'run the smoke suite and report failures' +``` + Queue follow-up without waiting: ```bash @@ -330,7 +519,7 @@ acpx --format quiet exec 'summarize repo purpose in 3 lines' Machine-readable output for orchestration: ```bash -acpx --format json codex 'review current branch changes' > events.ndjson +acpx --format json --json-strict codex 'review current branch changes' > events.ndjson ``` Raw custom adapter command: @@ -339,11 +528,17 @@ Raw custom adapter command: acpx --agent './bin/custom-acp-server --profile ci' 'run validation checks' ``` -Flow run: +Periodic cleanup: + +```bash +acpx codex sessions prune --dry-run --older-than 14d +acpx codex sessions prune --older-than 30d --include-history +``` + +Multi-agent triage flow: ```bash -acpx flow run ./my-flow.ts --input-file ./flow-input.json -acpx flow run examples/flows/branch.flow.ts --input-json '{"task":"FIX: add a regression test"}' +acpx --approve-all flow run ./pr-triage.flow.ts --input-json '{"prNumber": 842}' ``` Repo-scoped review with permissive mode: From c3c31c970b7a622ff8d8f72f1391bb3bd5b647a1 Mon Sep 17 00:00:00 2001 From: Erwan Lee Pesle Date: Sat, 9 May 2026 15:52:36 +0800 Subject: [PATCH 2/2] fix(skills/acpx): --older-than takes integer days, not Nd suffix The CLI surface confirmed by acpx 0.7.0 --help: --older-than Prune sessions closed more than N days ago Fixing the prune examples accordingly: 7d/14d/30d -> 7/14/30. --- skills/acpx/SKILL.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/skills/acpx/SKILL.md b/skills/acpx/SKILL.md index 6be75ab..def1bab 100644 --- a/skills/acpx/SKILL.md +++ b/skills/acpx/SKILL.md @@ -179,8 +179,8 @@ acpx sessions close acpx sessions close backend acpx sessions show acpx sessions history --limit 20 -acpx sessions prune --dry-run --older-than 7d -acpx sessions prune --older-than 30d --include-history +acpx sessions prune --dry-run --older-than 7 +acpx sessions prune --older-than 30 --include-history acpx status acpx codex sessions @@ -253,10 +253,10 @@ Closed session records accumulate on disk by default. Use `sessions prune` to en ```bash # Preview what would be deleted (no writes) -acpx codex sessions prune --dry-run --older-than 7d +acpx codex sessions prune --dry-run --older-than 7 # Remove records closed more than 30 days ago, including their event-stream files -acpx codex sessions prune --older-than 30d --include-history +acpx codex sessions prune --older-than 30 --include-history # Remove everything closed before a date acpx codex sessions prune --before 2026-04-01 @@ -531,8 +531,8 @@ acpx --agent './bin/custom-acp-server --profile ci' 'run validation checks' Periodic cleanup: ```bash -acpx codex sessions prune --dry-run --older-than 14d -acpx codex sessions prune --older-than 30d --include-history +acpx codex sessions prune --dry-run --older-than 14 +acpx codex sessions prune --older-than 30 --include-history ``` Multi-agent triage flow: