Development guide

How to build, test, and extend gh-wm. Pair this with architecture.md (especially RunTask pipeline (detailed reference) for reads, writes, and persistence per phase).

Prerequisites

  • Go (see go.mod for version).
  • gh CLI for local commands that shell out (assign, status, logs, outputs).
  • Optional: claude CLI for default run behavior, or set WM_AGENT_CMD.

Build and run

# From repo root
go build -o gh-wm .

./gh-wm resolve --payload /path/to/event.json --event-name issues --json
./gh-wm run --task implement --payload /path/to/event.json --event-name issues

run expects a clean git working tree at --repo-root (use --allow-dirty to skip). A short banner prints to stderr (task, branch, engine), then agent output streams to stderr; a summary line prints when the run finishes.

Install via module path:

go install github.com/an-lee/gh-wm@latest

Documentation site (Hugo)

The HTML site at https://gh-wm.github.io/gh-wm/ is built from this repo’s docs/ tree (Markdown in content/ , Hugo config in hugo.toml ). Local preview:

cd docs && hugo mod get -u && hugo server

Deployment runs via .github/workflows/pages.yml when docs/ changes on main.

Repository layout

PathRole
main.goCalls cmd.Execute().
cmd/Cobra commands; keep thin—delegate to internal/.
internal/config/YAML + markdown frontmatter loading.
internal/engine/Resolve + run + agent + per-run artifact dirs (rundir.go) + checkpoint wiring.
internal/output/Reads output.jsonl (gh wm emit); runs validated safe-output items per safe-outputs: policy.
internal/trigger/on: matching (match.go).
internal/types/GitHubEvent, TaskContext, AgentResult, RunResult, Phase.
internal/gen/wm-agent.yml generation and task-driven workflow trigger collection (triggers.go, schedules.go).
internal/templates/Embedded files for gh wm init.
internal/ghclient/gh api helpers (labels, comments).
internal/gitbranch/Default branch detection; feature branch wm/<task>-… before agent when create-pull-request is enabled.
internal/checkpoint/Checkpoint HTML comments.
docs/Hugo site (hugo.toml , content/ ) for GitHub Pages .
.github/workflows/CI + reusable workflows + release + Pages.

Extending on: matching

  1. Edit internal/trigger/match.go .
  2. Add a branch inside MatchOnOR or extend an existing matcher.
  3. Add tests where practical.
  4. Document new syntax in task-format.md .

Convention: GITHUB_EVENT_NAME matches GitHub’s webhook names (issues, issue_comment, …).

Extending outputs

  1. Add a Kind… constant, parsing in parse.go , policy in policy.go if needed, a handler, and a case in runAgentDrivenOutputs ; extend prompt.go for the injected prompt section.
  2. Use ghclient or exec.Command("gh", …) with tc.RepoPath / GITHUB_REPOSITORY.
  3. Document the key and JSON type in task-format.md .

Extending configuration

  • Global config: Extend GlobalConfig and document in task-format.md .
  • Tasks: Frontmatter is map[string]any—add accessors on Task when a field becomes first-class.

Agent backend selection

See runAgent : WM_AGENT_CMD overrides everything; otherwise engine: selects claude or codex (+ optional WM_ENGINE_CODEX_CMD). The former copilot engine name errors; use WM_AGENT_CMD for a custom CLI.

Workflows and releases

  • Caller wm-agent.yml is generated—use gh wm compile (regenerates the file from tasks and config). Use gh wm upgrade to update the gh-wm extension via gh extension upgrade.
  • Reusable workflows live in this repo. agent-resolve.yml / agent-run.yml use the composite install-gh-cli action (official cli/cli Linux tarball; no Node — avoids broken third-party setup actions on some self-hosted runners). GitHub-hosted runners already include gh, so the step is a no-op there. CI installs gh-wm with gh extension install and invokes gh wm resolve / gh wm run. Set workflow.gh_wm_extension_version in .wm/config.yml (and run gh wm compile) to pass --pin to gh extension install (e.g. a release tag or commit SHA; see gh help extension install). The reusable agent-run.yml optionally installs Claude Code (official install.sh) and appends $HOME/.local/bin to GITHUB_PATH so claude is on PATH on self-hosted runners with a minimal environment. Disable via workflow.install_claude_code: false in .wm/config.yml when using codex only or a pre-installed CLI.

When changing reusable workflow inputs/outputs, update internal/gen/wmagent.go .

Tests

go test ./...

Add tests for parsers and trigger.MatchOnOR whenever behavior changes.

Style

  • Keep CLI flags and env var names stable; document in cli-reference.md .
  • Prefer explicit errors over silent skips (e.g. missing payload path).