feat(engine): add opencode CLI review engine
Add a third review harness alongside the in-process majordomo loop and the
claude-code CLI shell-out: the OpenCode CLI (opencode.ai) driving an ollama-cloud
model, selected by an "opencode/<model>" spec. The goal is to benchmark gadfly's
boutique executus harness against a freely-available agentic harness on the SAME
model (e.g. "ollama-cloud/glm-5.2" vs "opencode/glm-5.2").
OpenCode has no --append-system-prompt flag, so the lens system prompt and the
read-only discipline are delivered through a generated config injected via
OPENCODE_CONFIG_CONTENT: a "gadfly" agent whose prompt is the system prompt with
edit/bash denied at both the global and agent level, plus a "gadfly" ollama-cloud
provider. That env var is the highest-precedence config source in the container,
so a reviewed repo's own opencode.json can't re-enable edits on the reviewer.
Spec forms: "opencode/<model>" (wrapped in the generated provider), the
"open-code/" alias, "opencode/<provider>/<model>" pass-through to OpenCode's own
registry, and bare "opencode". Model ids are taken verbatim so colon-bearing
ollama ids (qwen3-coder:480b-cloud) survive. Auth reuses OLLAMA_CLOUD_API_KEY
(mapped to OLLAMA_API_KEY, referenced as {env:OLLAMA_API_KEY} in config, never a
literal secret). Knobs mirror GADFLY_CLAUDE_*: GADFLY_OPENCODE_BIN/MODEL/BASE_URL/
EXTRA_ARGS. openCodeEnv() forwards OLLAMA_API_KEY (the inverse of claudeEnv) but
still withholds the Gitea/findings/Anthropic secrets.
main.go engine selection is now a switch (claude-code / opencode / majordomo), and
the auto-select path uses a type-check instead of a boolean so a shell-out engine
can never hit the *majordomoEngine assertion. auto-select and delegate_investigation
stay majordomo-only and are skipped for opencode (the CLI does its own legwork).
Dockerfile bundles opencode-ai (npm auto-selects its musl build on alpine) with a
best-effort version check + provider pre-warm that never fails the shared image
build. README/examples/CLAUDE.md/scripts updated per the maintenance rules.
Tests: new opencode_test.go mirrors engine_test.go (spec/model/args/config/env-
filter + stub-CLI runtime tests). Verified end-to-end with a fake opencode CLI:
correct argv, injected config, and consolidated markdown output.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
+20
@@ -33,6 +33,26 @@ RUN apk add --no-cache bash git curl jq ca-certificates nodejs npm procps
|
||||
# CLI to the image (notably larger); ollama-only users pay the size but nothing
|
||||
# else. Auth is provided at runtime via CLAUDE_CODE_OAUTH_TOKEN / ANTHROPIC_API_KEY.
|
||||
RUN npm install -g @anthropic-ai/claude-code && npm cache clean --force
|
||||
# Bundle the OpenCode CLI (opencode.ai) for the `opencode` review engine
|
||||
# (GADFLY_MODELS=opencode/<model>): a freely-available agentic harness driving an
|
||||
# ollama-cloud model, used to benchmark it against gadfly's own executus harness
|
||||
# on the same model. Auth reuses OLLAMA_CLOUD_API_KEY at runtime. opencode ships a
|
||||
# compiled (Bun) binary; it publishes musl variants (opencode-linux-*-musl) that
|
||||
# npm auto-selects on alpine via the package "libc" field. libstdc++/libgcc are
|
||||
# the Bun binary's runtime deps; gcompat is a belt-and-suspenders fallback in case
|
||||
# npm ever resolves a glibc build here.
|
||||
RUN apk add --no-cache gcompat libstdc++ libgcc \
|
||||
&& npm install -g opencode-ai \
|
||||
&& npm cache clean --force
|
||||
# Best-effort: confirm the binary runs and pre-warm the openai-compatible provider
|
||||
# package into opencode's cache so a review doesn't pay a first-run npm fetch. The
|
||||
# warm-up model call intentionally fails against a dead URL. Never fail the build:
|
||||
# a musl/runtime quirk here must not break the shared image for ollama/claude
|
||||
# users — a broken opencode engine degrades to a normal (advisory) pass error.
|
||||
RUN opencode --version >/dev/null 2>&1 \
|
||||
&& OPENCODE_CONFIG_CONTENT='{"provider":{"gadfly":{"npm":"@ai-sdk/openai-compatible","options":{"baseURL":"http://127.0.0.1:9/v1"},"models":{"x":{}}}}}' \
|
||||
timeout 120 opencode run --model gadfly/x "warm" >/dev/null 2>&1 \
|
||||
; true
|
||||
COPY --from=build /out/gadfly /usr/local/bin/gadfly
|
||||
COPY scripts /app/scripts
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
|
||||
Reference in New Issue
Block a user