hyperhive/docs/tools/forge.md

218 lines
13 KiB
Markdown

# hive-forge CLI
`hive-forge` is the Forgejo API wrapper available in every agent
container (installed via `harness-base.nix`; lives in `/hive-forge`
as a proper Rust binary). Use it instead of ad-hoc curl pipelines.
## Credentials and repo defaults
- Credentials: `$HYPERHIVE_STATE_DIR/forge-token`
- Default repo: `$HIVE_FORGE_REPO`
- Per-invocation override: global `-r/--repo` flag
## Verbs
**Kind-namespaced commands (preferred):** issue/PR operations are grouped
under `issue` and `pr` parent commands — `hive-forge pr close 42`,
`hive-forge issue create --title …`, `hive-forge pr status --pr 42`. The
`pr <verb>` / `issue <verb>` forms validate the number's kind (e.g. `pr close`
refuses an issue number, which the old generic `close` couldn't). Run
`hive-forge pr --help` / `hive-forge issue --help` for the full subcommand
list (show/create/edit/status/merge/reviews/commits/diff/view/comment/
comments/close/reopen/labels/assign/timeline as applicable).
The flat forms below (`close 42`, `pr-create …`, `pr-status …`, …) still work
as **hidden back-compat aliases** during the transition and are dropped from
`--help`; prefer the namespaced form. They'll be removed in a later sweep.
```bash
hive-forge pr close 42 # close a PR (kind-validated)
hive-forge pr reopen 42 # reopen a closed PR (kind-validated)
hive-forge issue close 42 # close an issue (kind-validated)
hive-forge issue reopen 42 # reopen a closed issue (kind-validated)
hive-forge pr status --pr 42 # PR health (mergeable / CI / reviews)
hive-forge issue create --title "..." --body "..."
# --- flat aliases below remain valid (hidden) ---
hive-forge view 42 # title + body + comments (marks thread read)
hive-forge comments 42 # list all comments (human-readable; marks thread read)
hive-forge comments 42 --tail 10 # last 10 comments (count-then-page; efficient on long threads)
hive-forge --json comments 42 # same as above, JSON array (global flag)
hive-forge comment 42 --body "..." # post comment (inline body)
hive-forge comment 42 --body-file - <<EOF # ...or pipe a HEREDOC
multi-line body
EOF
hive-forge comment 42 --body "..." --force # post even if thread has unread activity
hive-forge comment-show 18042 # fetch one comment by id
hive-forge comment-edit 18042 --body "..." # edit a comment
hive-forge assign 42 damocles
hive-forge close 42
hive-forge labels 42 add feature
hive-forge issue-create --title "..." --body "..."
hive-forge issue-edit 42 --title "new title"
hive-forge pr 42 # PR metadata as JSON
hive-forge pr-create --title "..." --head my-branch --push # also `git push forge my-branch`
hive-forge pr-reviews 42 # list reviews; inline comments included per review
hive-forge pr-reviews 42 --approve # submit APPROVED review
hive-forge pr-reviews 42 --request-changes -m "msg" # submit REQUEST_CHANGES review
hive-forge pr-reviews 42 --comment -m "msg" # submit COMMENT review
hive-forge diff 42 # unified diff (lockfile hunks collapsed by default)
hive-forge diff 42 --full # include unfiltered lockfile hunks
hive-forge list # open issues/PRs
hive-forge list --kind pr --state all --page 2 # page 2 of all PRs (walk --page 1,2,… with --limit as page size for a repo-wide sweep)
hive-forge milestone # list milestones
hive-forge branches deployed/ # filter branches by pattern
hive-forge tree-sha main # git tree SHA for a ref
hive-forge -r other-org/other-repo pr 7 # target a different repo
hive-forge lint unassigned # open issues/PRs with no assignee
hive-forge lint no-reviewer --reviewer argus # PRs missing a reviewer comment from argus
hive-forge lint stale-branches --days 14 # branches with no recent activity
hive-forge lint assignments # per-assignee open item count
hive-forge pr-status --pr 42 # PR health: mergeable, CI, reviews, last comment (exit 0 = ready)
hive-forge pr-status --sha <sha> # CI-only fast path for an explicit commit sha
hive-forge pr-merge 42 # merge (refuses unless mergeable + CI not red + no changes-requested); deletes head branch
hive-forge pr-merge 42 --method rebase # rebase-merge instead of a merge commit (no squash option)
hive-forge pr-merge 42 --keep-branch --force # keep the head branch; override the readiness gate
hive-forge timeline 42 # audit trail: closes, label changes, assignments, commit refs
hive-forge attach-issue 42 /path/to/file # upload a file attachment to an issue; prints download URL
hive-forge attach-comment 18042 /path/to/file # upload a file attachment to a comment; prints download URL
hive-forge attachment-get <uuid> # download an attachment; prints resolved path to stdout
hive-forge artifact-get pr1ma-paper-pdf --run 51 # download a CI run's Actions artifact zip (run number from the run-page URL)
hive-forge ci-log --run 51 # print a CI run's job step logs (run number from the run-page URL); --job i / --step i to narrow
hive-forge ci-rerun --pr 42 # re-run CI without an empty commit (dispatches a fresh run; --run n / --branch name also work)
hive-forge subscription --watch # subscribe to repo notifications
hive-forge subscription --unwatch # unsubscribe
hive-forge subscription --list # list every repo you watch (audit the notification firehose)
hive-forge -r internal/knowledge clone # clone with creds auto-injected
hive-forge -r internal/knowledge pr-create --agit --topic foo --title "..." # open PR via AGit (no fork)
```
### Which read verb when
Several verbs read an issue/PR and look overlapping, but each has a
distinct output shape — pick by what you need:
| Need | Verb | Shape |
|------|------|-------|
| The full human view of one item — title, body, **and** every comment in order | `view <n>` | prose dump; **marks the thread read** (clears the read-before-comment guard). Top-level `view` auto-detects issue-or-PR by number; scoped `issue view <n>` / `pr view <n>` do the same when you already know the kind |
| Just the structured metadata of one item (state, labels, assignees, head sha…) | `issue <n>` / `pr <n>` | JSON object |
| Only the comments (skip the body), e.g. to catch up a long thread | `comments <n>` [`--tail N`] | comment list; **marks read** |
| One specific comment by its id | `comment-show <id>` | single comment |
| The audit trail — closes, label/assignee changes, commit refs, merges (no comment bodies) | `timeline <n>` | event list |
| The code change | `diff <n>` | unified diff |
| Is this PR ready to merge — mergeable + CI + reviews | `pr-status --pr <n>` | health view; exit code = merge-readiness |
| The review verdicts + inline review comments | `pr-reviews <n>` | review list |
Rule of thumb: **`view` first** when you're about to act on a thread (it
shows everything and clears the unread guard so your follow-up `comment`
isn't rejected); the JSON verbs (`issue`/`pr`) when a script needs one
field; `pr-status` when the only question is "can I merge it".
### Contributing to a read-only repo (`clone` + `pr-create --agit`)
Agents are read-only collaborators on some repos (e.g.
`internal/knowledge`) and so can't push branches. Forgejo's AGit flow
lets a read-only user open a PR by pushing the current `HEAD` to the
magic ref `refs/for/<base>/<topic>`. Two verbs cover the workflow:
```
hive-forge -r internal/knowledge clone # clone with token auto-injected
cd knowledge
# add / edit / delete any files, then commit normally
git add -A && git commit -m "add foo runbook"
hive-forge -r internal/knowledge pr-create --agit \
--topic foo-runbook \ # groups pushes into ONE PR; reuse to update it
--title "add foo runbook" \
[--body "details"] # PR description (also accepts --body-file)
```
`clone` derives the dest dir from the repo basename (override with a
positional arg); `--branch` / `--depth` are passed through. The token
is injected into the clone's `origin` remote so `pr-create --agit`
(default remote `origin`) can push without re-auth.
`pr-create --agit` prints the PR URL. Re-running with the same
`--topic` force-updates the existing open PR (the AGit ref is
agent-owned scratch). Opens a reviewable PR the operator merges — never
commits straight to `main`.
`hive-forge <verb> --help` prints the full signature for any verb.
### `pr-status`
One-stop PR health view (`--pr <n>`): mergeable state, CI checks,
requested reviewers + review verdicts, and the last-comment timestamp —
the things you need to know whether a PR is ready to merge (CI must pass
before merge). `--sha <sha>` is a CI-only fast path for a raw commit.
A failing/erroring CI context prints its job link. The process exit code
is a **merge-readiness** verdict for `--pr` (0 only when CI is green AND
the PR is mergeable AND no review requests changes), so it composes:
`hive-forge pr-status --pr 42 && echo ready`. `--sha` mirrors the CI
verdict alone.
```
hive-forge pr-status --pr 42
# PR #42: feat(...): ...
# state: open (mergeable: yes)
# CI: e39a87ea3949: ✅ success (1 context(s))
# ✅ CI / nix flake check (pull_request): success — Successful in 1m50s
# reviewers: (none requested)
# reviews: ✅ argus: APPROVED
# last comment: 2026-06-05T19:13:28+02:00 by argus
```
Note: review verdicts come from *formal* Forgejo reviews (the
approve / request-changes API). Reviewers who post their verdict as a
plain comment show under `last comment`, not `reviews`.
## Notes
- **Read-before-comment guard:** `comment` refuses to post when forge still
has an unread notification for the thread (i.e. someone commented since you
last read it). This prevents accidentally replying to old activity without
seeing the new context. Read the thread with `hive-forge view <n>` or
`hive-forge comments <n>` (which mark the notification read and clear the
block), or pass `--force` to skip the guard.
- `comment --body "..."` with backticks in the body: always use
`--body-file -` with a HEREDOC to avoid shell escaping issues.
- `pr-create --push` also runs `git push forge <head>` and suppresses
the post-push "Create a pull request" hint (we print the canonical
URL ourselves).
- `attachment-get` saves to `/tmp/forge-attachment-{uuid}` by default
and prints the resolved path. Pass `-o -` to stream to stdout.
- `artifact-get <name> --run <n>` downloads a CI Actions artifact. `<n>`
is the run number from the run-page URL (`/actions/runs/<n>`, which
`pr-status` surfaces as a CI context's target_url). Forgejo 15 serves
artifacts only via the web route, not REST, and that route is keyed by
the run's internal global id, so the verb translates the run number
first. Saves a zip to `/tmp/forge-artifact-<name>.zip` by default; pass
`-o -` to stream to stdout.
- `ci-log --run <n> [--job i] [--step i] [--attempt n]` prints a CI
run's job step logs. `<n>` is the run number from the run-page URL
(same value `artifact-get` takes; `pr-status` surfaces it as a CI
context's target_url). Two log sources are tried in order: first the
web run-view **streamer** the run page polls (rich per-step framing,
honors `--step`) — but that reads the live `act_runner` task record,
which Forgejo prunes once a run completes; then, when the streamer is
pruned (500 / no lines), the **durable persisted-log download** the
run page's "view raw logs" link uses
(`…/runs/<n>/jobs/<job>/attempt/<a>/logs`), a flat whole-job log that
survives the prune (`--step` is not honored on this path). So quick /
older runs that the streamer can no longer serve still print instead
of erroring. `--job` selects the job (0-based, default 0); `--attempt`
picks the run attempt for the durable path (default 1; re-runs
increment it). `--json` wraps the output.
- `ci-rerun` re-runs CI without pushing an empty commit (the old
retrigger path, which littered PR history). Forgejo has no token-usable
REST endpoint to re-run an *existing* run (the run-page rerun buttons
are CSRF-gated web routes a token POST 404s), so this dispatches a
**fresh** run of the workflow via the workflow-dispatch API
(`POST …/actions/workflows/<workflow>/dispatches {"ref":"<branch>"}`).
Resolve the branch with exactly one of: `--pr <n>` (the PR's head
branch), `--run <n>` (the same run number `ci-log` / `artifact-get`
take — resolves the branch + workflow from that run), or `--branch
<name>` (directly). `--workflow <file>` picks the workflow file for
`--pr` / `--branch` (default `ci.yml`). Dispatch re-runs the whole
workflow — there is no single-job variant.
- Do NOT use raw `curl` for forge access -- the CLI handles auth,
error checking, and output formatting.