Documentation
¶
Overview ¶
Package geminicli implements the Gemini model adapter via `gemini -o text`. Prompts are piped via stdin per ADR 0007.
Why text mode, not json ¶
`gemini -o json` returns a structured envelope with response, stats, and error fields ({"response": "<model text>", ...}). Text mode returns the raw model output, which by prompt contract is the {"findings":[...]} JSON object that model.ParseFindings expects. Skipping the envelope keeps parsing identical across all adapters.
Why no --output-schema ¶
Gemini has no native schema flag (unlike Codex which uses --output-schema for runtime enforcement). JSON shape is enforced via prompt instructions and validated by model.ParseFindings, which already tolerates the kinds of drift gemini sometimes produces (code fences, leading prose). Same risk profile as the Claude adapter.
Replaces antigravity as default third model ¶
Antigravity (`agy`) requires interactive browser OAuth on every invocation with no persistent-token path (spike S8b), so it cannot run non-interactively. Gemini fills the third-model slot in v1 with the same priority pattern (codex > claude > gemini) used by the model picker and synthesis chain-fallback.
Index ¶
- Constants
- type Adapter
- func (a *Adapter) Name() string
- func (a *Adapter) Preflight(_ context.Context) error
- func (a *Adapter) Review(ctx context.Context, input *review.ReviewInput) (*review.ModelReviewResult, error)
- func (a *Adapter) Synthesize(ctx context.Context, input *review.ReviewInput, ...) (*review.ModelReviewResult, error)
Constants ¶
const DefaultInputBudgetBytes = 256 * 1024
DefaultInputBudgetBytes caps the prompt size sent to gemini. Matches the claudecli budget (256 KB) since both adapters consume the same model.BuildPrompt scaffold and the budget is calibrated per the spike S9 measurements documented in claudecli/adapter.go.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Adapter ¶
type Adapter struct {
// contains filtered or unexported fields
}
Adapter implements the model.Model interface against the Gemini CLI.
func New ¶
New constructs an Adapter. Passing nil uses provider.DefaultRunner; lookPath defaults to exec.LookPath. Tests override fields directly (the package is internal-only).
func (*Adapter) Name ¶
Name returns the model identifier surfaced to users via the picker and attached to validated findings.
func (*Adapter) Preflight ¶
Preflight verifies the gemini binary is on PATH. The model is never invoked when this fails; the user sees an actionable install hint instead of a stack trace from os/exec.
func (*Adapter) Review ¶
func (a *Adapter) Review(ctx context.Context, input *review.ReviewInput) (*review.ModelReviewResult, error)
Review invokes gemini with `-o text --skip-trust`. Stdin piping, JSON shape, and validation are prompt-engineered (see prompt-contract.md): the model is instructed to emit a {"findings":[...]} JSON object as its entire response, so text mode returns exactly that.
We deliberately do NOT use `-o json`, which wraps the model output in a {"response": ..., "stats": ...} envelope. That envelope would have to be unwrapped before parsing; text mode skips that step.
--skip-trust bypasses gemini's per-directory workspace-trust gate. Diffsmith pipes the full diff via stdin and gemini never reads files from the CWD, so the trust check has no semantic meaning here — and without the flag, gemini exits 55 ("not running in a trusted directory") whenever diffsmith is run from a repo the user hasn't trusted via gemini's interactive prompt.
func (*Adapter) Synthesize ¶
func (a *Adapter) Synthesize(ctx context.Context, input *review.ReviewInput, results []*review.ModelReviewResult) (*review.ModelReviewResult, error)
Synthesize runs gemini against the synthesis prompt that combines the diff with N other reviewers' findings.