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
64 changes: 64 additions & 0 deletions .opencode/opencode.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,57 @@
// zero-traffic window on :18751.
// "models": maintained by sync-models in the runtime overlay (~/.local/state/opencode/opencode-runtime.jsonc) — see code#4544.
},
"mistral": {
"npm": "@opencode/ai/providers/mistral",
"name": "Mistral API (drewrypope)"
// Credential: the enrolled server credential (integration
// "mistral", Bitwarden mistral.api-key); MISTRAL_API_KEY is also
// materialized into the server unit's environment (home/common).
// "models": maintained by sync-models in the runtime overlay (~/.local/state/opencode/opencode-runtime.jsonc) — see code#4544.
},
"vibe-direct": {
"npm": "@opencode/ai/providers/vibe",
"name": "Mistral Vibe Direct (native wire clone)",
// 2026-11-04 (opencode#1653, PR #1661): native in-fork emulation of
// the mistral-vibe binary — same Mistral wire, Vibe's presets and
// the attribution stamp (metadata.call_source "vibe_code", the
// metering key for the Vibe quota marts). No vibe subprocess.
// Credential: MISTRAL_API_KEY in the server unit's environment
// (vibe-auth resolution: config -> env -> ~/.vibe/.env -> keyring).
// Models are declared HERE: models.dev has no vibe entry, so
// sync-models cannot maintain this catalog. Only the default
// preset's limit was verified from the binary; the rest are the
// preset ids + names from Vibe's own catalog (opencode#1653).
"models": {
"mistral-vibe-cli-latest": {
"name": "Mistral Medium 3.5",
"limit": {
"context": 262144
}
},
"mistral-medium-latest": {
"name": "Mistral Medium"
},
"mistral-large-latest": {
"name": "Mistral Large"
},
"mistral-small-latest": {
"name": "Mistral Small"
},
"codestral-latest": {
"name": "Codestral"
},
"ministral-14b-latest": {
"name": "Ministral 14B"
},
"ministral-8b-latest": {
"name": "Ministral 8B"
},
"ministral-3b-latest": {
"name": "Ministral 3B"
}
}
},
// "openai": model catalog maintained by sync-models in the runtime overlay (~/.local/state/opencode/opencode-runtime.jsonc) — see code#4544.
// "openai-codex": retired 2026-11-03 -- definition deleted after its
// route legs were re-seated onto openai-plan (see the note at
Expand Down Expand Up @@ -1641,6 +1692,19 @@
"selection": "weighted",
"weights": { "openai.main": 2, "openai.alternate": 1 }
},
// mistral-plan (2026-11-04, Drew): the Mistral pair as ONE
// provider route — vibe-direct attempted first on every dispatch
// (the Vibe-attributed leg: metadata.call_source "vibe_code"),
// the plain Mistral API provider the reserve; the API leg serves
// only when vibe-direct fails or is demoted. Both legs resolve
// the same Bitwarden mistral.api-key credential (the vibe leg via
// MISTRAL_API_KEY in the server environment, the API leg via the
// enrolled "mistral" integration credential). Change the leg
// order HERE, in this providers list, and nowhere else.
"mistral-plan": {
"providers": ["vibe-direct", "mistral"],
"selection": "ordered"
},
// opencode-go-plans (2026-11-03, Drew): the OpenCode Go plans as
// ONE virtual provider (provider routes, opencode#1132). Consumers
// name opencode-go-plans/<model> in lieu of the per-account
Expand Down
6 changes: 3 additions & 3 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions home/common/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -1044,6 +1044,27 @@ in
};
};

# MISTRAL_API_KEY for the opencode server (opencode#1653): the value
# lives in Bitwarden (mistral.api-key), mirrored into sops and decrypted
# to /run/secrets/agent-auth/mistral-api-key (nixos/agent-auth). It must
# never enter the Nix store, so an ExecStartPre materializes a
# systemd EnvironmentFile at every server start — the same pattern as
# openclaw-facade-auth-materialize in home/openclaw — and the unit reads
# it via EnvironmentFile. The vibe provider resolves the key from the
# server process env; the mistral provider's enrolled credential
# (integration "mistral") remains its primary source.
systemd.user.services.opencode.Service = {
ExecStartPre = toString (
pkgs.writeShellScript "opencode-mistral-key-materialize" ''
set -eu
umask 077
mkdir -p "$HOME/.local/state/opencode"
printf 'MISTRAL_API_KEY=%s\n' "$(cat /run/secrets/agent-auth/mistral-api-key)" > "$HOME/.local/state/opencode/mistral-api-key.env"
''
);
EnvironmentFile = "%h/.local/state/opencode/mistral-api-key.env";
};

services.mcpx = {
# enable comes from the cascade (mkDefault at each layer).
#
Expand Down
6 changes: 6 additions & 0 deletions nixos/agent-auth/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ in
"agent-auth/cloudflare-ai-inference-token" =
userSecret "secrets/sops/common/cloudflare.yaml" "cloudflare_api_token_ai_inference";
"agent-auth/muse-sdk-token" = userSecret "secrets/sops/common/bws.yaml" "muse.sdk-token";
# Mistral API key (Bitwarden mistral.api-key): materialized into the
# opencode server unit's environment as MISTRAL_API_KEY by the
# ExecStartPre in home/common (services.opencode) — the vibe provider
# resolves it from the server process env (vibe-auth tier 2), and the
# plain mistral provider's env tier names the same variable.
"agent-auth/mistral-api-key" = userSecret "secrets/sops/common/bws.yaml" "mistral.api-key";
};

# `op` as a setgid (onepassword-cli) wrapper in /run/wrappers/bin -- required
Expand Down
Loading