feat(ca): answer "where are my agents" with one myCloudAgents request - #1062
Merged
Conversation
Built with backboard's dump-public-introspection.ts against the branch that adds myCloudAgents (railwayapp/mono#34876), so the CLI change that consumes the field can be written before the backboard change deploys. The bulk of the diff is drift between the deployed schema and master plus field ordering; the whole binary still compiles against it, which is the check that matters. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Startup previously loaded only what a keypress immediately needs — the target, the default project, environments this machine had used — because asking `cloudAgents` for the whole account was one request per environment, and hundreds of requests rate limited real users. That kept launches cheap by giving up on full visibility. `myCloudAgents` (railwayapp/mono#34876) removes the trade. One request returns every agent the caller owns across the account, so startup now asks that first and settles the entire tree from the answer: agents land in their environments, and every environment absent from the reply is loaded as empty, because absence means "none of yours here" rather than "unknown". An environment that already answered — a launch just filled the target — keeps what it has, which may carry session state the account-wide reply doesn't. Against a backboard that predates the field, the request fails with an unqueryable-field error and startup degrades to exactly what it did before: the keypress-driven loads, the per-environment sweep behind `shift+r`, and the 429 handling, all unchanged. A rate limit on the new request itself gets the same Retry-After toast the sweep produces, not a silent fallback that would spend more requests against a refusal. `shift+r` stays for the fallback path. On a backboard with the field it reports every project as already loaded, which is now simply true at startup. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An adversarial review pass found four ways the new startup path could misbehave, all fixed: Session prefetch is bounded. The account-wide settle names every running agent at once, and the prefetch fired one sessions request per agent simultaneously — the burst shape this TUI exists to avoid, reintroduced one layer down. Prefetch now runs through the same five-permit, stop-on-first-429 discipline as the environment sweep. Sessions replies follow their agent. A reply was applied to whatever agent sat at the index the request went out with; an environment refetch inserting a newer agent above it would attach the sessions to the wrong row. The reply now carries the agent id and resolves by it, going nowhere if the agent is gone. The settle no longer overwrites in-flight environments. An environment in Loading has a request issued after the account-wide one, so its reply is strictly newer; settling over it could briefly hide an agent created since the snapshot — permanently, if that newer fetch had already failed. Loading environments keep their spinner, and the settle arm now also runs expand_pending as the safety net for a launch whose own refetch died. A stale stop flag can't strand the fallback. If a 429 had set the stop-everything flag before myCloudAgents failed over, the fallback sweep marked environments Loading and then aborted without ever answering — spinners forever. The flag is cleared before the fallback, and when the fallback has nothing to load the error is surfaced in the status line instead of vanishing (an expired login previously looked like an account with no agents anywhere). Also from review: user-driven environment loads (expand, per-row r, the post-launch refetch) now classify a 429 like every background fetch does — row back to "not loaded" plus the Retry-After toast, rather than pinning "rate limited" to one environment as its own failure — and re-entry from a session skips the account-wide request the already-settled tree would discard. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
codyde
force-pushed
the
cody/ca-my-cloud-agents
branch
from
August 9, 2026 05:20
cac6b23 to
1df73fe
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #1056; lands after it and after railwayapp/mono#34876 deploys.
#1056 stopped the startup fan-out by loading less — the price was that a project's agent count only appeared when you opened it, with
shift+ras the whole-account escape hatch. This restores full visibility at startup without the fan-out: onemyCloudAgentsrequest returns every agent the caller owns, and the tree settles entirely from that answer. Agents land in their environments; an environment absent from the reply is loaded as empty, since absence from a complete answer means "none of yours here" rather than "unknown". An environment that already answered (a launch just filled the target) keeps what it has, which may carry session state the account-wide reply doesn't.The fallback is the code #1056 shipped, unchanged. Against a backboard that predates the field, the request fails with an unqueryable-field error and startup degrades to the keypress-driven loads, the
shift+rsweep, and the 429 handling. A rate limit on the new request itself surfaces the same Retry-After toast rather than silently falling back, which would spend more requests against a refusal.schema.jsonwas regenerated from the mono working tree withdump-public-introspection.tsso this could be written before the backboard change deploys; the CLI must still release after backboard, or every launch takes the fallback path.shift+rstays for the fallback path. On a current backboard it reports every project as already loaded, which at startup is now simply true.Verification
873 tests, fmt and clippy clean. New tests: one
myCloudAgentsreply settles every environment (agents placed by environment, absent environments loaded as empty, unknown environments ignored), and environments that already answered keep their contents.🤖 Generated with Claude Code
An adversarial review pass then hardened the path (second fix commit): session prefetch is bounded by the same five-permit discipline as the sweep, sessions replies resolve by agent id instead of positional index, the settle no longer overwrites in-flight environments, a stale rate-limit stop can't strand the fallback as permanent spinners, user-driven loads classify 429s like background ones, and re-entry skips the request a settled tree would discard.