Skip to content

feat(cli): ensure the daemon explicitly before attaching in the CLI and MCP - #3766

Open
thymikee wants to merge 1 commit into
feat/ensure-daemon-clientfrom
feat/ensure-daemon-adoption
Open

thymikee wants to merge 1 commit into
feat/ensure-daemon-clientfrom
feat/ensure-daemon-adoption

Conversation

@thymikee

@thymikee thymikee commented Oct 16, 2026 •

Copy link
Copy Markdown
Member

Summary

Layer 3 of 3 for #3754 (umbrella #3747); based on #3765. The CLI and MCP stop managing the daemon implicitly.

  • withEnsuredDaemon wraps the CLI's default transport and each MCP tool call's client. The first request that needs a local daemon calls ensureDaemon() once; every request then attaches. A command that never reaches the daemon starts none.
  • Intentional CLI behavior change: a daemon from another version or build is replaced only if idle. A busy one fails the command with daemon-busy instead of losing its sessions; one without the quiesce capability fails with daemon-incompatible. Recorded in the changelog and CLI help, and in the client docs.
  • agent-device proxy is unchanged and stays on the managed path.
  • A request that finds its ensured daemon gone ensures again and retries once; nothing was sent.
  • Pass-through, unchanged: remote --daemon-base-url connections and a one-shot replay/test on its private ephemeral daemon. A timeout no longer retires an unresponsive daemon from the CLI or MCP (changelog).

11 files incl. docs. Closes #3754.

Validation

pnpm check:affected --run --head e9cab3f641: passed. Tests cover ensure-once, idle replacement, busy refusal before send, remote and private-replay pass-through, and re-ensure after the daemon vanishes. An independent review of layers 1-3 found 7 issues. Five are fixed. Uploads and lease-less holds being outside the census, and quiesce over HTTP with an auth hook, are documented in ADR 0006. A hung but connectable daemon is no longer retired by a CLI timeout; the changelog says so.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://callstack.github.io/agent-device/pr-preview/pr-3766/

Built to branch gh-pages at 2026-10-17 05:57 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@github-actions

github-actions Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Size Report

Metric Base Current Diff
Installed (including dependencies) 5.34 MB 5.34 MB +3.1 kB
Package (unpacked) 5.33 MB 5.34 MB +3.1 kB
Package (download) 1.61 MB 1.61 MB +960 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 28.3 ms 29.9 ms +1.6 ms
CLI --help 82.3 ms 81.0 ms -1.3 ms

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 8 files

You’re at about 92% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread src/daemon-client/daemon-client-ensuring.ts Outdated
Comment thread src/daemon-client/daemon-client-ensuring.ts Outdated
Comment thread src/commands/schema/cli-help.ts Outdated
Comment thread website/docs/docs/commands.md Outdated
Comment thread CHANGELOG.md Outdated
@thymikee
thymikee force-pushed the feat/ensure-daemon-adoption branch from d5cc25a to 0bb9f87 Compare October 16, 2026 21:13

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 5 files (changes from recent commits).

You’re at about 92% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread src/daemon-client/__tests__/daemon-client-ensuring.test.ts Outdated
Comment thread CHANGELOG.md Outdated
@thymikee
thymikee force-pushed the feat/ensure-daemon-adoption branch from 0bb9f87 to ad9f406 Compare October 16, 2026 21:35
@thymikee
thymikee force-pushed the feat/ensure-daemon-adoption branch from ad9f406 to b5575cb Compare October 16, 2026 22:00

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 4 files (changes from recent commits).

You’re at about 93% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread src/daemon-client/daemon-client.ts Outdated
@thymikee
thymikee force-pushed the feat/ensure-daemon-adoption branch from b5575cb to 25a88e0 Compare October 16, 2026 22:10

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 5 files (changes from recent commits).

You’re at about 93% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

Requires human review: Auto-approval blocked because this review re-detected 1 unresolved issue already reported by Cubic.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread src/daemon-client/daemon-client-ensuring.ts
@thymikee
thymikee force-pushed the feat/ensure-daemon-adoption branch from 25a88e0 to 4178464 Compare October 16, 2026 22:28
@thymikee
thymikee force-pushed the feat/ensure-daemon-adoption branch from 4178464 to 74b7ceb Compare October 16, 2026 23:05
@thymikee
thymikee force-pushed the feat/ensure-daemon-adoption branch 3 times, most recently from 8de53bd to c710506 Compare October 17, 2026 00:05
@thymikee
thymikee force-pushed the feat/ensure-daemon-adoption branch from c710506 to 932f6f1 Compare October 17, 2026 00:14
@thymikee
thymikee force-pushed the feat/ensure-daemon-adoption branch from 932f6f1 to 20bc45f Compare October 17, 2026 00:38
@thymikee
thymikee force-pushed the feat/ensure-daemon-adoption branch from 20bc45f to e1e2b91 Compare October 17, 2026 01:33
@thymikee
thymikee force-pushed the feat/ensure-daemon-adoption branch from e1e2b91 to 125b4cc Compare October 17, 2026 01:44
@thymikee

Copy link
Copy Markdown
Member Author

This PR is ready at 125b4cc. I found no problems that should hold it up. All 9 checks that are not passing were cancelled as superseded runs, so there is no failure to attribute, and they need a completed run at 125b4cc before merge. The diff touches their routes, because the CLI default transport is now the ensured one and daemon-replace-exit-flush.test.ts changed. No conflicts.

Not blocking, so take or leave these: daemon-client-ensuring.ts:95 maps a daemon that was force-retired as unresponsive to reason 'incompatible', so cli.ts:88 prints "Replaced idle daemon ... it did not match this client", and the 'unreachable' label is inferred from 'missing' plus a previous daemon, so the notice should name how the previous daemon left and ensureDaemon's onStart could report that cause as a declared value; daemon-lifecycle-errors.ts:77, line 61 and daemon-client-timeout.ts:195 now reach CLI and MCP users with hints that name ensureDaemon(), so the hints should hold on every surface (for example, stop it with agent-device daemon stop --state-dir X); command-tools.ts:251 wiring through the default createClient has no test, so one MCP tool-call test could assert that daemonLifecycle 'attach' reaches the transport and that a second call ensures again; and in daemon-client-ensuring.ts:50 the "Settled promises are not kept" comment is wrong (only rejected ones are dropped), ?? process.env.AGENT_DEVICE_STATE_DIR repeats what resolveExplicitStateDir reads, the MCP cast at command-tools.ts:258 duplicates the one in cli.ts and goes away if createEnsuredDaemonTransport returns AgentDeviceDaemonTransport, the test at ensuring.test.ts:252 should assert details.reason instead of matching /busy/, and the re-ensure test at ensuring.test.ts:183-188 should build daemon-not-running through daemonNotRunningError.

I did not run the tests or check:affected, and I did not measure the latency of the extra per-tool-call ensure in MCP. I took the busy/idle census behavior from the base layer without reading its implementation.

Nine inline threads from cubic-dev-ai (all P2) no longer apply at this head, so the author can resolve them: r4299317645 (entry deleted only when it matches the relied one), r4299317658 (rejected ensure is dropped), r4299317674 (cli-help excludes device status and release --stale), r4299317719 (commands.md names the exclusions), r4299317737 (CHANGELOG names the census exclusions), r4299430976 (test binds both listeners before closing), r4299430986 (CHANGELOG no longer says idle for an unresponsive daemon), r4299793590 (import promise is memoized), and r4299837292 (a pre-aborted request skips ensuring; a mid-ensure abort is documented and the caller's guard settles it).

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Oct 17, 2026
…nd MCP

The CLI and MCP now call ensureDaemon() once their config is resolved and attach to what it leaves.
A command replaces a daemon from another version or build only if it holds no work, instead of
destroying its sessions; a busy one fails the command with daemon-busy. Remote connections and a
one-shot replay on its private daemon pass through unchanged.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@thymikee
thymikee added this pull request to stack #3774 October 17, 2026 05:48
@thymikee
thymikee force-pushed the feat/ensure-daemon-adoption branch from 125b4cc to e9cab3f Compare October 17, 2026 05:49
@thymikee

Copy link
Copy Markdown
Member Author

Thanks. Taken in e9cab3f:

  • Force-retired daemon: a daemon retired for timing out on quiesce and failing liveness probes is now reported through onStart as missing with a previous (the same as an unreachable one), so the CLI prints "Replaced unreachable daemon" and never "Replaced idle daemon". The onStart contract says so.
  • Hints hold on every surface (see feat(client): daemonLifecycle attach mode and ensureDaemon() #3765).
  • MCP wiring: new test drives the default client factory twice and asserts one ensureDaemon per tool call and a single daemon start.
  • Nits: the stale "Settled promises" comment is fixed, the redundant AGENT_DEVICE_STATE_DIR fallback is dropped, the busy-refusal test asserts details.reason, and the re-ensure test builds its error with daemonNotRunningError.
  • Not taken: the MCP cast. createEnsuredDaemonTransport returning the client transport type would loosen CliDeps.sendToDaemon, which the CLI tests inject fakes into; the cast stays at the one boundary where the request types differ.
  • agent-device proxy stays on the managed path (see feat(client): daemonLifecycle attach mode and ensureDaemon() #3765), so nothing about it changes here.

pnpm check:affected --run passes at e9cab3f, plus the full unit and Node integration suites. CI is re-running on this head.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(client): explicit daemon lifecycle with ensureDaemon() and attach clients

1 participant