Multica runtime identity: the daemon.id hijack
Applies to: Any Multica crew host where ~/.multica/daemon.id may have been copied or shared from another machine.
Multica keys a runtime's identity on the contents of ~/.multica/daemon.id, not on the hostname. Two machines carrying the same daemon.id are a single runtime record to the server, and the last daemon to start silently claims it — rewriting the record's name/device_info and receiving all agent work dispatched to it. No conflict error, no warning, no log line on either side.
The incident (2026-08-02, OBJ-2049 and five others)
Both Objectuve-Pro (a second Mac) and joshuas-mbp-2.lan (the real crew runtime) carried the identical daemon.id 019db58e-51f8-7dcb-b9e7-580bdabd4636 — the file was dated Apr 22 on both, i.e. ~/.multica/ had at some point been copied wholesale between the machines. All 12 Objectuve agents bind to runtime bf3c31e7-4a7e-452d-98c7-d0e88beda4dd, whose bound daemon_id field holds that same value.
| Time (UTC) | Event |
|---|---|
| 10:33 | A daemon restart on Objectuve-Pro claims bf3c31e7, renaming it Claude (Objectuve-Pro.local) · 2.1.173 |
| 10:39:54 | First 401 OAuth access token has been revoked — crew work is now landing on a laptop whose claude CLI login expired 2026-05-25 |
| 10:39 → 16:09 | 20 × 401 across 10 distinct tasks, all failure_reason=agent_error.provider_auth_or_access |
| 16:22:50 | A daemon restart on joshuas-mbp-2.lan flips the record back to Claude (joshuas-mbp-2.lan) · 2.1.220 |
| 16:27 → 16:29 | Rerun of OBJ-2049 completes cleanly — fix confirmed |
Six issues took collateral damage: OBJ-2049, OBJ-1982, OBJ-2058, OBJ-2057, OBJ-1997, OBJ-1993 (plus OBJ-2044, already blocked for unrelated reasons).
The name drift is itself the tell. multica-github-auth.md records this runtime as Claude (Joshuas-MacBook-Pro-2.local); it now reads Claude (joshuas-mbp-2.lan). A runtime whose displayed name changes without anyone renaming anything has been re-registered by a different daemon.
Why the obvious diagnosis is the wrong one
The 401 wording says revoked, which reads like a credential problem, and there genuinely was one: Objectuve-Pro's Claude Code login had been dead for months. Two further real-but-downstream details make the credential story even more convincing:
- Claude Code session env inheritance (
CLAUDE_CODE_HOST_SESSION_ID,CLAUDE_CODE_SDK_HAS_HOST_AUTH_REFRESH,ANTHROPIC_BASE_URL, …) turns what would otherwise surface as "Not logged in · Please run /login" into "revoked" when the daemon was started from inside a Claude Code session. - The runtime heartbeats normally throughout.
last_seenstays current, status staysonline. Heartbeat is not auth — a runtime can be perfectly healthy at the transport layer and fail every single agent run.
None of it would have mattered if the runtime hadn't been hijacked. Check runtime ownership before debugging credentials — otherwise you re-login a machine that was never supposed to be serving the work.
Diagnosis
One command settles it. Compare the local file against the runtime the agents are bound to:
cat ~/.multica/daemon.id
multica agent list --output json | jq -r '.[].runtime_id' | sort -u
multica runtime list --output json | jq -r '.[] | "\(.id) \(.daemon_id) \(.name)"'If the local daemon.id equals the daemon_id of a runtime you did not intend this machine to own, you have a hijack (or are one restart away from one). A null daemon_id on some other runtime in the list is expected and benign — it just means that runtime has no daemon bound to it yet, not a second incident.
To prove which machine actually owns which runtime, stop the local daemon and re-list. Runtimes that stay online belong to the other machine; ones that flip offline were genuinely local:
multica daemon stop
multica runtime listApplied here, that A/B was run from Objectuve-Pro — the machine that should not have owned the runtime — and was unambiguous:
| Runtime | Before stop | After stop | Verdict |
|---|---|---|---|
bf3c31e7 Claude | online | online | joshuas-mbp-2.lan's — was hijacked |
18e011d1 Opencode | online | online | joshuas-mbp-2.lan's — never hijacked, confirms baseline ownership |
8c621a62 Hermes | online | offline | genuinely local |
3e5130d2 Gemini | online | offline | genuinely local |
Supporting evidence lives in ~/.multica/daemon.log (the 401s and their failure_reason) and ~/.multica/daemon.pid (mtime = the hijacking restart). Note that ~/.multica/config.json holds only app_url / server_url / token / workspace_id — no identity key. Identity is daemon.id alone.
Fix
On the machine that should not own the runtime, stop the daemon and retire the duplicated identity file so a future start registers fresh instead of hijacking:
multica daemon stop
mv ~/.multica/daemon.id ~/.multica/daemon.id.disabled-dupeThen rerun the affected issues from any machine:
multica issue rerun <issue-id>A subsequent multica daemon start on that machine now registers a new, unbound runtime. That runtime will sit idle — correct and intended, since no agent is bound to it. Do not "fix" the idleness by restoring the old daemon.id.
multica --profile <name> … isolates config and daemon state per profile and is the cleaner option if a machine legitimately needs to run a second daemon.
Prevention
- Never copy
~/.multica/between machines. Copyconfig.jsonalone if you need to carry credentials over, and let each machine generate its owndaemon.idon first start. - Before starting a daemon on a machine that hasn't run one recently, check
cat ~/.multica/daemon.idagainst the bound runtime first. - Treat a runtime name change as an incident signal, not cosmetic drift.
- Confirming a fix requires a completed run, not a green
last_seen. Usemultica issue runs <issue-id>and look for acompletedrow.
Open gap
Nothing detects this automatically. There is still no alerting on consecutive agent-run failures or on runner login health — the same gap flagged after the 2026-06-30 → 07-03 outage (~3 days unnoticed, 401 Invalid authentication credentials, terminal variant "Not logged in · Please run /login"). This incident ran ~6 hours before a human noticed a stalled issue. A crew-side check that fires on N consecutive agent_error.provider_auth_or_access failures, or a server-side conflict warning when a daemon.id re-registers from a different device_info, would have caught both.
Related
multica-github-auth.md— documents the single-shared-runtime model this incident exploits../guides/multica-agent-crew.md— the crew runbook this runtime backsmultica-shared-runtime-quota-gotcha.md— same runtime, a different failure class: the shared Claude account's own session/weekly quota running out, not the runtime record being claimed by a different machine
Last updated: 2026-08-03