Originally created by: imshaikot
Closes [#9].
The side panel ran on Claude Code, Codex or Antigravity. This adds Mistral Vibe (vibe) as a fourth, marked beta, so a Le Chat subscription or a Mistral API key is a way in too.
It is the first file-configured runner with real containment: --enabled-tools is a per-run allowlist, so Vibe's shell and file tools are never loaded — the allowlist class, alongside Claude Code.
vibe --prompt <instruction> --output streaming --trust --agent ask
--enabled-tools 'browsentic_*' [--resume <sessionId>]
The MCP server, the picked model and the tool permissions go into a .vibe/config.toml written into the run's own folder under ~/.browsentic/agents/vibe/run/<runId>, with the system prompt as AGENTS.md beside it. The user's ~/.vibe/config.toml is read for their key and models and never written, so there is no check() / grant().
runners/vibe.ts| Change | Why |
|---|---|
Runner.endsOnExit |
Vibe's stream has no closing event. runStream rejected any run that closed before the reader called done; a runner can now say exit code 0 is the end of the turn. A non-zero exit still fails through hint() |
StreamContext.mcpTools |
Vibe looks permissions up by exact tool name, MCP tools default to ask, and headless turns an ask into a refusal. So every tool is granted by name, from the daemon's live list (AgentSessionDeps.actionNames) — a drifted extension manifest is still covered. agentRunToolNames() in tool-names.ts shares the status/site-map/focus-shot names with the MCP server rather than restating them |
Requirements.allows in spawn.ts |
vetPlan now asserts that nothing outside the expected names ever follows --enabled-tools, and that the flag is present at all — an empty list means every tool |
FORBIDDEN gains --auto-approve |
The alias of --yolo, which was already there. Checked for every runner |
MISTRAL_ sealed, MISTRAL_ / VIBE_ kept for Vibe |
MISTRAL_API_KEY reads as a credential and was being sealed out of the run; it is now Vibe's own, and lost by the other three |
--agent ask pins the approval profile, so a user whose default_agent is auto-approve does not carry that into a browser run.
sessionId--resume re-emits the whole conversation before the new turn; entries whose createdAt predates the reader are skippedweb_search, web_fetch) — Browsentic's MCP calls already report themselvesOne-shot tasks get no MCP server, and either read_file alone or re:^$, a pattern no tool matches.
thinking key in Vibe's own config.yarn check — both type-checks, 40 toolkit checks, 596 security checks (15 new: both plans contained in both modes and with research/reads, the config grants by name and never a local tool, a task carries no MCP server, and tampering — bash, *, a dropped allowlist, a task reaching the browser, --auto-approve, --yolo, another approval profile, a lost config — is each caught)reader(): session, replay skipped, MCP call not double-drawn, web_search reported, two messages separated, junk lines ignoredvibe through the real runStream: clean exit resolves with stopReason: end_turn and the session id; exit 1 with Vibe's missing-key message becomes the vibe --setup hint; MISTRAL_API_KEY reaches the child and AWS_* does notPATH, AGENT_MISSING with uv tool install mistral-vibe as the fix without itNot verified: the real CLI. Vibe was not installed and there was no Mistral key. The entry field names (sessionId, createdAt, detail.toolName) come from reading Vibe v2.25.5's source, not from captured output. Before the beta label comes off: uv tool install mistral-vibe && vibe --setup, yarn daemon:restart, browsentic agent vibe, then one instruction and a follow-up in the same conversation — that exercises the config trust, the by-name grants and the replay skip in one go.
yarn check is green locallyyarn daemon:manifest run, and docs/reference/tools.md in step — not touchedfeat(actions): …, fix(daemon): …)
Ticket changed by: imshaikot