CLI reference
The extension is invoked as gh wm <subcommand> when installed via gh extension install. Building from source produces a binary named gh-wm (same commands as the root Cobra app in cmd/root.go
).
Global
- Root use string:
gh-wm(binary name). - Short description: GitHub Workflow Manager — run gh-aw-style task markdown in CI.
version
Purpose: Print the installed gh-wm version (and optional Git commit line for release builds).
Usage:
gh wm version— printsgh-wm <version>on one line; if the binary was built with a commit SHA (release workflow), printscommit: <short-sha>on a second line.gh wm --version/gh wm -v— same version string via the root Cobra flag.
Local and CI builds without linker flags report dev. Release assets built from a git tag embed the tag (without the leading v) and a short commit hash. See cmd/version.go
and .github/workflows/release.yml
.
init
Purpose: Create .wm/ layout, starter tasks, and generate .github/workflows/wm-agent.yml.
Usage: gh wm init
Steps (see cmd/init.go
):
- Create
.wm/tasks/. - Write embedded
config.ymland starter tasks (internal/templates). - Validate task markdown bodies for gh-aw–compatible
${{ }}expressions (see Task format — expressions ) usingcompat.gh_aw_expressionsin.wm/config.yml(defaulterror). - Collect workflow
on:triggers from.wm/tasks(union ofissues/issue_comment/pull_requesttypes,slash_command→issue_comment,schedulecrons, and alwaysworkflow_dispatch) viagen.CollectTriggersFromTasksDir, then generatewm-agent.ymlviagen.WriteWMAgent(same pipeline asgh wm compile), includingworkflow.runs_onfrom.wm/config.yml(defaultubuntu-latestif unset),workflow.install_claude_code(default true: install Claude Code in CI beforegh wm run), and optionalworkflow.gh_wm_extension_version(when set, CI runsgh extension install owner/repo --pin <ref>pergh help extension install). Reusable workflows ensureghvia the compositeinstall-gh-cliaction, then installgh-wmwithgh extension install(seeagent-resolve.yml/agent-run.yml). - Ensure
.wm/.gitignorecontainsruns/(per-run artifact dirs fromgh wm run) — creates or appends that file when needed.
workflow.pre_steps (optional): A list of GitHub Actions job steps (name, uses, run, with, env, if) run after checkout and before installing gh-wm and running the task. Use this for toolchains (e.g. jdx/mise-action
), dependency installs, or installing the agent CLI. When pre_steps is non-empty, the generated wm-agent.yml uses an inline run job (steps embedded in the file) instead of calling the reusable agent-run.yml
workflow, because reusable workflows cannot accept arbitrary step YAML as inputs.
Environment:
| Variable | Default | Meaning |
|---|---|---|
GH_WM_REPO | an-lee/gh-wm | owner/repo for reusable workflow uses: in generated wm-agent.yml. |
compile
Purpose: Validate task bodies for ${{ }} (same rules as gh wm validate; see compat.gh_aw_expressions in Task format
), then regenerate .github/workflows/wm-agent.yml from current tasks (task-driven on: union, same as init step 4), workflow.runs_on, workflow.gh_wm_extension_version, and workflow.pre_steps in .wm/config.yml (when present), and GH_WM_REPO.
Usage: gh wm compile
If .wm/config.yml is missing, runner labels default to ubuntu-latest when generating wm-agent.yml. workflow.pre_steps follows the same rules as under init above. compile also ensures .wm/.gitignore lists runs/ (same as the last step under init), so older repos pick up the ignore rule without re-running init.
Breaking change: Earlier versions folded this into gh wm upgrade. upgrade no longer rewrites wm-agent.yml — use compile after changing tasks, schedules, or workflow-related config.
upgrade
Purpose: Run gh extension upgrade an-lee/gh-wm so the installed gh-wm extension matches the latest release (or your pinned source). If the upgrade fails (for example the CLI was not installed as a gh extension), the command prints gh’s output and exits with a non-zero status.
Usage: gh wm upgrade
validate
Purpose: Scan .wm/tasks/*.md bodies for gh-aw–compatible ${{ }} expressions without upgrading the extension or rewriting wm-agent.yml. Use in CI (e.g. after editing tasks).
Usage: gh wm validate — --repo-root defaults to . (same as other commands).
Behavior matches compat.gh_aw_expressions in .wm/config.yml (error / warn / off). See Task format — expressions
.
update
Purpose: Re-download task files using each task’s source: frontmatter (same idea as gh aw update for workflows with a source). source: may be an https URL or an owner/repo/path shorthand (path under the repo on main, e.g. owner/repo/workflows/task.md).
Usage:
gh wm update— update every.wm/tasks/*.mdthat has a non-emptysource:field.gh wm update <task-name> …— update only the named tasks (filename without.md, or with.md).
Tasks created with gh wm add (URL, owner/repo/task shorthand, or path) get a source: when appropriate so gh wm update can re-fetch. gh wm add runs gh wm compile automatically after a successful write. After gh wm update, run gh wm compile to refresh wm-agent.yml if task on: triggers, schedules, or other generator inputs changed.
See cmd/update.go
.
assign
Purpose: Add a label to an issue (local gh auth).
Usage: gh wm assign <issue-number>
Flags:
| Flag | Default | Description |
|---|---|---|
--label | agent | Label name to add |
Implementation: ghclient.AddIssueLabel
— by default invokes gh api; set GH_WM_REST=1 to use go-gh REST (internal/gh
).
add
Purpose: Copy or download a gh-aw–compatible Markdown file into .wm/tasks/ (validates YAML frontmatter).
Usage: gh wm add <owner/repo/task | url | path>
owner/repo/task-name— Fetches from the default branch (main), tryingworkflows/<task>.mdfirst (gh aw layout), then.wm/tasks/<task>.md. Recordssource:asowner/repo/workflows/…orowner/repo/.wm/tasks/…(gh aw-style shorthand), not a raw URL.https://…orhttp://…— Downloads the file;source:is the same URL (unless already set in the file).- Local path — Copies the file; no
source:is injected unless the file already has one.
Writes <cwd>/.wm/tasks/<basename>.md, then runs gh wm compile so wm-agent.yml matches the new task. See cmd/add.go
and cmd/github.go
.
resolve
Purpose: Print matching task names for a GitHub event (JSON array by default).
Usage: gh wm resolve
Flags:
| Flag | Default | Description |
|---|---|---|
--repo-root | . | Repository root containing .wm/ |
--event-name | $GITHUB_EVENT_NAME | GitHub event name |
--payload | $GITHUB_EVENT_PATH | Path to event JSON file; if --payload and GITHUB_EVENT_PATH are both unset, payload defaults to {} |
--json | true | If true, print JSON array; if false, one name per line |
--force-task | (unset) | Pin a single task by name; skips event/on: matching (same idea as local run picking a task). Used for manual runs and CI when the resolve job should return exactly one task. |
Schedule narrowing: When --event-name is schedule, set WM_SCHEDULE_CRON to the workflow cron string that fired (same value as github.event.schedule on Actions). agent-resolve.yml sets this automatically for reusable resolve. Omit WM_SCHEDULE_CRON locally to list every task that declares on.schedule.
run
Purpose: Execute one task: activation (validate event/engine, optional working label, branch prep for PR mode), agent, validation (exit + output size), safe-outputs: steps, then conclusion (done/failed labels, checkpoint, branch rollback on failure). With --agent-only, stops after a successful validation phase (skips safe-outputs and conclusion) so a follow-up gh wm process-outputs job can run with a write-capable GITHUB_TOKEN while the agent job used read-only permissions (see architecture.md
).
Usage: gh wm run --task <name> (local agent), or gh wm run --task <name> --remote to dispatch the wm-agent workflow on GitHub.
Git working tree: For local runs (default), gh wm requires a clean repository at --repo-root: git status --porcelain must be empty (no modified, staged, or untracked files). CI checkouts from actions/checkout usually satisfy this. Use --allow-dirty to skip the check (e.g. local scripts or tests). --remote does not require a clean tree (it does not run the agent locally).
Flags:
| Flag | Default | Description |
|---|---|---|
--repo-root | . | Repository root |
--task | (required) | Task name (filename without .md) |
--event-name | $GITHUB_EVENT_NAME | Event name (local run only) |
--payload | $GITHUB_EVENT_PATH | Path to event JSON; if --payload and GITHUB_EVENT_PATH are both unset, payload defaults to {} (local run only) |
--allow-dirty | false | Skip the git clean working tree check (local run only) |
--agent-only | false | Stop after agent validation; do not run safe-outputs or conclusion. Writes result.json / run.json for the partial run. Pair with gh wm process-outputs in a second CI job (see architecture.md
). |
--remote | false | Run gh workflow run to trigger workflow_dispatch on the repo’s wm-agent.yml with -f task_name=<task>. Requires the gh CLI and auth. Repository defaults to gh repo view; override with --repo OWNER/NAME. Optional --workflow (default wm-agent.yml), --ref (git ref for the workflow run), and --issue (passed as -f issue_number= for the dispatch inputs). After changing gh-wm or task inputs, run gh wm compile in the target repo so the generated workflow declares the task_name input; older wm-agent.yml files may reject unknown -f fields. --remote does not send a custom GitHub event payload (the run on Actions sees a normal workflow_dispatch event, optionally with issue_number). |
Timeout: Uses timeout-minutes from task frontmatter (default 45, max 480). The deadline is applied inside engine.RunTask
(so direct library use gets the same behavior as the CLI). See cmd/run.go
for the stderr banner.
Output: Before and during the run, stderr prints a banner (task name, repo path, current git branch, engine, timeout in minutes) and wm run: progress lines for each phase—e.g. activation (run directory path, optional checkpoint hint, working label, feature branch when safe-outputs includes create-pull-request), agent: immediately before the subprocess, validation: after the agent exits, and safe-outputs: when the task declares safe-outputs: with at least one key. The live agent stream (combined subprocess stdout/stderr) follows the agent: line on stderr. Each run also writes a per-run artifact directory under .wm/runs/<id>/ (or WM_RUN_DIR/<id>/ when set): prompt.md, combined agent log (default agent-stdout.log, or conversation.json / conversation.jsonl when structured Claude print-mode output is configured — see claude_output_format / WM_CLAUDE_OUTPUT_FORMAT in task-format.md
), meta.json, result.json, and run.json (merged meta + outcome; see architecture.md
). The summary block on stderr includes a line artifacts=<path> when that directory was created. After the run, a short summary line is printed to stderr (task name, repo path, duration, exit code, success, phase= — activation, agent, validation, safe-outputs, or last phase reached). If the run fails, stderr also prints failure phase: (for safe-outputs, the message still says safe-outputs (post-agent); otherwise the failing phase name).
GitHub Actions job summary: When GITHUB_STEP_SUMMARY is set (GitHub provides this automatically on Actions runners) and the task uses the built-in claude engine with WM_AGENT_CMD unset, gh wm run appends a markdown section to that file after the run if conversation.jsonl or conversation.json exists under the per-run directory (structured Claude print-mode output). The section includes pipeline success, wall-clock duration, stream event counts, cost and token usage from the final result event when present, and model IDs from modelUsage (or model from config as a fallback label). Plain-text agent logs (agent-stdout.log only) do not produce this block.
Branch + PR (safe-outputs: create-pull-request): If the task lists create-pull-request under safe-outputs and the repo is on the default branch (or detached HEAD), internal/gitbranch
creates and checks out wm/<task-slug>-<UTC-timestamp> before the agent runs so commits are not on main. If you are already on a non-default branch, no branch is created. On agent failure after a branch was created, the runner checks out the previous branch when possible (skipped when the previous state was detached HEAD). After a successful agent run, if output.jsonl includes a create_pull_request item (and policy allows it), the safe-output step runs git push then gh pr create --base <default> when there are commits ahead of the remote default branch; it skips if the current branch is still the default, if gh pr list already shows a PR for the current head, or if there is nothing to push.
Agent invocation (internal/engine/agent.go
):
| Variable | Meaning |
|---|---|
WM_AGENT_CMD | If set: split on whitespace for argv; prompt is appended as the last argument unless the string contains {prompt}, in which case that placeholder is replaced by the prompt (single argument). Overrides engine:. |
WM_ENGINE_CODEX_CMD | When engine: codex and WM_AGENT_CMD unset: same {prompt} rule as above (otherwise prompt is appended). Default codex invocation mirrors claude (stdin prompt, --dangerously-skip-permissions, --model / --max-turns from config when set). |
| (default) | claude -p --dangerously-skip-permissions with the prompt on stdin; --model and --max-turns come from .wm/config.yml
when set. Optional --output-format json or stream-json (with --verbose) when claude_output_format / WM_CLAUDE_OUTPUT_FORMAT is set (built-in claude only). When safe-outputs: is non-empty, also --append-system-prompt with enforcement text (output.SafeOutputsSystemPromptAppend
) so rules live in Claude Code’s system prompt, not only the user message. |
The default claude invocation uses --dangerously-skip-permissions so non-interactive runs can use tools (file edits, gh, git). Subprocess env is the parent environment (GITHUB_TOKEN in Actions, gh auth locally) plus GITHUB_REPOSITORY, WM_TASK, WM_REPO_ROOT, WM_SAFE_OUTPUT_FILE (output.jsonl for gh wm emit), WM_ISSUE_NUMBER / WM_PR_NUMBER when known, and WM_TASK_TOOLS when tools: is set in the task frontmatter (JSON for structured values). |
Post-agent: When safe-outputs: has at least one key, outputs are recorded via gh wm emit (see Emit
below) into WM_SAFE_OUTPUT_FILE (output.jsonl). If output.jsonl is empty, the phase warns and succeeds (implicit noop). WM_CHECKPOINT=1 enables loading/posting checkpoint comments (internal/engine/runner.go
).
Secrets (CI): ANTHROPIC_API_KEY is expected by reusable workflow for Claude Code; ensure the agent you invoke uses it as required.
process-outputs
Purpose: Resume the pipeline after gh wm run --agent-only: run safe-outputs: (output.RunSuccessOutputs
) and conclusion (concludeRun
) for an existing per-run directory. Used in the second job of agent-run.yml
so GitHub writes use a token with issue/PR/content write permissions.
Usage: gh wm process-outputs with the same --repo-root, --event-name, and --payload as the prior gh wm run (defaults to GITHUB_EVENT_NAME / GITHUB_EVENT_PATH when unset). Supply either --run-dir or --task (CI generated workflows use --task so the extension resolves the run directory; no Python or jq required).
The run directory must contain result.json from --agent-only with agent_result.success true (and optional top-level success must not be false). Otherwise the command errors and does not apply GitHub mutations.
Flags:
| Flag | Default | Description |
|---|---|---|
--repo-root | . | Repository root (must match the agent run) |
--run-dir | — | Path to .wm/runs/<id>/ from the agent-only run (required if --task is not set) |
--task | — | Task name: use the newest .wm/runs/<id>/ whose meta.json matches this task (required if --run-dir is not set) |
--event-name | $GITHUB_EVENT_NAME | Event name |
--payload | $GITHUB_EVENT_PATH | Event JSON path |
See architecture.md — GitHub Actions token sandbox .
Labels: When applying create_pull_request, add_labels, or create_issue outputs that include label names, process-outputs creates missing repository labels (default neutral color) before gh pr create or issue APIs, so the repo does not need those labels defined ahead of time.
emit
Purpose: Append one validated safe-output line (NDJSON) for the current task run. Intended to be invoked from the agent’s shell tool during gh wm run (environment is set by the runner).
Usage: gh wm emit <subcommand> with flags, e.g. gh wm emit noop --message "nothing to post", gh wm emit add-comment --body "…".
Environment (required): WM_REPO_ROOT, WM_TASK, WM_SAFE_OUTPUT_FILE. Typically also GITHUB_REPOSITORY and WM_ISSUE_NUMBER / WM_PR_NUMBER when commenting or labeling on the triggering thread.
Subcommands: noop, add-comment, add-labels, remove-labels, create-issue, create-pull-request, update-issue, update-pull-request, close-issue, close-pull-request, add-reviewer, create-pull-request-review-comment, submit-pull-request-review, reply-to-pull-request-review-comment, resolve-pull-request-review-thread, push-to-pull-request-branch, missing-tool, missing-data. Use gh wm emit --help and gh wm emit <cmd> --help for flags.
update-issue and update-pull-request accept optional --operation for the body: replace (default), append, prepend, replace-island (same semantics as task-format.md
operation on JSON items).
Inline review comments use the head commit SHA and a path/line in the diff; resolving a thread requires a GraphQL review thread id (flag --thread-id / JSON thread_id), not the numeric REST comment id alone.
submit-pull-request-review posts an overall PR review with --event (APPROVE, REQUEST_CHANGES, or COMMENT), optional --body, and optional --commit-id.
See task-format.md — safe-outputs:
.
status
Purpose: List issues with agent-related labels.
Usage: gh wm status
Flags:
| Flag | Default | Description |
|---|---|---|
--all | false | Use gh search issues across visible repositories instead of gh issue list for the current repo |
See cmd/status.go
.
logs
Purpose: List wm-agent workflow runs; prefers runs whose title contains #<issue-number>.
Usage: gh wm logs <issue-number>
If none match, prints recent runs with a note. See cmd/logs.go
.
CI-related environment (summary)
| Variable | Used by |
|---|---|
GITHUB_EVENT_NAME, GITHUB_EVENT_PATH | resolve, run: event name / payload file when flags omitted; if GITHUB_EVENT_PATH unset, payload is {} |
GITHUB_REPOSITORY | Agent + gh outputs; required for labels/comments |
WM_SCHEDULE_CRON | resolve schedule narrowing (resolver.go
); set in CI by agent-resolve.yml
from github.event.schedule. |
WM_AGENT_CMD | Override agent command (agent.go
) |
WM_ENGINE_CODEX_CMD | Codex CLI prefix when engine: codex |
WM_TASK_TOOLS | Set automatically from tools: (read by agent) |
WM_SAFE_OUTPUT_FILE | Set by run when a per-run dir exists: NDJSON log for gh wm emit (output.jsonl). |
WM_REPO_ROOT | Repository root (same as --repo-root); used by gh wm emit to load the task. |
WM_ISSUE_NUMBER, WM_PR_NUMBER | Optional; set by run when the event provides issue/PR numbers (for emit validation / default --target). |
WM_CHECKPOINT | Set to 1 to enable checkpoint load/post |
WM_RUN_DIR | If set, per-run artifacts are written under <WM_RUN_DIR>/<run-id>/ instead of <repo>/.wm/runs/<run-id>/ (useful for CI artifact upload paths). |
WM_CLAUDE_OUTPUT_FORMAT | Overrides claude_output_format in .wm/config.yml
: text (default), json, or stream-json for built-in claude (run-dir filename, --output-format, and --verbose when stream-json). |
WM_LOG_FORMAT | Set to json for JSON log/slog output on stderr (structured pipeline logs). |
GH_WM_REST | Set to 1 so ghclient / label-comment APIs use go-gh REST instead of gh api subprocesses (internal/gh
). |
GITHUB_STEP_SUMMARY | GitHub Actions: path to the job summary file; when set, run may append Claude usage stats from conversation.json / conversation.jsonl (internal/engine/conversation_summary.go
). |
GH_WM_REPO | init, compile for reusable workflow owner/repo |