Repository navigation
Description
Direction
Drew (2026-11-05): "eventually vibe direct needs to be embedded per that project" — Vibe's end state in our stack is embedded the way Mistral's own project intends: the real vibe agent hosted by the fork, not wire-emulated by it.
Current state — the shim
vibe-direct today is a wire-protocol provider in packages/ai (packages/ai/src/providers/vibe.ts + vibe-auth.ts, landed in #1653):
- Reuses the MistralChat route against
https://api.mistral.ai/v1(the same wire the binary uses), rebranded to provider idvibe, with Vibe's model presets and request defaults (temperature 1.0, reasoning_effort "high"). - Stamps requests with the binary's attribution (
metadata.call_source = "vibe_code"). - Resolves the credential the way the binary does: config → env
MISTRAL_API_KEY→~/.vibe/.env→ OS keyring (serviceai.mistral.vibe). - The vibe provider: native wire-protocol emulation of the Mistral Vibe binary (no ACP host, no subprocess) #1653 commit says it plainly: "No vibe subprocess, no ACP host." It emulates the binary's requests; the binary's agent (tools, skills, subagents, session semantics) is not in the loop.
Deployed route (developing-today/code .opencode/opencode.jsonc): model mistral-vibe-cli-latest, providers ["vibe-direct", "mistral"], vibe-direct attempted first.
Vibe's intended embedding surface (primary sources)
Mistral documents ACP as the embedding path:
- "Vibe implements the Agent Client Protocol (ACP) and is published in the ACP registry… If your client has no agent registry, install the CLI and point the client at the
vibe-acpcommand it installs." — https://docs.mistral.ai/vibe/code/use-vibe-in-other-ides - "One agent, three surfaces… They share the same engine, configuration, and customization layer (agents, skills, MCP servers)" + ACP for other clients — https://docs.mistral.ai/vibe/code/choose-cli-vscode-web-sessions
- ACP registry id:
mistral-vibe; ACP command:vibe-acp.
Installed on the laptop (vibe 3.1.0, verified 2026-11-05): three entrypoints —
vibe— interactive CLI + headless programmatic mode (-p/--prompt,--output json|streaming,--output-dirwritesexport.jsonwith token usage/cost).vibe-acp— "Run Mistral Vibe in ACP mode": JSON-RPC 2.0 over stdio, protocol v1.vibe-app-server— an app-server surface ("Unified Harness connections",--multiplex) — noted for the design record; ACP is the documented, registry-published path and the one this epic builds on.
What the host provides over ACP (observed live, see spike): the client spawns vibe-acp, drives initialize → session/new → session/prompt; the agent streams session/update (message chunks, tool calls, usage updates), delegates approvals back via session/request_permission, and exposes session modes (ask / accept-edits / auto-approve) and config options (model, reasoning effort) for the host to present and set. Session state (journal, resume) stays the agent's, under ~/.vibe.
Spike result (2026-11-05, laptop amd-6) — PROVEN
A minimal ACP host (211-line Python client, stdlib only) drove one real end-to-end turn through vibe-acp on the Vibe plan credential:
initialize→ protocolVersion 1, agent@mistralai/mistral-vibe3.1.0; capabilities: loadSession, prompt image + embeddedContext, session list/fork/close. Noauthenticatecall needed — the keyring credential was already live.session/new→ session48475654-f48c-f816-04aa-56fd06364bd4; model config optionmistral-medium-3.5(the model behind aliasmistral-vibe-cli-latest), efforthigh, default modeaccept-edits.session/prompt(instructed to runecho VIBE-EMBED-SPIKE-OKvia its bash tool) → tool callbash: echo VIBE-EMBED-SPIKE-OK, reply exactlyMARKER=VIBE-EMBED-SPIKE-OK,stopReason: end_turn, usage: 16,864 total tokens (16,643 in / 221 out, 3,072 cached read) in the prompt response, plus streamingusage_updatenotifications.- Artifacts on the laptop:
~/work/spikes/vibe-acp-embed-2026-11-05/(acp_client.py,transcript.jsonl,summary.json,run.log).
The embedded contract works tonight, unmodified, on the plan credential — no console cookies involved.
Target architecture
The fork hosts vibe-acp as an embedded agent runtime: a session in the fork maps to an ACP session in a supervised vibe-acp process; prompts/streaming/tool calls flow over ACP; host approvals answer session/request_permission; modes + model/effort surface as session config; usage lands in the quota pipeline with call_source=vibe_code parity. The embedded route registers switchboard-style beside vibe-direct (definition present, enablement a flag) and the shim retires only after parity acceptance.
Auth rule (Drew, standing): the embedded path rides the keyring/OAuth credential with its own refresh — never a browser console cookie. Anything browser-born in any provider must have auto-renew built in; Vibe's keyring credential already satisfies this and the design must keep it that way.
Children
- ACP client runtime: host
vibe-acp(lifecycle, streaming, session mapping) - Permission + mode bridge (
session/request_permission→ fork approvals; modes/model/effort config options) - Embedded auth: keyring credential lifecycle + refresh for the hosted process
- Usage attribution: ACP usage → quota gatherer,
vibe_codeparity (adjacent: quota: mistral browser-dependent usage read (Vibe plan) — producer + watchdog adapter #1 openchamber#1630) - Switchboard slice: embedded route disabled-by-default beside
vibe-direct; parity acceptance + cutover criteria
Design note: ~/workspace/scratch/vibe-embed-2026-11-05/design.md (fleet scratch, 2026-11-05).
Activity
dezren39 commentedon Nov 5, 2026
Children filed:
Spike evidence summary and primary-source citations are in the epic body; full design note in fleet scratch (~/workspace/scratch/vibe-embed-2026-11-05/design.md).
dezren39 commentedon Nov 5, 2026
Spike update (same night, 2026-11-05): the permission round-trip is now PROVEN, and two records need reconciling.
Run 2 — ask mode, safe command.
session/set_mode→askaccepted. Echo-marker turn: session4795ea5b-15fb-2b5e-8880-9ababaf20069, 0 permission requests, 16,837 tokens. (Mode list also includes a fourth mode,smart-approve.)Run 3 — ask mode, risky command. Create +
rma file from an untrusted cwd: the agent issued exactly onesession/request_permissionwith options allow_once / allow_always (session) / allow_always_permanent / reject_once (Deny). Host answered allow_always; the command executed and verified its own deletion; reply DONE-RM-TEST; 16,791 tokens. Approval delegation is risk-classified:echonever asks (any mode seen),rmasks. Deny path still unproven — stays in #1711.Journal finding. The agent's session journal lives at
~/.vibe/logs/session/unified/<sessionId>/generations/<gen>/. For spike session 48475654…,runtime-state.jsonrecordssession_metadata.active_model = mistral-large-4-0-3— while the ACP config option presents the model asmistral-medium-3.5("mistral-vibe-cli-latest"). The preset↔backing-model mapping needs pinning before #1713 keys attribution on a name.Design note updated:
~/workspace/scratch/vibe-embed-2026-11-05/design.md(§3 follow-up runs + journal, §7 open questions).dezren39 commentedon Nov 5, 2026
CLOSED — direction corrected by Drew (2026-11-05 01:13 CST): 'no we emulate and don't actually need vibe at all except maybe for certain login calls. same for all direct.' The architecture for vibe-direct and all *-direct providers is EMULATION of the first-party wire, not ACP embedding. The spike evidence in this epic stands as protocol research. Doctrine + vibe-direct compliance record + the equivalent audit for the other direct providers: #1717.
dezren39 commentedon Nov 5, 2026
Requirement handed over from the quota single-source program (developing-today/code#6125, Drew's order 2026-11-05 01:25 CST): vibe-direct must own a QUOTA function.
Drew: "if other direct lanes don't handle all functions including quota then fix them too tonight don't wait. renewal, everything. dashboard and all other sources should rely on opencode quota subcommand only, 1 single source for quota info."
Quota is a provider function like any other, and under the emulation doctrine (Drew, 2026-11-05 01:13) it is implemented IN the provider, emulating the first-party surface. For vibe-direct that surface is the Mistral admin console budget read — the figures exist and were verified live tonight:
GET admin.mistral.ai/api/local-trpc/billing.budget→{api_budget: {usage_percentage: 3.157, …}, vibe_budget: {usage_percentage: 0.0246, …}, reset_at: 2026-12-01}against budgets API $15/mo, Vibe $150/mo..mistral.ai) ONLY — the keyring API key gets a 302 on this endpoint. Cookie expires 2027-02-02. Its renewal classification belongs to the provider-auth auto-renewal registry (Drew's standing rule, 2026-11-05 01:10): record how this cookie renews before it expires; do not let the quota function die silently with it.Acceptance: vibe-direct's quota implementation returns both budgets as windows in the shared result shape ({usedPercent, resetAt, valueLabel with the dollar figures}), and
opencode quota --json(the new subcommand, tracked on code#6125) reports vibe-direct/mistral figures matching the console truth above (small drift from new usage is fine). The gatherer-side console-fetch design previously recorded on openchamber#1630 is superseded — the fetch lives in the provider now, never in the gatherer.