Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,12 @@ Use `@main` while the project is pre-release. After the first stable release, pi

| Mode | Provider examples | Credentials | Best for |
|---|---|---|---|
| Local CLI | `codex-cli`, `claude-cli` | Existing CLI login | Local development or self-hosted runners |
| Local CLI | `codex-cli`, `claude-cli`, `grok-cli`, `opencode-cli` | Existing CLI login | Local development or self-hosted runners |
| Hosted API | `openai`, `anthropic`, `gemini`, `mistral`, `groq` | Provider API key | Managed CI |
| Local model | `ollama` | Usually none | Privacy and predictable cost |
| Gateway | `openrouter` or a custom `--base-url` | Gateway-specific | Central routing and policy |

Provider names other than the two local CLIs resolve to factories exported by [`@agentskit/adapters`](https://www.npmjs.com/package/@agentskit/adapters). Run `npx --yes github:AgentsKit-io/code-review-cli --list-providers` for common choices.
`grok` is the xAI API provider; `grok-cli` is the separate Grok Build CLI entry. `opencode-cli` is the OpenCode CLI entry. API providers are discovered from factories exported by [`@agentskit/adapters`](https://www.npmjs.com/package/@agentskit/adapters). Run `npx --yes github:AgentsKit-io/code-review-cli --list-providers` to see IDs, support levels, transports, and model requirements.

Credentials resolve in this order:

Expand Down Expand Up @@ -224,6 +224,8 @@ Run these commands from the repository you want to review:
|---|---|---|---|
| `codex-cli` | Codex CLI logged in | Optional | `npx --yes github:AgentsKit-io/code-review-cli --provider codex-cli` |
| `claude-cli` | Claude CLI logged in | Optional | `npx --yes github:AgentsKit-io/code-review-cli --provider claude-cli` |
| `grok-cli` | Grok Build CLI; experimental | Optional | `... --provider grok-cli` |
| `opencode-cli` | OpenCode CLI; experimental | Optional | `... --provider opencode-cli` |
| `openai` | `OPENAI_API_KEY` | Required | `... --provider openai --model gpt-4o` |
| `anthropic` | `ANTHROPIC_API_KEY` | Required | `... --provider anthropic --model <model>` |
| `gemini` | `GEMINI_API_KEY` | Required | `... --provider gemini --model <model>` |
Expand Down Expand Up @@ -257,10 +259,23 @@ In shortened examples, replace `...` with `npx --yes github:AgentsKit-io/code-re
| `--no-fail` | Keep findings advisory |
| `--conventions <path>` | Inject project conventions |
| `--api` | Back-compatible alias for `--provider anthropic` |
| `doctor --provider <name>` | Offline provider diagnostics; no model request |
| `doctor --live` | Explicit provider smoke-test mode |
| `doctor --json` | Stable machine-readable diagnostics |
| `--mode <mode>` | `isolated` (default) or explicit local-only `trusted-local` |
| `--help` | Full command help |

When no conventions path is supplied, the CLI looks for `CONVENTIONS.md`, `CONTRIBUTING.md`, `.cursorrules`, or `AGENTS.md`.

### Doctor

Run `doctor` before a review to check a registered provider’s executable, version, transport, model requirement, configuration mode, and credential presence. It is offline by default: API credentials are checked only for presence and values are never printed; local CLI login is represented as login-managed until a provider-specific live check is available. Unknown local CLI versions warn locally and fail when `CI=true`. Exit `0` means healthy, `1` means a failed diagnostic, and `2` means invalid CLI usage.

```sh
npx --yes github:AgentsKit-io/code-review-cli doctor --provider codex-cli
npx --yes github:AgentsKit-io/code-review-cli doctor --provider openai --model gpt-4o --json
```

## Cost and privacy

A full review runs seven lenses across selected files and then verifies candidate findings. Control usage with `--max-files`, `--votes`, `--concurrency`, paths, and workflow triggers. For sensitive code, use a local model or an approved private gateway; provider data policies still apply to hosted APIs.
Expand Down
15 changes: 14 additions & 1 deletion docs/OPERATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This guide is the repository-native reference for running AgentsKit Code Review

| Provider class | Examples | Secret or login | Network boundary |
|---|---|---|---|
| Logged-in local CLI | `codex-cli`, `claude-cli` | Existing local login | Provider CLI policy |
| Logged-in local CLI | `codex-cli`, `claude-cli`, `grok-cli`, `opencode-cli` | Existing local login | Provider CLI policy |
| Hosted API | `openai`, `anthropic`, `gemini`, `mistral`, `groq` | Repository/org secret | Selected code reaches provider |
| Local model | `ollama` | Usually none | Host or runner network only |
| Gateway | `openrouter`, custom `--base-url` | Gateway secret | Gateway policy and routing |
Expand All @@ -15,6 +15,19 @@ Credential precedence is `--api-key`, `LLM_API_KEY`, then `<PROVIDER>_API_KEY`.

Do not run hosted review on code whose policy forbids external processing. A local model reduces external disclosure but does not remove the need to secure the runner, logs, cache, and generated SARIF.

## Provider registry and doctor

Provider IDs are versioned registry entries. `grok` is the xAI API adapter, while `grok-cli` is the experimental Grok Build CLI; `opencode-cli` is the experimental OpenCode CLI. `--list-providers` prints registry metadata and dynamically discovered API factories, including each support level (`stable`, `experimental`, or `unsupported`), transport, and model requirement.

Use the offline doctor before execution:

```sh
npx --yes github:AgentsKit-io/code-review-cli doctor --provider codex-cli
npx --yes github:AgentsKit-io/code-review-cli doctor --provider openai --model gpt-4o --json
```

It checks the named executable and version, transport, model requirement, configuration mode, and credential presence without making a model request. API keys are represented only as `configured` or `missing`; they are never printed. Local CLI credentials are represented as login-managed because login storage is provider-specific. `doctor --live` is the explicit provider smoke-test path. Unknown local CLI versions warn during local runs and fail in CI. Doctor exits `0` when checks pass, `1` when a provider check fails, and `2` for invalid usage.

## pre-commit integration

The root `.pre-commit-hooks.yaml` exposes `agentskit-review` as a Node hook. It uses `pass_filenames: false` because the CLI reviews a Git diff, explicit paths, a pull request, or stdin rather than interpreting positional filenames. It is confined to the `manual` stage by default so cloning the hook does not silently add model calls to every commit.
Expand Down
34 changes: 31 additions & 3 deletions llms-full.txt
Original file line number Diff line number Diff line change
Expand Up @@ -169,12 +169,12 @@ Use `@main` while the project is pre-release. After the first stable release, pi

| Mode | Provider examples | Credentials | Best for |
|---|---|---|---|
| Local CLI | `codex-cli`, `claude-cli` | Existing CLI login | Local development or self-hosted runners |
| Local CLI | `codex-cli`, `claude-cli`, `grok-cli`, `opencode-cli` | Existing CLI login | Local development or self-hosted runners |
| Hosted API | `openai`, `anthropic`, `gemini`, `mistral`, `groq` | Provider API key | Managed CI |
| Local model | `ollama` | Usually none | Privacy and predictable cost |
| Gateway | `openrouter` or a custom `--base-url` | Gateway-specific | Central routing and policy |

Provider names other than the two local CLIs resolve to factories exported by [`@agentskit/adapters`](https://www.npmjs.com/package/@agentskit/adapters). Run `npx --yes github:AgentsKit-io/code-review-cli --list-providers` for common choices.
`grok` is the xAI API provider; `grok-cli` is the separate Grok Build CLI entry. `opencode-cli` is the OpenCode CLI entry. API providers are discovered from factories exported by [`@agentskit/adapters`](https://www.npmjs.com/package/@agentskit/adapters). Run `npx --yes github:AgentsKit-io/code-review-cli --list-providers` to see IDs, support levels, transports, and model requirements.

Credentials resolve in this order:

Expand Down Expand Up @@ -242,6 +242,8 @@ Run these commands from the repository you want to review:
|---|---|---|---|
| `codex-cli` | Codex CLI logged in | Optional | `npx --yes github:AgentsKit-io/code-review-cli --provider codex-cli` |
| `claude-cli` | Claude CLI logged in | Optional | `npx --yes github:AgentsKit-io/code-review-cli --provider claude-cli` |
| `grok-cli` | Grok Build CLI; experimental | Optional | `... --provider grok-cli` |
| `opencode-cli` | OpenCode CLI; experimental | Optional | `... --provider opencode-cli` |
| `openai` | `OPENAI_API_KEY` | Required | `... --provider openai --model gpt-4o` |
| `anthropic` | `ANTHROPIC_API_KEY` | Required | `... --provider anthropic --model <model>` |
| `gemini` | `GEMINI_API_KEY` | Required | `... --provider gemini --model <model>` |
Expand Down Expand Up @@ -275,10 +277,23 @@ In shortened examples, replace `...` with `npx --yes github:AgentsKit-io/code-re
| `--no-fail` | Keep findings advisory |
| `--conventions <path>` | Inject project conventions |
| `--api` | Back-compatible alias for `--provider anthropic` |
| `doctor --provider <name>` | Offline provider diagnostics; no model request |
| `doctor --live` | Explicit provider smoke-test mode |
| `doctor --json` | Stable machine-readable diagnostics |
| `--mode <mode>` | `isolated` (default) or explicit local-only `trusted-local` |
| `--help` | Full command help |

When no conventions path is supplied, the CLI looks for `CONVENTIONS.md`, `CONTRIBUTING.md`, `.cursorrules`, or `AGENTS.md`.

### Doctor

Run `doctor` before a review to check a registered provider’s executable, version, transport, model requirement, configuration mode, and credential presence. It is offline by default: API credentials are checked only for presence and values are never printed; local CLI login is represented as login-managed until a provider-specific live check is available. Unknown local CLI versions warn locally and fail when `CI=true`. Exit `0` means healthy, `1` means a failed diagnostic, and `2` means invalid CLI usage.

```sh
npx --yes github:AgentsKit-io/code-review-cli doctor --provider codex-cli
npx --yes github:AgentsKit-io/code-review-cli doctor --provider openai --model gpt-4o --json
```

## Cost and privacy

A full review runs seven lenses across selected files and then verifies candidate findings. Control usage with `--max-files`, `--votes`, `--concurrency`, paths, and workflow triggers. For sensitive code, use a local model or an approved private gateway; provider data policies still apply to hosted APIs.
Expand Down Expand Up @@ -352,7 +367,7 @@ This guide is the repository-native reference for running AgentsKit Code Review

| Provider class | Examples | Secret or login | Network boundary |
|---|---|---|---|
| Logged-in local CLI | `codex-cli`, `claude-cli` | Existing local login | Provider CLI policy |
| Logged-in local CLI | `codex-cli`, `claude-cli`, `grok-cli`, `opencode-cli` | Existing local login | Provider CLI policy |
| Hosted API | `openai`, `anthropic`, `gemini`, `mistral`, `groq` | Repository/org secret | Selected code reaches provider |
| Local model | `ollama` | Usually none | Host or runner network only |
| Gateway | `openrouter`, custom `--base-url` | Gateway secret | Gateway policy and routing |
Expand All @@ -361,6 +376,19 @@ Credential precedence is `--api-key`, `LLM_API_KEY`, then `<PROVIDER>_API_KEY`.

Do not run hosted review on code whose policy forbids external processing. A local model reduces external disclosure but does not remove the need to secure the runner, logs, cache, and generated SARIF.

## Provider registry and doctor

Provider IDs are versioned registry entries. `grok` is the xAI API adapter, while `grok-cli` is the experimental Grok Build CLI; `opencode-cli` is the experimental OpenCode CLI. `--list-providers` prints registry metadata and dynamically discovered API factories, including each support level (`stable`, `experimental`, or `unsupported`), transport, and model requirement.

Use the offline doctor before execution:

```sh
npx --yes github:AgentsKit-io/code-review-cli doctor --provider codex-cli
npx --yes github:AgentsKit-io/code-review-cli doctor --provider openai --model gpt-4o --json
```

It checks the named executable and version, transport, model requirement, configuration mode, and credential presence without making a model request. API keys are represented only as `configured` or `missing`; they are never printed. Local CLI credentials are represented as login-managed because login storage is provider-specific. `doctor --live` is the explicit provider smoke-test path. Unknown local CLI versions warn during local runs and fail in CI. Doctor exits `0` when checks pass, `1` when a provider check fails, and `2` for invalid usage.

## pre-commit integration

The root `.pre-commit-hooks.yaml` exposes `agentskit-review` as a Node hook. It uses `pass_filenames: false` because the CLI reviews a Git diff, explicit paths, a pull request, or stdin rather than interpreting positional filenames. It is confined to the `manual` stage by default so cloning the hook does not silently add model calls to every commit.
Expand Down
2 changes: 1 addition & 1 deletion readme-standard-v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@
"docs/OPERATIONS.md",
"test/cli-smoke.test.mjs"
],
"sourceHash": "sha256:d6f8cf7be73f4b674d2b4cfb3da901471107d28baa91cc14031df19753857f6e"
"sourceHash": "sha256:9e43fecef7502fabffa1bc976a9febebdf14d7522431cd18e8f7bb4553078e68"
},
"exceptions": []
}
Expand Down
80 changes: 69 additions & 11 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
*
* Exit code: 1 when a finding at/above --block survives (unless --no-fail) — wire to CI.
*/
import * as adapters from '@agentskit/adapters'
import type { AdapterFactory } from '@agentskit/core'
import { createProgressObserver } from '@agentskit/ink'
import { readFileSync } from 'node:fs'
Expand All @@ -23,6 +22,7 @@ import { claudeCode } from './claude-code-adapter.js'
import { codexCli } from './codex-adapter.js'
import { ollamaReview } from './ollama-adapter.js'
import type { SourceConfig } from '../agents/code-review/sources.js'
import { diagnoseProvider, factoryFor, providerEntry, providerRegistry, resolveProviderId, type DoctorReport, type ProviderEntry } from './provider-registry.js'

const HELP = `AgentsKit Code Review — deep, low-noise review with your model

Expand Down Expand Up @@ -62,14 +62,20 @@ Provider options:
--model <id> Model id (required for API/local-server providers)
--api-key <key> Or use LLM_API_KEY / <PROVIDER>_API_KEY
--base-url <url> Custom endpoint or local gateway
--transport <name> Provider transport (doctor validates it)
--api Back-compatible alias for --provider anthropic

Diagnostics:
doctor Check one provider without making a model request
--live Explicitly enable a provider smoke test for doctor
--json Emit machine-readable doctor output
--mode <mode> Configuration mode: isolated or trusted-local
--ci Apply CI version and trust checks

--help Show this help
--list-providers List common providers
`

const PROVIDERS = 'codex-cli\nclaude-cli\nanthropic\nopenai\ngemini\ngrok\nollama\ndeepseek\nmistral\ngroq\nopenrouter\ntogether'

function flag(name: string): string | undefined {
const i = process.argv.indexOf(`--${name}`)
return i >= 0 ? process.argv[i + 1] : undefined
Expand Down Expand Up @@ -111,10 +117,15 @@ async function main() {
return
}
if (has('list-providers')) {
console.log(PROVIDERS)
console.log(providerRegistry().map(formatProvider).join('\n'))
return
}
if (process.argv.includes('doctor') || has('doctor')) {
await runDoctor()
return
}
const source = await resolveSource()
await preflightProvider()
const adapter = buildAdapter()

const reporters: Reporter[] = [markdownReporter()]
Expand Down Expand Up @@ -153,8 +164,9 @@ async function main() {
* `{ apiKey, model, baseUrl? }`. `--api` is a back-compat alias for `--provider anthropic`.
*/
function buildAdapter(): AdapterFactory {
const provider = flag('provider') ?? (has('api') ? 'anthropic' : undefined)
if (!provider) throw new Error('choose a provider with --provider <name> (run --list-providers for common options)')
const requestedProvider = flag('provider') ?? (has('api') ? 'anthropic' : undefined)
const provider = requestedProvider && resolveProviderId(requestedProvider)
if (!provider) throw new Error(requestedProvider ? `unknown --provider "${requestedProvider}" (run --list-providers for common options)` : 'choose a provider with --provider <name> (run --list-providers for common options)')
const model = flag('model') ?? (has('api') ? 'claude-opus-4-8' : undefined)
if (provider === 'claude-cli') return claudeCode({ model })
if (provider === 'codex-cli') return codexCli({ model })
Expand All @@ -163,14 +175,60 @@ function buildAdapter(): AdapterFactory {
return ollamaReview({ model, ...(flag('base-url') ? { baseUrl: flag('base-url') } : {}) })
}

const make = (adapters as Record<string, unknown>)[provider]
if (typeof make !== 'function') {
throw new Error(`unknown --provider "${provider}". Use "claude-cli" or any @agentskit/adapters factory (anthropic, openai, gemini, grok, ollama, deepseek, mistral, groq, openrouter, together, …).`)
}
const entry = providerEntry(provider)
const make = entry && factoryFor(entry)
if (!entry || !make) throw new Error(`provider "${provider}" is registered but has no local adapter yet`)
if (!model) throw new Error(`--model is required for provider "${provider}"`)
const apiKey = flag('api-key') ?? process.env.LLM_API_KEY ?? process.env[`${provider.toUpperCase()}_API_KEY`] ?? ''
const baseUrl = flag('base-url')
return (make as (c: Record<string, unknown>) => AdapterFactory)({ apiKey, model, ...(baseUrl ? { baseUrl } : {}) })
return make({ apiKey, model, ...(baseUrl ? { baseUrl } : {}) })
}

async function preflightProvider(): Promise<void> {
const requested = flag('provider') ?? (has('api') ? 'anthropic' : undefined)
const id = requested && resolveProviderId(requested)
const entry = id && providerEntry(id)
if (!entry || entry.kind === 'api') return
const report = await diagnoseProvider({
provider: entry.id,
model: flag('model'),
transport: flag('transport'),
mode: flag('mode'),
apiKey: flag('api-key'),
ci: has('ci'),
})
const version = report.checks.find((check) => check.name === 'version')
if (version?.status === 'warn') console.error(`warning: ${entry.id} ${version.detail}`)
if (!report.ok) throw new Error(`${entry.id} provider preflight failed: ${report.checks.filter((check) => check.status === 'fail').map((check) => `${check.name}: ${check.detail}`).join('; ')}`)
}

async function runDoctor(): Promise<void> {
const requested = flag('provider') ?? (has('api') ? 'anthropic' : undefined)
if (!requested) throw new Error('doctor needs --provider <name>')
const report = await diagnoseProvider({
provider: requested,
model: flag('model'),
transport: flag('transport'),
mode: flag('mode'),
live: has('live'),
ci: has('ci'),
apiKey: flag('api-key'),
})
if (has('json')) console.log(JSON.stringify(report))
else console.log(formatDoctor(report))
if (!report.ok) process.exitCode = report.checks.some((check) => check.name === 'provider' && check.status === 'fail') ? 2 : 1
}

function formatProvider(entry: ProviderEntry): string {
const aliases = entry.aliases.length ? `\taliases=${entry.aliases.join(',')}` : ''
return `${entry.id}\tkind=${entry.kind}\tsupport=${entry.support}\ttransport=${entry.defaultTransport}\tmodel=${entry.model}${aliases}`
}

function formatDoctor(report: DoctorReport): string {
const lines = [`Provider doctor: ${report.provider} (${report.support})`]
for (const check of report.checks) lines.push(` ${check.name}: ${check.status.toUpperCase()} — ${check.detail}`)
lines.push(`Result: ${report.ok ? 'PASS' : 'FAIL'}`)
return lines.join('\n')
}

/** Best-effort: feed a conventions doc to every lens if one exists. */
Expand Down
Loading