* feat(agent): add custom CLI arguments support
Allow users to configure custom CLI arguments per agent that get
appended to the agent subprocess command at launch time. This enables
use cases like specifying different models (--model o3), max turns,
or other provider-specific flags without needing separate runtimes.
Changes:
- Add custom_args JSONB column to agent table (migration 041)
- Update API handler to accept/return custom_args in create/update
- Pass custom_args through claim endpoint to daemon
- Append custom_args to CLI commands for all agent backends
- Add ExecOptions.CustomArgs field in agent package
- Add Custom Args tab in agent detail UI
- Add --custom-args flag to CLI agent create/update commands
Closes MUL-802
* fix(agent): filter protocol-critical flags from custom_args
Add per-backend filtering of custom_args to prevent users from
accidentally overriding flags that the daemon hardcodes for its
communication protocol (e.g. --output-format, --input-format,
--permission-mode for Claude).
This follows the same pattern as custom_env's isBlockedEnvKey: we
only block the small, stable set of flags that would break the
daemon↔agent protocol — not every possible dangerous flag. Workspace
members are trusted for everything else.
Each backend defines its own blocked set:
- Claude: -p, --output-format, --input-format, --permission-mode
- Gemini: -p, --yolo, -o
- Codex: --listen
- OpenCode: --format
- OpenClaw: --local, --json, --session-id, --message
- Hermes: none (ACP is positional)
Includes unit tests for the filtering logic.
* fix(agent): address code review nits for custom_args
- Replace module-level `nextArgId` counter with `crypto.randomUUID()`
in custom-args-tab.tsx to avoid SSR ID conflicts
- Add unit tests for custom args passthrough and blocked-arg filtering
in both Claude and Gemini arg builders
Switch Gemini backend from `-o text` (batch output) to `-o stream-json`
(NDJSON streaming) so tool calls, text, and errors are forwarded to the
UI in real time instead of collected at the end.
Parses all Gemini stream-json event types: init, message, tool_use,
tool_result, error, and result — including per-model token usage from
the result stats.
Registers `gemini` as a sixth supported agent provider alongside claude,
codex, opencode, openclaw, and hermes.
- Daemon config probes for `gemini` on PATH (MULTICA_GEMINI_PATH /
MULTICA_GEMINI_MODEL env overrides mirror the other providers).
- New agent.geminiBackend in pkg/agent/gemini.go: spawns
`gemini -p <prompt> --yolo -o text [-m <model>] [-r <session>]`,
reads stdout to completion, and returns a single MessageText plus
the standard Result struct (Status / Output / DurationMs).
- Execution environment writes a GEMINI.md file into the task workdir
(mirroring the existing CLAUDE.md / AGENTS.md injection for other
providers) so Gemini discovers the Multica runtime meta-skill
through its native mechanism.
Tests:
- pkg/agent/gemini_test.go — unit coverage for buildGeminiArgs
(baseline, model override, resume session, omit-when-empty).
- internal/daemon/execenv/TestInjectRuntimeConfigGemini — verifies
GEMINI.md is written and that CLAUDE.md/AGENTS.md are NOT.
Scope (intentional for v1):
- Text output only (`-o text`). Streaming tool events via
`--output-format stream-json` is a follow-up once we have a
reliable reproduction of Gemini's event schema.
- No MCP config plumbing. Gemini's `--allowed-mcp-server-names`
filter pairs well with the per-agent MCP work on feat/per-agent-mcp;
stacking the two can land as a follow-up.
- No token usage scraping (Gemini's accounting lives on the Google
Cloud side, not a local JSONL log like claude/codex).
- No session resume wiring beyond accepting the ExecOptions field —
the daemon does not yet persist Gemini session IDs because the text
output mode does not expose them.
Migration / env changes:
- New optional environment variables MULTICA_GEMINI_PATH and
MULTICA_GEMINI_MODEL. Default path is the string "gemini" (resolved
via PATH at daemon startup). If no Gemini install is detected, the
provider is simply absent from the runtime — no behavior change for
existing deployments.