SDK: spawn-and-connect (singleton daemon) mode for Node clients
@kantord is already working on this.
Since Sep 10, 2026.
- Dominant language
- Go
- Stars
- 152
- Forks
- 16
- Avg merge
- 14h 48m
- Merged PRs (30d)
- 536
Description
Parent
Sub-issue of #821 (which is the implementation plan for epic #761).
Problem
spawn() and connect() cover two ends of a spectrum: a private, ephemeral, per-process daemon (spawn(), auto-exits via the lifetime pipe when its owning process dies) versus attaching to an already-known, externally-managed daemon (connect()). Neither covers a common third case for CLI-style Node clients: several independent process launches that want to share one daemon and its live sessions, without the caller having to stand up and manage that daemon as a separate long-running service themselves.
Motivating case
mecavim (a minimal Neovim client for mecated, an internal prototype) currently calls spawn({}) on every launch. Each launch gets a brand-new private daemon with in-memory-only session state. This makes --resume/--resume-latest (session picked via sessions.get(id) / sessions.list()) structurally unable to find anything from a previous launch: the daemon that held that session already exited (by design — that's what the lifetime pipe is for) before the next launch starts. Adding --store-dir would let a session survive on disk and be reconstructed via session.activity(), but the AI's live conversational state — and any true "reconnect to exactly where I left off" experience — is gone the moment that private daemon exits.
The fix needs a daemon that outlives any single launch, addressable by subsequent launches, without the client having to build its own "is one already running, else start one" lifecycle logic (locking, idle shutdown, etc.) — that's the same complexity spawn() already exists to hide for the private-daemon case.
Proposal
A third node-only entry point (name TBD — spawnAndConnect(), ensure(), something in that family) that:
- Tries to
connect()to a daemon at a well-known, stable address (notspawn()'s private per-call temp-dir socket). - If nothing answers, spawns one at that address instead of a private one, so later callers can find it.
- Does not wire up
spawn()'s lifetime pipe (the whole point is that this daemon outlives its first caller).
Why this is a real feature, not a thin wrapper
- Race safety. Two callers starting near-simultaneously and both doing "spawn if nothing's there" need a lock (e.g. atomic bind-or-connect on the socket) or you get two daemons contending for one address.
- Idle shutdown. For this to be a good citizen (not an orphan process running forever after the last client disconnects), the daemon itself needs to track "no clients connected for N minutes" and self-exit. That's server-side (
mecated serve) logic, not something the TS client can enforce from the outside. - Version skew. A long-lived daemon started by an older
mecatedbinary reconnected to by a newer SDK client needs the existingServerCapabilitiesfeature-bit check (already used forspawn()/connect()skew detection) applied the same way here.
Non-goals (for a first version)
- Multi-machine/network discovery — this is about one user's machine, a well-known local address (e.g. a UDS path under XDG state dir) is enough.
- Automatic
--store-dirprovisioning — this is a separate, complementary concern (already flagged as a deliberate non-addition on #821's M3).
Fully or partially written by an AI agent.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.