-
Notifications
You must be signed in to change notification settings - Fork 0
CLI Reference
The specgit CLI has ten commands. The human story is issue → finish; setup installs agent entry points; bind / unbind / accept are machine aliases for scripts. All evaluation is evidence-derived and fail-closed.
| Command | Purpose | Network | Exit codes |
|---|---|---|---|
specgit init |
Create the project policy and generate the harness | gh (protection probe) | 0 · 2 · 3 |
specgit setup |
Install agent entry points (commands for opencode, portable skills for other tools) | no | 0 · 2 · 3 |
specgit issue |
One-command delivery bootstrap (issues, branch, draft PR, record, commit, push) | yes | 0 · 2 · 3 |
specgit finish |
The verdict — full evaluation against git + forge | yes | 0 · 1 · 2 · 3 |
specgit pr |
Repair the PR binding (auto-discover by head branch, or bind explicitly) | yes | 0 · 2 · 3 |
specgit bind |
Create/update the delivery record (.specgit.yaml) — script alias |
no | 0 · 2 · 3 |
specgit unbind |
Delete the delivery record — script alias | no | 0 · 2 |
specgit status |
Local evidence only (record, policy, git facts, drift) | no | 0 · 2 · 3 |
specgit accept |
Same evaluation as finish — script/CI alias |
yes | 0 · 1 · 2 · 3 |
specgit doctor |
Probe prerequisites (git, repo, origin, provider CLI, policy) | provider auth only | 0 · 3 |
Plus --version and --help (exit 0; usage errors exit 2).
| Code | Meaning |
|---|---|
0 |
Success / accepted (all gates passed with evidence) |
1 |
Rejected with complete evidence (all evidence gathered, at least one gate failed) |
2 |
Usage error (bad flags, invalid arguments) |
3 |
Fail-closed unknown — evidence could not be gathered: record/policy missing or invalid, provider missing or unauthenticated, transport failure, not a git repository. One documented exception: specgit status reports a missing record as the healthy pre-binding state — exit 0 with state unbound; only an invalid record fails closed there. |
130 |
Interruption exception — Ctrl-C (SIGINT) during an interactive prompt. The process prints Interrupted. to stderr and exits 130; no JSON envelope is emitted. |
The distinction between 1 and 3 is contractual: 1 means the evidence was gathered and says no; 3 means no verdict is possible. Automation should branch on exit codes, never on phrasing.
-
--json— available on every command. stdout becomes exactly one valid JSON document (the envelope below); all human-readable text goes to stderr. The only exception is the Ctrl-C130interruption path, which emits no envelope.
| Variable | Meaning |
|---|---|
SPECGIT_GH |
Path to the gh executable. Defaults to gh on PATH. |
SPECGIT_GH_TIMEOUT_MS |
Per-call timeout for gh invocations in ms. Default 15000. A timeout is gh_transport (exit 3). |
SPECGIT_GLAB |
Path to the glab executable used by the GitLab adapter. Defaults to glab on PATH. |
SPECGIT_GLAB_TIMEOUT_MS |
Per-call timeout for glab invocations in ms. Default 15000. A timeout is glab_transport (exit 3). |
No tokens are ever read from the environment — authentication is your existing gh / glab session.
The optional language key in spec_git/policy.yaml (en default, or zh; set with specgit init --language zh) selects the language of generated text: issue/PR scaffolds, the managed AGENTS.md block, and success-path stderr prose. The machine contract is never localized: exit codes, --json field names, diagnostic codes, closing references (Closes #n), generated workflow YAML, hook scripts, and commit messages. Branch names stay ASCII under every language — a non-ASCII title falls back to feat/<n>-issue<n>.
Creates spec_git/policy.yaml (write-once; refuses to overwrite) and generates the delivery harness. Initialization is non-destructive: validation before mutation, error-atomic harness writes (rollback on partial failure), hooks merged never overwritten. Running init again with an existing policy exits 2 (policy_exists); --force rebuilds the policy and refreshes the harness.
| Flag | Meaning |
|---|---|
--required-check <name> |
A CI check name every delivery must pass. Repeatable. Omitted: auto-detected from CI files; a no-CI repository gets an empty list. |
--gitlab-host <hostname> |
Declare the origin's platform as self-managed GitLab (host or host:port). Persists to spec_git/providers.yaml. |
--language <lang> |
en | zh (default en). Unsupported values fail closed (language_invalid, exit 2). |
--protect |
Enable branch protection + auto-merge without asking. |
--no-protect |
Skip the protection probe and warning entirely. |
Artifacts: the acceptance workflow .github/workflows/specgit-accept.yml (job SpecGit Acceptance, runs specgit finish --json on every PR; never listed in policy.required_checks — self-deadlock avoidance) and the managed prompt block <!-- specgit:block:start --> … <!-- specgit:block:end --> in AGENTS.md (created if missing) and CLAUDE.md (only if present). On GitLab mode no GitHub Actions workflow is written (gitlab_harness_pending warning).
After writing, init probes the default branch: if SpecGit Acceptance is not a required status check there, the gate can be bypassed — init warns and offers to enable protection + auto-merge (--protect applies it from scripts; the update is read-modify-write and never weakens existing rules).
Installs agent entry points. Idempotent, safe to re-run.
specgit setup # auto-detect the tool
specgit setup --tool opencode # commands for opencode only
specgit setup --tool generic # portable skills for any tool
specgit setup --tool all # everythingThe one-command bootstrap: create/reuse N issues (one issue = one independently verifiable WHY), create the branch <type>/<first-issue#>-<slug>, open a draft PR whose body is a deterministic scaffold (the Closes #n line for every bound issue, then Why / What changed / Evidence / Checklist sections), write .specgit.yaml, commit, push. Re-running resumes: completed steps are detected and skipped.
specgit issue "feat: add login" "Harden the session model" # two new issues, one delivery
specgit issue 4 "Extend the harness" # reuse #4, create one
specgit issue # resume an incomplete bootstrapEach positional argument is a quoted title (<type>: <english title>, type whitelist: feat, fix, refactor, perf, docs, test, chore, style, build, ci, revert, security, deprecate, dogfood) or a pure number (existing issue). The slug is kebab-case from the first three ASCII words of the title. The PR body is written exactly once at draft creation; resume and specgit pr never edit an existing PR body.
Key diagnostics (exit 2, zero side effects): issue_resume_drift, issue_delivery_merged, issue_title_ambiguous. Provider failures (gh_missing, gh_unauthenticated, gh_transport, evidence_truncated) exit 3 and are resumable.
The verdict command — the CI gate runs it with --json on every PR. Runs the full eleven-gate evaluation through the same fail-closed evaluator as accept; checks are verified at the PR head commit.
specgit finish # human-readable verdict
specgit finish --json # machine-readable verdict (what CI parses)Exit semantics: 0 accepted · 1 rejected with complete evidence · 3 cannot determine.
Repairs the PR binding. Without arguments it auto-discovers the open pull request whose head is the record's branch: exactly one candidate binds; zero fails with a fix (pr_not_found); several refuse and list (pr_ambiguous). With an explicit number or URL the PR binds directly.
Script alias: creates or updates .specgit.yaml, one field at a time. Local-only, never calls the network.
specgit bind --delivery add-login-flow --issue 123
specgit bind --issue 124 # merges into issues
specgit bind --pr 42 # sets/replaces the PRDeletes .specgit.yaml for the current checkout: specgit unbind --yes (required flag, no interactive prompt). The policy is untouched.
Reports local evidence only — record, policy, live git context, upstream drift, origin — with zero network calls. A missing record is the healthy pre-binding state: exit 0 with state unbound and a warning pointing at specgit issue. Genuine evidence failures (record_invalid, policy_missing, policy_invalid, git_unavailable, not_a_git_repo) fail closed with exit 3.
Script/CI alias of specgit finish: identical evaluation and exit codes, differing only in the envelope's command field.
Probes prerequisites in order: git present → inside a repository → origin parses → provider CLI present → provider CLI authenticated (gh on GitHub origins, glab on declared GitLab origins) → policy present. Exit 0 when all probes pass, otherwise 3.
Every --json invocation writes exactly one JSON document to stdout:
{
"tool": "specgit",
"version": "1.0.0",
"command": "accept",
"status": "rejected",
"exit": 1,
"state": "bound",
"verdict": {
"accepted": false,
"gates": [
{
"id": "closing",
"status": "fail",
"code": "closing_refs_incomplete",
"detail": { "missing": [124] },
"fix": "Add \"Closes #124\" to the PR body"
}
],
"evidence": {
"repo": "LeXwDeX/SpecGit",
"branch": "feat/123-login",
"context": { "kind": "branch" },
"pr": 42,
"prHead": "abc123…"
}
},
"errors": [
{
"severity": "error",
"code": "closing_refs_incomplete",
"message": "PR 42 does not close issue #124",
"target": "pr:42",
"fix": "Add \"Closes #124\" to the PR body"
}
]
}Fields:
-
status—ok|rejected|unknown|error -
exit— the numeric exit code (0|1|2|3), matchingstatus' mapping -
state— derived delivery state:unbound|draft|bound|accepted|rejected|unknown -
verdict.gates[]— one entry per evaluated gate withid,status, failurecode, structureddetail, and afix -
verdict.evidence— the facts the verdict was derived from -
errors[]— diagnostics withseverity,code,message,target,fix
In --json mode nothing else touches stdout; parse the whole document, not fragments.
Chinese version: CLI-Reference-zh