mirror of
https://github.com/multica-ai/multica.git
synced 2026-08-12 19:06:06 +02:00
Adds DevEco Code (Huawei's HarmonyOS coding agent, built on the OpenCode engine) as a first-class runtime provider: backend/model parser, daemon discovery (probe + login-shell list + Windows .cmd native resolver), runtime profile migration (protocol_family whitelist), provider UI, metrics, and four-language docs. MCP injection is deferred (UI gates it off). Migration numbered 175.
193 lines
10 KiB
Plaintext
193 lines
10 KiB
Plaintext
---
|
||
title: Daemon and runtimes
|
||
description: Agents don't run on Multica's servers — they run on your own machines.
|
||
---
|
||
|
||
import { Callout } from "fumadocs-ui/components/callout";
|
||
import { Mermaid } from "@/components/mermaid";
|
||
|
||
In Multica, [agents](/agents) do **not** run on our servers — they run on your own machines, driven by a small program called the **daemon** that invokes the [AI coding tools](/providers) installed locally. The Multica server only coordinates: it stores [issues](/issues), queues [tasks](/tasks), and dispatches them to the right **runtime** (runtime = daemon × one AI coding tool).
|
||
|
||
This structure is the biggest difference between Multica and Linear / Jira: **your API keys, toolchain, and code directories stay on your machine** — the Multica server never sees any of them. That means "my agent isn't working" is almost always a local problem — the daemon isn't running, an AI tool isn't installed, a key has expired. Check locally first; see [Troubleshooting](/troubleshooting) for a guide.
|
||
|
||
## Starting the daemon
|
||
|
||
The daemon is part of the Multica CLI. Once you've installed the [Multica CLI](/cli), run on your own machine:
|
||
|
||
```bash
|
||
multica daemon start
|
||
```
|
||
|
||
On startup it does four things:
|
||
|
||
1. Reads the credentials saved when you logged in
|
||
2. Detects AI coding tools installed on your `PATH` (15 built-in: [Antigravity](/providers#antigravity), [Claude Code](/providers#claude-code), [CodeBuddy](/providers#codebuddy), [Codex](/providers#codex), [Cursor](/providers#cursor), [Copilot](/providers#copilot), [Hermes](/providers#hermes), [Kimi](/providers#kimi), [Kiro CLI](/providers#kiro-cli), [OpenCode](/providers#opencode), [OpenClaw](/providers#openclaw), [Pi](/providers#pi), [Qoder](/providers#qoder), [Trae CLI](/providers#trae), [DevEco Code](/providers#deveco-code))
|
||
3. Registers itself with the server, along with a runtime for each detected tool
|
||
4. Keeps **polling every 3 seconds** for tasks to pick up, and **sends a heartbeat every 15 seconds**
|
||
|
||
Common commands:
|
||
|
||
| Command | Purpose |
|
||
|---|---|
|
||
| `multica daemon start` | Start (background by default; add `--foreground` to run in the foreground) |
|
||
| `multica daemon stop` | Stop |
|
||
| `multica daemon restart` | Restart |
|
||
| `multica daemon status` | Show status |
|
||
| `multica daemon logs` | Show logs (add `-f` to follow) |
|
||
|
||
Full CLI reference in [CLI commands](/cli).
|
||
|
||
**The desktop app ships with a daemon.** If you use the [desktop app](/desktop-app), you don't need to run `multica daemon start` manually — it launches the daemon automatically on startup. See the [Desktop app](/desktop-app) page for which option fits your workflow.
|
||
|
||
## Why one machine has multiple runtimes
|
||
|
||
A runtime is not a server and not a container — it's the combination of "**daemon × one AI coding tool**". For example: you start the daemon on a MacBook with both Claude Code and Codex installed, and you're a member of two workspaces. Multica then registers 4 runtimes:
|
||
|
||
<Mermaid chart={`
|
||
graph TD
|
||
D["Your daemon<br/>MacBook"]
|
||
D --> R1["Runtime<br/>Workspace A × Claude Code"]
|
||
D --> R2["Runtime<br/>Workspace A × Codex"]
|
||
D --> R3["Runtime<br/>Workspace B × Claude Code"]
|
||
D --> R4["Runtime<br/>Workspace B × Codex"]
|
||
`} />
|
||
|
||
Key points:
|
||
|
||
- **One daemon can map to multiple runtimes** — one per combination of installed tool and workspace you belong to
|
||
- **The same daemon, workspace, and tool produces exactly one runtime** — restarting the daemon never creates duplicate records
|
||
- The **Runtimes** page in the Multica UI lists these rows
|
||
|
||
## Custom runtime profiles
|
||
|
||
Built-in provider detection covers the common tools, but teams can also define
|
||
**custom runtime profiles** for AI CLIs that speak one of Multica's supported
|
||
protocol families and need a different launch command. Typical examples include
|
||
an internal wrapper around Codex, a version-pinned executable, or a team CLI
|
||
that adds fixed model arguments.
|
||
|
||
Do not create a custom profile just to use Claude Code, Codex, Kimi, or another
|
||
built-in provider with its normal command. The daemon detects those tools
|
||
automatically.
|
||
|
||
### Before you create one
|
||
|
||
- Install the custom command on at least one machine running a Multica daemon,
|
||
and confirm the same command works in that machine's terminal.
|
||
- Confirm the tool speaks one of the base protocol families shown in the UI.
|
||
Choosing a family tells Multica how to communicate with the process; it does
|
||
not make an incompatible CLI compatible.
|
||
- You must be a workspace owner or admin to create, edit, or delete a profile.
|
||
|
||
### Create one from the Runtimes UI
|
||
|
||
1. Open **Runtimes**, then select the machine where you installed the command.
|
||
2. Select **Add custom runtime**.
|
||
3. Choose the base protocol family implemented by the command.
|
||
4. Enter a display name and the command you would run in a terminal, including
|
||
any fixed arguments. Add an optional description so teammates know what it
|
||
is for.
|
||
5. Select **Create runtime**.
|
||
|
||
The profile definition belongs to the whole workspace and syncs to every
|
||
connected daemon. Each machine registers its own runtime only when it can
|
||
resolve that command. The machine where you started the flow shows a temporary
|
||
**Registering** row while it waits. If the row does not become online, check
|
||
that the command is installed and available to the daemon on that machine.
|
||
|
||
Creating a profile does not install the CLI, authenticate it, or copy it to
|
||
other machines. Install and sign in to the underlying tool separately on every
|
||
machine that should provide this runtime.
|
||
|
||
### Manage profiles from the CLI
|
||
|
||
The same workspace profiles can be managed from the CLI:
|
||
|
||
```bash
|
||
multica runtime profile list
|
||
multica runtime profile create --display-name "Composer" --protocol-family codex --command-name agent
|
||
multica runtime profile update <profile-id> --command-name agent
|
||
multica runtime profile delete <profile-id>
|
||
```
|
||
|
||
Custom and built-in runtimes share the same machine list. Use a custom runtime
|
||
row's actions menu to edit or delete its profile. Deleting a profile removes its
|
||
registered runtime instances after the daemons synchronize; it can be blocked
|
||
while agents still depend on it.
|
||
|
||
The command is argv-oriented, not a shell string. Multica stores an executable
|
||
name plus fixed arguments, then the daemon launches it directly with
|
||
`exec.Command(command_name, fixed_args...)`. Plain arguments, quotes, and
|
||
backslash escaping are supported; pipes, redirects, `&&`, `;`, backticks, and
|
||
`$VAR` / `$(...)` expansion are not. Use a wrapper script when the runtime needs
|
||
shell behavior. Today the Runtimes UI owns command-and-argument parsing; the CLI
|
||
profile commands manage the profile row and local path overrides.
|
||
|
||
If a desktop-launched daemon cannot find a command that works in your terminal,
|
||
pin the absolute path on that machine:
|
||
|
||
```bash
|
||
multica runtime profile set-path <profile-id> --path /abs/path/to/agent
|
||
multica runtime profile unset-path <profile-id>
|
||
```
|
||
|
||
Profile command or argument edits apply to newly claimed tasks after the daemon
|
||
re-registers. Running tasks keep the launch arguments they started with. For
|
||
mixed deployments, upgrade the server before rolling out newer daemons: the
|
||
server-side Runtimes UI stores `fixed_args`, and the server is what surfaces
|
||
`failed_profiles` registration reports. Older components may ignore fields they
|
||
do not understand instead of failing loudly, so treating the server upgrade as
|
||
the first step keeps the rollout observable.
|
||
|
||
<Callout type="info">
|
||
**Cloud runtimes are coming**, currently in a waitlist phase. Once available, you'll be able to execute agent tasks directly on Multica Cloud without running a local daemon. Sign up with your email on the [download page](https://multica.ai/download) to get notified.
|
||
</Callout>
|
||
|
||
## When a runtime is marked offline
|
||
|
||
Multica uses heartbeats to decide whether a runtime is online. Three key numbers:
|
||
|
||
| Event | Threshold |
|
||
|---|---|
|
||
| Daemon heartbeat frequency | Every **15 seconds** |
|
||
| Marked as missing | No heartbeat for **45 seconds** (3 missed beats) |
|
||
| Auto-deleted | Missing with no associated agents for over **7 days** |
|
||
|
||
Missing is not permanent — as soon as the daemon sends another heartbeat it returns to online, and the runtime record is preserved. Restarting the daemon does not lose runtimes.
|
||
|
||
<Callout type="warning">
|
||
**Tasks running on a missing runtime are marked as failed** (failure reason `runtime_offline`). For retryable sources (issues, chat), Multica automatically requeues them; Autopilot-triggered tasks are not retried automatically. See [Tasks → Which failures retry automatically](/tasks#which-failures-retry-automatically-which-dont).
|
||
</Callout>
|
||
|
||
## How many tasks can run in parallel
|
||
|
||
Multica enforces concurrency limits at two layers:
|
||
|
||
- **Daemon layer**: **20 concurrent tasks** by default (tunable via env var `MULTICA_DAEMON_MAX_CONCURRENT_TASKS`)
|
||
- **Agent layer**: **6 concurrent tasks per agent** by default (configured per-agent)
|
||
|
||
The tighter of the two wins. If your daemon is already running 20 tasks, new tasks wait even if an agent still has headroom.
|
||
|
||
If you see tasks stuck in `queued` without moving to `dispatched`, one of these two limits is usually saturated.
|
||
|
||
## What happens to in-flight tasks after a daemon crash
|
||
|
||
When the daemon crashes or is force-killed, the tasks it had picked up are left in `dispatched` or `running`. On the next start, the daemon tells the server: "these tasks are no longer mine, please mark them failed." The server flips them to `failed` with reason `runtime_recovery` — for retryable sources, the tasks are automatically requeued.
|
||
|
||
Even if this step fails due to a network issue, there's a server-side scan **every 30 seconds** as a backstop: any runtime without a heartbeat for over 45 seconds is marked missing, and its tasks are reclaimed along with it.
|
||
|
||
## Troubleshooting agents that aren't working
|
||
|
||
When you hit a "my agent isn't working" problem, run this three-step checklist first:
|
||
|
||
1. Run `multica daemon status` — confirm the daemon is running and online
|
||
2. Run `multica daemon logs -f` — check for errors
|
||
3. Open the **Runtimes** page in the Multica UI — confirm your runtime shows "online"
|
||
|
||
More scenarios in [Troubleshooting](/troubleshooting).
|
||
|
||
## Next
|
||
|
||
- [Tasks](/tasks) — the full lifecycle of a task once the daemon picks it up
|
||
- [Providers Matrix](/providers) — capability differences across the 15 AI coding tools
|