---
name: aiom-review
description: >
  Agent skill for reviewing PRs and triaging issues through AI OSS
  Maintainer, a self-hosted mirror of GitHub work items with AI triage and
  review context. Use the `aiom` CLI (or the agent API it wraps) to discover
  work by queue status, load AI verdicts/summaries/diffs, check out a PR
  worktree, and submit an advisory local review. Read-mostly; the only routine
  write is that review record. Never comments, labels, or merges on GitHub, and
  pushes fixes only when the maintainer explicitly asks.
---

# AI OSS Maintainer — local review skill

AIOM mirrors your GitHub repos locally: it ingests issues and PRs, runs AI
triage/review, and stages prototype fixes. This skill lets a local agent
discover that work, review a PR with full AI context, and record an
**advisory** local review.

## Environment

| Variable | Description | Example |
|---|---|---|
| `AIOM_BASE_URL` | AIOM server base URL | `http://127.0.0.1:3000` |
| `AIOM_AGENT_TOKEN` | Agent API bearer token (yours) | `aiom_...` |
| `AIOM_LOCAL_ROOT` | Root of local clones (for `aiom`) | `~/Projects` |
| `AIOM_AGENT_NAME` | Default `--agent` name | `codex` / `opencode` |

```bash
export AIOM_BASE_URL="http://127.0.0.1:3000"
export AIOM_AGENT_TOKEN="..."
export AIOM_AGENT_NAME="codex"
```

Tokens are **per-user**: every org member creates their own at the server's
profile page, Settings tab → **Agent tokens** — scoped to that user's orgs,
teams and personal repos. The server also has a platform-level operator token
(config `auth.agent_token`) that sees everything. `?org=` takes the org
**slug** (derived from its display name, so a spaced name slugs to dashes).

Every detail endpoint is scoped: a token that cannot see a repo gets 404, not
403. A 401 everywhere means the token is wrong or revoked.

## CLI setup

The `aiom` CLI wraps every action below (it is the preferred interface; the
raw API is documented for fallbacks). Install it from the server's public
agent page:

```bash
curl -fsSL "${AIOM_BASE_URL:-https://aiom.sh}/agent/install.sh" | sh
aiom --help
```

The installer picks the binary for your platform, verifies its SHA-256, and
prints the installed path. If `aiom` is not on `PATH`, use the absolute path
it prints (or export that directory). Versions and checksums are listed at
`${AIOM_BASE_URL:-https://aiom.sh}/agent`; pin one with `AIOM_BUILD=<build>`
on the installer.

From a checkout of the (private) AIOM repository, the fallback is
`cargo install --path crates/cli`.

**References** accepted by `pr`, `diff`, `review`, `issue`, `checkout-pr`,
`remove-pr`:

- an internal id: `47362` (shown by `aiom prs`/`aiom next`)
- `owner/name#number`: `grafana/mimir#16975`
- a GitHub URL: `https://github.com/grafana/mimir/pull/16975`

A bare number is always the AIOM internal id, never a GitHub PR or issue
number: `aiom pr 16975` looks up AIOM item 16975, which usually fails with
"not found". For a GitHub number, use `owner/name#number` or the URL.

Add `--json` to any read/review command for raw JSON (agents should prefer it).

## Commands

```bash
aiom repos                          # tracked repos + open counts
aiom prs --status reviewable        # pending|needs_human|failed|waiting|escalated|reviewable
aiom prs --org grafana --limit 20    # org slug, max 200
aiom next                            # needs_human first, else reviewable
aiom next --repo grafana/mimir       # same, restricted to one repo
aiom pr 47362                        # or grafana/mimir#16975 / the GitHub URL
aiom diff grafana/mimir#16975        # unified diff on stdout
aiom issues --status new             # new|failed|waiting
aiom issue grafana/mimir#12345
aiom checkout-pr 47362               # worktree path is the final stdout line
aiom remove-pr 47362
```

`aiom next --repo` checks the repo is tracked and visible to your token, then
inspects the top 200 `needs_human` and `reviewable` items for it (the cap is
the agent API limit). `aiom prs` defaults to the server's `pending` status;
pass `--status` explicitly for discovery.

## Submitting a local review

```bash
# Short review:
aiom review grafana/mimir#16975 \
  --verdict approve \
  --summary "LGTM with one nit: the loop variable shadows the outer one." \
  --agent codex

# Long reasoning from files/stdin (markdown):
aiom review 47362 --verdict request_changes \
  --summary "The error path leaks the goroutine." \
  --notes-file review-notes.md --agent opencode

git show HEAD | aiom review 47362 --verdict comment \
  --summary "Notes from the diff" --notes-file - --agent codex
```

- `--verdict`: `approve`, `comment`, or `request_changes`.
- `--summary` or `--summary-file` (one required); `--notes` or `--notes-file`
  (optional). Only one of the two `-` stdin forms may be used.
- `--agent` defaults to `$AIOM_AGENT_NAME`, then `aiom-cli`.
- The review is **advisory**: it appears on the PR page under “Local agent
  reviews” but never flips pipeline status or overwrites the AI verdict. The
  maintainer decides.

## Review workflow

1. **Discover**: `aiom next` (needs_human first, then reviewable), or
   `aiom prs --status needs_human` / `--status reviewable`. `reviewable` means
   the highest-priority non-draft PRs not waiting on authors, not the
   maintainer's own, and without a local review yet.
2. **Load context**: `aiom pr <ref>` — read `ai_verdict` and `ai_summary` as a
   first pass to verify, not gospel; inline `ai_comments` are the AI's notes.
3. **Get the code**:
   ```bash
   aiom checkout-pr <ref>    # path is the final stdout line
   ```
   The worktree lands at `{AIOM_LOCAL_ROOT}/{owner}/{repo}.pr-{n}` on branch
   `aiom/pr-{n}`. Re-running refreshes to the latest PR head; a dirty worktree
   is refused unless `--force` — your edits are never silently discarded.
   Clean up with `aiom remove-pr <ref>`. Without the CLI/local clone, fall
   back to `git clone`, or read the diff with `aiom diff <ref>`.
4. **Review**: correctness, tests, API changes, concurrency, security.
   Cross-check the PR body claims against the diff.
5. **Submit**: `aiom review <ref> --verdict … --summary …`; put longer
   reasoning in notes.
6. **Report**: tell the maintainer what you reviewed and what you found.

## Applying fixes when the maintainer asks

Only when the maintainer explicitly asks you to fix **their own** PR:

1. **Check ownership**: `aiom --json pr <ref> | jq -r .author` must match
   `gh api user --jq .login`. If it does not, stop and ask; never push someone
   else's branch.
2. **Refresh**: `aiom checkout-pr <ref>`, and note the head SHA it lands on.
3. **Change**: work in that worktree, on `aiom/pr-{n}`, not in another local
   checkout of the PR branch. Follow the repo's own commit conventions
   (amend vs. new commit, sign-off, signing).
4. **Push**, only if asked. Confirm the worktree's `origin` is the PR's head
   repository (the maintainer's fork; for a same-repo branch, the canonical
   repo). `aiom/pr-{n}` has no upstream, so name the PR's head branch and
   lease against the head you started from:
   ```bash
   git push --force-with-lease=refs/heads/<head-branch>:<old-head-sha> \
     origin HEAD:refs/heads/<head-branch>
   ```
   Get `<head-branch>` and the head repo from
   `gh pr view <n> -R <owner>/<name> --json author,headRefName,headRepository,headRepositoryOwner,isCrossRepository`.
   If the PR is cross-repository, push only to the maintainer's own fork;
   never to a stranger's fork.
5. **Report**: tell the maintainer that their own local copy of the branch, if
   any, is now behind the remote.

## Raw API (fallback)

Base `$AIOM_BASE_URL/api/v1`, header `Authorization: Bearer $AIOM_AGENT_TOKEN`.

| Method | Path | Purpose |
|---|---|---|
| GET | `/repos` | visible repos + open counts |
| GET | `/prs?status=…&org=…&limit=…` | queue listing (limit 1–200, default 50) |
| GET | `/prs/{id}` | PR detail (AI verdict/summary/comments, local reviews) |
| GET | `/prs/by-number/{owner}/{repo}/{number}` | PR detail by GitHub number |
| GET | `/prs/{id}/diff` | unified diff (`text/plain`; 503 if unavailable) |
| POST | `/prs/{id}/local-review` | advisory review: `{verdict, summary, notes, agent}` |
| GET | `/issues?status=…&org=…&limit=…` | triage listing |
| GET | `/issues/{id}`, `/issues/by-number/{owner}/{repo}/{number}` | issue detail |
| GET | `/prs/{id}` etc. | 404 when the token cannot see the repo |

## Guardrails

- **Never** comment, label, review, or merge on GitHub, and never push on your
  own initiative. Push only a fix the maintainer explicitly asked for, only to
  their own PR branch, using the lease in "Applying fixes when the maintainer
  asks". All other GitHub interaction is read-only (clone, fetch diff).
- Apart from those requested pushes, your only write surface is the
  local-review record (advisory, SQLite-only).
- Do not attempt to log in to the web UI; the agent token is your only
  credential.
- Secrets hygiene: the bearer token grants read access to your visible mirrored
  items. Do not echo it into logs or files.
