Repository navigation
Let a hosted launch name a Claude or Codex account - #1870
alexeyzimarev wants to merge 47 commits into
Conversation
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… host Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
An explicit account id is honoured or refused, never replaced by the default. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…1806) An id with no stored directory resolves against the registry like a fresh launch. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The spawn frame's account follows the title byte, so a frame without a title now has that byte consumed before it is read. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…1806) A snapshot cached before the wiring could satisfy "at or past the revision", so add and rewire now commit one after wiring and every verb reports it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ed (#1806) A partial unwire changes the account on disk, so a snapshot cached before it must not read as current. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
accounts.json is polled by length and mtime and re-read once more on the tick after a change: two same-length writes inside one timestamp tick stat alike. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#1806) A throwing Changed handler faulted the poll loop, and the host stops on that. A failed read now leaves the stat untrusted, so a transient sharing violation during the CLI's atomic replace is retried on the next tick. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A refusal ends the launch as launch_failed_cleaned rather than a rejection, so its account_unavailable reason is never collapsed into a generic one. A vendor with no default directory carries no account and is never refused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The Codex resolved-model report reads the account's config.toml as well, so a default-model launch reports the model that account runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1806) The built-in directory is reached by removing the variable, not naming it: CLAUDE_CONFIG_DIR=~/.claude moves .claude.json inside the directory. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A refused account interrupts the entry by name and skips kcap continue: the continuation resolves the same recorded account and would be refused too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Without a vendor session the lane never runs the native launch that checks the account, so the check runs before the continuation instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A reconnect re-registers every agent and a launch still in its handshake is reported before its agent exists, so both carry the account too. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The accounts snapshot is built before the host starts so the startup probe and the watcher's first watch set read the same accounts; start now announces a snapshot that replaces it, so a registry change in that window still reaches both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The watcher starts watching an added account on its next tick, up to 15 s after the probe; priming from the files as they are then would absorb a write in between and leave a stale catalog advertised. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The daemon's pre-start rebuild can fail, and the snapshot start then builds is the first one any subscriber sees; an unchanged revision is still never announced. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A change landing between the DaemonConnect payload and readiness has its own send dropped by the IsReady guard, so registration sends the current snapshot when its host id or revision differs from the one it connected with. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#1806) kcap plugin install --codex wires the CLI shell's Codex directory, which need not be the daemon's or the chosen account's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The daemon is the last hop, so an id it cannot honour must not launch as if none were sent. A resume still ignores the id, as it does for every vendor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1806) On the local-spawn path a throw here escapes the handler, so the client sees EOF instead of an error frame. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1806) The host stops the daemon when a background service throws. A failed read must also leave the stat untrusted, or later ticks skip until the next write. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1806) kcap agent ls shows no account, and kcap daemon status --json reports the service rather than agents. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Frame 86 went to AgentSessionReply on main, so AccountsSubscribe moves to 32, and the PTY factory takes the account home where the removed prompt root was. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Important Review skippedToo many files! This PR contains 129 files, which is 29 over the limit of 100. To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch. Upgrade to a paid plan to raise the limit. This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry. ⚙️ Run configuration
📒 Files selected for processing: 129
You can disable this status message by setting the
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
PR Summary by QodoSupport account-selected Claude and Codex launches in the daemon and CLI
AI Description
Diagram
High-Level Assessment
Files changed (126)
|
The agent status row and the connect payload carry main's working_since and active_count fields ahead of the account fields, and the golden fixture follows that order. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6b3afe31d0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| return new CommandOutcome(CommandOutcomeKind.LaunchRejected, agentId, RejectReason: CommandRejectedReason.Semantic); | ||
| } | ||
|
|
||
| var resolution = ResolveAccount(cmd.Vendor, cmd.AccountId, resume?.Entry.Launch); |
There was a problem hiding this comment.
Reject account IDs on review launches
When a LaunchKind.Review or LaunchKind.ReviewFlow command unexpectedly carries a non-null AccountId, this unconditional resolution honors that account and launches the reviewer with its credentials/configuration. The feature contract requires both review kinds to remain on the daemon's default account, so a stale or malformed server command can spend the wrong account and, for Codex review flows, make MCP isolation inspect the daemon-default configuration while the child inherits the selected account's configuration. Reject a supplied account ID for review kinds, or ignore it explicitly and resolve the default before creating the runtime.
Useful? React with 👍 / 👎.
Code Review by Qodo
1.
|
| public virtual async Task AccountsChangedAsync(AccountsSnapshotDto snapshot) { | ||
| if (!IsReady) return; | ||
| try { await SendAccountsChangedRawAsync(snapshot); } | ||
| catch (Exception ex) { _logger.LogDebug(ex, "AccountsChanged send failed (old server or transient)"); } |
There was a problem hiding this comment.
2. The server can retain a stale account list 🐞 Bug ☼ Reliability
AccountsChangedAsync catches a failed send, while AccountsPublisher treats that snapshot as sent and schedules no retry. If a send fails while the connection remains ready and no later registry change or registration occurs, the server never receives the updated account list.
Agent Prompt
## Issue description
A transient account-snapshot send failure is swallowed, leaving the server stale until another change or registration.
## Fix Focus Areas
- src/Capacitor.Cli.Daemon/Services/ServerConnection.cs[209-219]
- src/Capacitor.Cli.Daemon/Services/AccountsPublisher.cs[148-185]
## Recommended Fix
Make send failure observable to the publisher and retry its latest snapshot with a bounded delay while the connection is ready. Preserve the connect snapshot as the reconnect recovery path.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| _lastSentAt = time.GetTimestamp(); | ||
| } | ||
|
|
||
| _ = SendAsync(snapshot); |
There was a problem hiding this comment.
4. Older account data can overwrite newer data 🐞 Bug ☼ Reliability
AccountsPublisher starts each snapshot send without awaiting or ordering earlier sends. If an earlier send remains in flight when a trailing send or reconnect repair delivers a newer revision, the older revision can subsequently reach the server last.
Agent Prompt
## Issue description
Overlapping snapshot sends can leave the server with an older account revision than the daemon holds.
## Fix Focus Areas
- src/Capacitor.Cli.Daemon/Services/AccountsPublisher.cs[148-185]
- src/Capacitor.Cli.Daemon/Services/ServerConnection.cs[823-830]
## Recommended Fix
Use one ordered publication lane for publisher sends and post-registration repair. Coalesce pending updates to the latest snapshot, and do not transmit an older revision after a newer one.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
…#1806) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A reviewer's MCP inventory and hooks are read from the daemon's default account, so an id on a review or review-flow launch would run the child where the inventory never looked. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…1806) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The wiring runs under the registry lock and the stamp takes it again, so a remove can land between them; the stamp now says whether it found the account. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The quoting helper moves to Core, public, so the daemon can reach it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A default reached through a symlink used to be recorded as the link, so retargeting the link before a resume moved the continuation to another account while the ledger still named the first. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Part of #1806 — AI-4194
What & why
A hosted Claude or Codex agent can now run under one of the accounts registered on its host (a vendor config directory), chosen at launch and carried into the resume ledger;
kcap agent start --accountand the app launcher share the path. The daemon publishes the host's registry, its own default directories and a per-account Codex model catalog to the server and over the local socket, so the app can list accounts and see which are wired. This is the daemon and CLI half of #1806; the server, app and limits readings follow in their own PRs.Where to look
An explicit account id is honoured or refused, never replaced by the default, on launch and resume alike. A daemon whose
CLAUDE_CONFIG_DIRis spelled~/.claudetreats it as the built-in directory and drops the variable for its default account, so hosted children keep reading~/.claude.json. The accounts frames are 32 and 87; 86 is the agent-session reply.Verification
dotnet test --solution Capacitor.slnxon the merged tree: 22,571 tests, 22,452 passed, 117 skipped, 2 failed. The WorkOS emulator image cannot be pulled from this machine, and the Cursor refresh test fails on any Mac with/opt/homebrew/bin/kcappresent, independent of this branch. Both AOT publishes report no IL2026/IL3050 warnings. Still owed: the live check (install, restart the daemon,kcap accounts --json,kcap agent start claude --account <id> -d), which restarts the daemon hosting the session that produced this branch.🤖 Generated with Claude Code