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.modfor version). ghCLI for local commands that shell out (assign,status,logs, outputs).- Optional:
claudeCLI for defaultrunbehavior, or setWM_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
| Path | Role |
|---|---|
main.go | Calls 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
- Edit
internal/trigger/match.go. - Add a branch inside
MatchOnORor extend an existing matcher. - Add tests where practical.
- Document new syntax in task-format.md .
Convention: GITHUB_EVENT_NAME matches GitHub’s webhook names (issues, issue_comment, …).
Extending outputs
- Add a
Kind…constant, parsing inparse.go, policy inpolicy.goif needed, a handler, and acaseinrunAgentDrivenOutputs; extendprompt.gofor the injected prompt section. - Use
ghclientorexec.Command("gh", …)withtc.RepoPath/GITHUB_REPOSITORY. - Document the key and JSON
typein task-format.md .
Extending configuration
- Global config: Extend
GlobalConfigand document in task-format.md . - Tasks: Frontmatter is
map[string]any—add accessors onTaskwhen 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.ymlis generated—usegh wm compile(regenerates the file from tasks and config). Usegh wm upgradeto update thegh-wmextension viagh extension upgrade. - Reusable workflows live in this repo.
agent-resolve.yml/agent-run.ymluse the compositeinstall-gh-cliaction (officialcli/cliLinux tarball; no Node — avoids broken third-party setup actions on some self-hosted runners). GitHub-hosted runners already includegh, so the step is a no-op there. CI installsgh-wmwithgh extension installand invokesgh wm resolve/gh wm run. Setworkflow.gh_wm_extension_versionin.wm/config.yml(and rungh wm compile) to pass--pintogh extension install(e.g. a release tag or commit SHA; seegh help extension install). The reusableagent-run.ymloptionally installs Claude Code (officialinstall.sh) and appends$HOME/.local/bintoGITHUB_PATHsoclaudeis onPATHon self-hosted runners with a minimal environment. Disable viaworkflow.install_claude_code: falsein.wm/config.ymlwhen 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).