* feat(agent): add Kimi CLI as agent runtime Adds support for Moonshot AI's Kimi Code CLI (https://github.com/MoonshotAI/kimi-cli) as a new agent runtime, alongside Claude, Codex, OpenCode, OpenClaw, Hermes, Gemini, Pi, Cursor and Copilot. Kimi Code CLI implements the standard Agent Client Protocol (ACP) via the `kimi acp` subcommand, so the new `kimiBackend` reuses the existing hermesClient JSON-RPC transport in the agent package — only the binary, client identity, log prefix, and tool-name extraction differ. Wiring: - server/pkg/agent: new kimiBackend + kimi_test.go; registered in New(), LaunchHeader map, and the supported-types coverage test. - server/internal/daemon/config.go: probes `kimi` (overridable via MULTICA_KIMI_PATH / MULTICA_KIMI_MODEL). - server/internal/daemon/execenv: writes AGENTS.md as the runtime context file (Kimi reads AGENTS.md natively via /init), and writes skills under `.kimi/skills/` so they are auto-discovered by the project-level skill loader. - packages/views/runtimes: ProviderLogo gains a Kimi mark. Co-authored-by: Copilot <[email protected]> * feat(agent/kimi): support per-agent model selection via ACP set_model Wire Kimi into the model dropdown introduced in #1399: - ListModels gets a 'kimi' case that drives the same ACP initialize + session/new handshake as Hermes; both share a new discoverACPModels helper and parseACPSessionNewModels parser so future ACP backends only need a small provider entry. - kimiBackend now issues session/set_model after session/new when opts.Model is non-empty, mirroring the Hermes flow. Failures fail the task instead of silently falling back to Kimi's default model — silent fallback would hide that the dropdown pick wasn't honoured. Verified: go build ./..., go test ./pkg/agent/... ./internal/daemon/... ./internal/handler/..., pnpm typecheck and pnpm test (138 passed). Co-authored-by: Copilot <[email protected]> * refactor(agent): address code review feedback on Kimi runtime - Share ACP provider-error sniffer between hermes and kimi. Previously only hermes promoted stderr-observed 4xx/5xx into a failed task; kimi would report "completed + empty output" when the Moonshot upstream rejected a request (expired token, rate limit, …). Rename hermesProviderErrorSniffer → acpProviderErrorSniffer and parameterise the provider name; wire it into kimiBackend.Execute the same way. - Rename extractHermesSessionID → extractACPSessionID (shared by all ACP backends) so the name matches parseACPSessionNewModels. - Drop the redundant second argument to kimiToolNameFromTitle; the Message struct has only one relevant field (Tool), so passing it twice was a dead fallback. Document that the function normalises residual capitalised kimi titles not caught by hermesToolNameFromTitle. - Remove kimi-only cmd.WaitDelay override; the hermes baseline is fine for both and divergence adds noise. - Add TestKimiBackendSetModelFailureFailsTask: fake `kimi acp` binary that returns a JSON-RPC error for session/set_model, asserts that the task result surfaces status=failed with the model name + upstream message and preserves the session id. - Fix stale agent listings in agent.go / daemon/config.go doc comments (missing cursor, gemini, copilot). All: `go build ./...`, `go vet ./...`, `go test ./pkg/agent/... ./internal/daemon/... ./internal/handler/...` green. * fix(agent/kimi): pass --yolo so Shell tools don't hang on approval Kimi's default config has `default_yolo = false`. Every Shell/file-mutating tool call causes kimi acp to send a `session/request_permission` request and block (up to 300s) waiting for a response. The daemon's hermesClient only handles `session/update` notifications — permission requests go unanswered, the tool call times out, and the UI loop eventually dies ("UI loop timed out"). Observed with the first real kimi task: agent sat as Live for ~7 minutes before the daemon killed it. The fix mirrors hermes' HERMES_YOLO_MODE=1 override: pass `--yolo` to `kimi` so it auto-approves everything. `--yolo` is a top-level flag on the `kimi` CLI (not a flag on `kimi acp`), so it must come before the `acp` subcommand in argv. Added to kimiBlockedArgs so user custom_args can't strip it. While here, fix a related bug that made kimi tool names show up empty in the daemon log ("tool #1: "): hermesToolNameFromTitle's fallback returned `kind` when neither title-with-colon nor kind matched a known tool. Kimi's ACP `tool_call` emits bare titles like "Shell" or "Read file" with no `kind` at all, so we'd drop the title on the floor before kimiToolNameFromTitle ever got a chance to map it. Now: preserve the title when kind is unclassified; hermes titles always carry a colon so this branch never fires for hermes. Tests: - TestKimiBackendPassesYoloFlag — fake binary that records its argv, asserts --yolo comes before acp. - TestHermesToolNameFromTitle rows for bare kimi-style titles. - Existing suite green: go build, go vet, full pkg/agent + daemon + handler test packages. * fix(agent/acp): auto-approve session/request_permission from agent The previous attempt (`kimi --yolo acp`) was a no-op. Inspected the kimi-cli source: the `acp` Typer subcommand takes no parameters, so flags on the root `kimi` command are dropped before `acp_main()` runs — it's impossible to opt into YOLO mode through CLI flags for ACP. The real fix is on our side: respond to session/request_permission. ACP is bidirectional. When kimi runs a Shell or file-write tool, it sends `session/request_permission` (agent → client, JSON-RPC request with id + method) and waits up to 300s for a response. Our existing hermesClient.handleLine only dispatched: (id + result/error) → handleResponse, and (no id + method) → handleNotification. A request with BOTH id and method fell through and got silently dropped — kimi timed out, UI loop died, task sat stuck for 7 minutes. Add handleAgentRequest: for session/request_permission, echo the id and respond with outcome=selected, optionId=approve_for_session. The daemon is headless; there's no user to prompt. `approve_for_session` lets the agent remember the action so subsequent identical calls (every Shell, every file write) skip the round-trip entirely. For any other agent → client method, reply with standard -32601 method-not- found so the agent doesn't block. Also: - Add writeMu so request() (main goroutine) and handleAgentRequest (reader goroutine) don't interleave JSON frames on stdin. - Revert the `--yolo acp` flag — it's a no-op, and carrying it in kimiBlockedArgs gives the wrong impression that it does something. Comment in kimi.go now points at handleAgentRequest as the real fix. Tests: - TestHermesClientAutoApprovesPermissionRequest: inject a session/request_permission, assert the reply echoes the id and carries {outcome: selected, optionId: approve_for_session}. - TestHermesClientReplesMethodNotFoundForUnknownAgentRequest: confirm unknown agent → client methods get JSON-RPC -32601 instead of silence. - TestKimiBackendInvokesACPSubcommand replaces the yolo-flag assertion with a negative assertion: no dead --yolo / --auto-approve / -y on argv, since they'd pretend to do something they can't. All: go build ./..., go vet ./..., go test ./pkg/agent/... green. * fix(agent/acp): surface kimi tool input/output via content blocks Kimi-cli emits tool_call and tool_call_update ACP frames with the input/output inside a `content` array of ContentToolCallContent blocks (shape: {type:"content", content:{type:"text", text:"..."}}), not in the hermes-style `rawInput` map / `rawOutput` string. Our parser only looked at rawInput/rawOutput, so the daemon recorded empty Input and Output for every kimi tool — the execution-history UI showed blank terminal panels even for commands that ran fine. Add extractACPToolCallText() and a fallback in handleToolCallStart / handleToolCallUpdate: when rawInput is nil / rawOutput is empty, pull the text out of the content blocks. rawInput / rawOutput still take precedence so hermes' behaviour is untouched. Terminal / FileEditToolCallContent blocks are skipped (we have nothing to render them as — kimi only emits TerminalToolCallContent when the client advertises terminal capability, which we don't). Tests: - TestHermesClientHandleToolCallStartKimiContent — content array → Input.text populated. - TestHermesClientHandleToolCallCompleteKimiContent — multi-block content → Output concatenated with newline separator. - TestHermesClientHandleToolCallRawOutputTakesPrecedence — hermes rawOutput still wins when both are present. - TestExtractACPToolCallText — unit coverage for the helper (single/multiple text blocks, terminal-block skip, empty input). * fix(agent/acp): buffer streaming tool args so Input isn't empty in UI kimi-cli streams tool args token-by-token via tool_call_update frames — the initial tool_call carries an empty content block and each subsequent in_progress update carries the cumulative JSON so far (`{`, `{"comma`, `{"command": "echo`, …). The final completed update then carries the tool's stdout, not the args. Observed per kimi-cli acp/session.py::_send_tool_call{,_part,_result} and confirmed by driving a real Shell call end-to-end: 10 in_progress frames, last with `{"command": "echo hello world"}`, then completed with `hello world\n`. Our previous handleToolCallStart emitted MessageToolUse on the first tool_call frame, capturing the empty content — so every kimi tool appeared in the execution-history UI with a blank input. Output was correct (fix 4335c198) but command was missing. Changes: - hermesClient now tracks pending tool calls per toolCallId. Hermes path is unchanged — rawInput is present at tool_call time, so emit-immediately-then-flag-emitted still fires on the initial frame. - kimi path defers MessageToolUse until status=completed / failed. tool_call_update in_progress frames update the buffered argsText (cumulative, so overwrite); on completion we parse the accumulated JSON into Message.Input. Malformed JSON falls back to `{"text": …}` so non-JSON tool args still render. - Orphan completion frames (no matching tool_call seen — e.g. daemon restarted mid-task) synthesise ToolUse from the update's own title/kind/rawInput so the UI still gets a header. - extractACPToolCallText now also renders FileEditToolCallContent blocks as a compact header ("--- path / +++ path / (edited: N → M bytes)"). kimi emits these for Write / StrReplaceFile / Patch when the tool's display block is a DiffDisplayBlock. Tests: - TestHermesClientKimiStreamingToolCall: empty tool_call + 5 streaming in_progress + completed. Asserts no emission until complete, then [ToolUse(Input.command="echo hi"), ToolResult(Output="hi\n")]. - TestHermesClientKimiMalformedArgsFallback: non-JSON argsText → falls back to Input.text. - TestHermesClientHandleToolCallCompleteOrphan: completed frame without a start → ToolUse synthesised from update's rawInput. - TestExtractACPToolCallText: diff + new-file-diff cases. All agent / daemon / handler test packages green. --------- Co-authored-by: Eve <[email protected]> Co-authored-by: Copilot <[email protected]> Co-authored-by: Eve <[email protected]> Co-authored-by: Lambda <[email protected]>
Multica
Your next 10 hires won't be human.
The open-source managed agents platform.
Turn coding agents into real teammates — assign tasks, track progress, compound skills.
Website · Cloud · X · Self-Hosting · Contributing
English | 简体中文
What is Multica?
Multica turns coding agents into real teammates. Assign issues to an agent like you'd assign to a colleague — they'll pick up the work, write code, report blockers, and update statuses autonomously.
No more copy-pasting prompts. No more babysitting runs. Your agents show up on the board, participate in conversations, and compound reusable skills over time. Think of it as open-source infrastructure for managed agents — vendor-neutral, self-hosted, and designed for human + AI teams. Works with Claude Code, Codex, OpenClaw, OpenCode, Hermes, Gemini, Pi, and Cursor Agent.
Features
Multica manages the full agent lifecycle: from task assignment to execution monitoring to skill reuse.
- Agents as Teammates — assign to an agent like you'd assign to a colleague. They have profiles, show up on the board, post comments, create issues, and report blockers proactively.
- Autonomous Execution — set it and forget it. Full task lifecycle management (enqueue, claim, start, complete/fail) with real-time progress streaming via WebSocket.
- Reusable Skills — every solution becomes a reusable skill for the whole team. Deployments, migrations, code reviews — skills compound your team's capabilities over time.
- Unified Runtimes — one dashboard for all your compute. Local daemons and cloud runtimes, auto-detection of available CLIs, real-time monitoring.
- Multi-Workspace — organize work across teams with workspace-level isolation. Each workspace has its own agents, issues, and settings.
Quick Install
macOS / Linux (Homebrew - recommended)
brew install multica-ai/tap/multica
Use brew upgrade multica-ai/tap/multica to keep the CLI current.
macOS / Linux (install script)
curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash
Use this if Homebrew is not available. The script installs the Multica CLI on macOS and Linux by using Homebrew when it is on PATH, otherwise it downloads the binary directly.
Windows (PowerShell)
irm https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.ps1 | iex
Then configure, authenticate, and start the daemon in one command:
multica setup # Connect to Multica Cloud, log in, start daemon
Self-hosting? Add
--with-serverto deploy a full Multica server on your machine:curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash -s -- --with-server multica setup self-hostRequires Docker. See the Self-Hosting Guide for details.
Getting Started
1. Set up and start the daemon
multica setup # Configure, authenticate, and start the daemon
The daemon runs in the background and auto-detects agent CLIs (claude, codex, openclaw, opencode, hermes, gemini, pi, cursor-agent) on your PATH.
2. Verify your runtime
Open your workspace in the Multica web app. Navigate to Settings → Runtimes — you should see your machine listed as an active Runtime.
What is a Runtime? A Runtime is a compute environment that can execute agent tasks. It can be your local machine (via the daemon) or a cloud instance. Each runtime reports which agent CLIs are available, so Multica knows where to route work.
3. Create an agent
Go to Settings → Agents and click New Agent. Pick the runtime you just connected and choose a provider (Claude Code, Codex, OpenClaw, OpenCode, Hermes, Gemini, Pi, or Cursor Agent). Give your agent a name — this is how it will appear on the board, in comments, and in assignments.
4. Assign your first task
Create an issue from the board (or via multica issue create), then assign it to your new agent. The agent will automatically pick up the task, execute it on your runtime, and report progress — just like a human teammate.
Multica vs Paperclip
| Multica | Paperclip | |
|---|---|---|
| Focus | Team AI agent collaboration platform | Solo AI agent company simulator |
| User model | Multi-user teams with roles & permissions | Single board operator |
| Agent interaction | Issues + Chat conversations | Issues + Heartbeat |
| Deployment | Cloud-first | Local-first |
| Management depth | Lightweight (Issues / Projects / Labels) | Heavy governance (Org chart / Approvals / Budgets) |
| Extensibility | Skills system | Skills + Plugin system |
TL;DR — Multica is built for teams that want to collaborate with AI agents on real projects together.
CLI
The multica CLI connects your local machine to Multica — authenticate, manage workspaces, and run the agent daemon.
| Command | Description |
|---|---|
multica login |
Authenticate (opens browser) |
multica daemon start |
Start the local agent runtime |
multica daemon status |
Check daemon status |
multica setup |
One-command setup for Multica Cloud (configure + login + start daemon) |
multica setup self-host |
Same, but for self-hosted deployments |
multica issue list |
List issues in your workspace |
multica issue create |
Create a new issue |
multica update |
Update to the latest version |
See the CLI and Daemon Guide for the full command reference.
Architecture
┌──────────────┐ ┌──────────────┐ ┌──────────────────┐
│ Next.js │────>│ Go Backend │────>│ PostgreSQL │
│ Frontend │<────│ (Chi + WS) │<────│ (pgvector) │
└──────────────┘ └──────┬───────┘ └──────────────────┘
│
┌──────┴───────┐
│ Agent Daemon │ runs on your machine
└──────────────┘ (Claude Code, Codex, OpenCode,
OpenClaw, Hermes, Gemini,
Pi, Cursor Agent)
| Layer | Stack |
|---|---|
| Frontend | Next.js 16 (App Router) |
| Backend | Go (Chi router, sqlc, gorilla/websocket) |
| Database | PostgreSQL 17 with pgvector |
| Agent Runtime | Local daemon executing Claude Code, Codex, OpenClaw, OpenCode, Hermes, Gemini, Pi, or Cursor Agent |
Development
For contributors working on the Multica codebase, see the Contributing Guide.
Prerequisites: Node.js v20+, pnpm v10.28+, Go v1.26+, Docker
make dev
make dev auto-detects your environment (main checkout or worktree), creates the env file, installs dependencies, sets up the database, runs migrations, and starts all services.
See CONTRIBUTING.md for the full development workflow, worktree support, testing, and troubleshooting.

