Goal
Factory dispatch runs on a cloud node, not on a laptop — so work expressed on any surface is picked up and executed without a human machine being awake.
This resumes chief/principals/khaliq/workstreams/factory-cloud-node-dispatch.md, which is status: active with owner: unassigned. It is the principal's stated priority 4 of four. It has never been started as a hosting change.
Read this before planning: the blocker is not hosting
The workstream's own conclusion, and the single most important line in it:
Moving the host first would only relocate the outage.
AGENT_RELAY_BIN means two different things in two repos:
- in
relay — the Rust broker binary
- in
relayfile's Go CLI — the agent-relay Node CLI
So Relayfile's automatic delegated-credential re-mint execs the Rust broker, fails, and reports a version error against a CLI that is already current:
relayfile status
error: refresh delegated relayfile credentials: delegated relayfile credentials expired
or revoked. Re-bootstrap with `agent-relay cloud login`; cloud re-mint fallback failed:
agent-relay CLI >= 8.7.0 required with `agent-relay cloud session --help`
(error: unrecognized subcommand 'cloud' / Usage: agent-relay-broker <COMMAND>)
Credential expiry is routine and self-healing by design. What makes it an outage is that the self-heal path can never run — it execs the wrong binary, then directs the operator to an upgrade that would change nothing.
Every relay-spawned agent inherits this variable, so it breaks Relayfile for the whole fleet, not one machine. Confirmed still set in the live environment as of 2026-08-15:
AGENT_RELAY_BIN = /Users/khaliqgant/.local/bin/agent-relay-broker
relayfile-sdk-auth-0814 owns the real fix, per the principal: use the SDK, do not shell out. Do not re-solve it here; coordinate.
What does NOT need changing — do not relitigate
The active dispatch contract is already correct. <chief>/factory.config.json has issueSource: "github", safety gated on the factory label plus [factory] title prefix, mergePolicy: "never", and a repo list spanning the org.
A cloud-node Factory needs its own resolved copy of factory.khaliq.config.json, with its exact path passed via --config on every command and runtime. Routing scope lives inside that file — never in file placement. A factory.config.json sitting in another repo is inert, not a fallback.
Prior art — do not re-derive
provisionFleetSandboxNode() (cloud, packages/web/lib/fleet/sandbox-bridge.ts:464) is a complete, tested function with zero production callers. It may be exactly the mechanism this needs; it was simply never wired to anything.
- Architecture correction, stated directly by the principal 2026-08-13: Daytona should provision a fresh sandbox per agent, not reuse one long-lived box.
- Therefore the existing "Done when" criteria in
daytona-fleet-nodes.md are STALE. Phase 1's 24-hour continuous-uptime bar was designed for a persistent node and is the wrong criterion for an ephemeral-per-agent model. Rewrite the acceptance bar before trusting it.
- A related consequence: the identity-reclaim gate (
relay#1499, draft, unmerged) may be solving a problem that mostly disappears under fresh-per-agent — a brand-new sandbox has no stale identity to reclaim. Reason about it in writing rather than assuming either way.
Sequencing — three defects would follow Factory to the cloud unchanged
Moving hosts today buys "runs while the laptop sleeps" and inherits every current defect. Each of these reproduces identically on a cloud node:
| blocker |
effect on a cloud Factory |
relayfile-adapters#263 — issue _index.json omits labels |
Same 1,362-issue serial walk; readiness reconcile stalls identically |
relayfile-cloud#155 — GitHub App writeback 403 |
PR publication fails the same way; work strands on branches |
factory#267 — unbounded fail-open index fallback |
Same total dispatch outage with no operator-visible signal |
Recommendation: land those three first, so the cloud node starts working rather than starting broken. This issue should plan for that ordering, not race it.
Scope
- Resolve the
AGENT_RELAY_BIN collision — or confirm relayfile-sdk-auth-0814's SDK fix lands first and depend on it. State which.
- Provision a cloud node for Factory, using
provisionFleetSandboxNode() if it fits rather than a parallel mechanism.
- Give it a resolved config copy and pass its exact path with
--config.
- Rewrite the acceptance criteria for the fresh-sandbox-per-agent model before declaring anything done.
- Keep the laptop Factory able to run, so this is a migration rather than a cutover — two Factories dispatching the same issues would double-claim, so the handover needs an explicit stop/start order.
Definition of done
- Factory dispatches an issue from a cloud node with the laptop asleep or offline, verified by an agent spawning and a PR opening.
- The node survives credential expiry without operator intervention — that is the whole point of fixing the env-var collision, so exercise it rather than assuming.
- Exactly one Factory is dispatching at any moment; prove the handover does not double-claim.
- The acceptance bar is written for the ephemeral model, not inherited from the persistent-node one.
Verification — required, against the built CLI
Do not close this on a deployment succeeding.
node bin/factory.mjs status --config <resolved-path-on-node>
node bin/factory.mjs run-once --config <resolved-path-on-node> --dry-run
Then a real dispatch from the node with the laptop's Factory stopped, showing the agent spawn and the PR. Attach real output.
Constraints
- Branch from
origin/main. mergePolicy: never — open the PR and stop at review.
- Do not restart the old
daytona-fleet-proof-0811 sandbox; that is the model being moved away from.
- PR publication is currently failing intermittently (
relayfile-cloud#155). If this issue's PR does not publish, report it rather than working around it.
- Related workstreams:
factory-cloud-node-dispatch.md (this), daytona-fleet-nodes.md, cross-node-attach.md.
Goal
Factory dispatch runs on a cloud node, not on a laptop — so work expressed on any surface is picked up and executed without a human machine being awake.
This resumes
chief/principals/khaliq/workstreams/factory-cloud-node-dispatch.md, which isstatus: activewithowner: unassigned. It is the principal's stated priority 4 of four. It has never been started as a hosting change.Read this before planning: the blocker is not hosting
The workstream's own conclusion, and the single most important line in it:
AGENT_RELAY_BINmeans two different things in two repos:relay— the Rust broker binaryrelayfile's Go CLI — the agent-relay Node CLISo Relayfile's automatic delegated-credential re-mint execs the Rust broker, fails, and reports a version error against a CLI that is already current:
Credential expiry is routine and self-healing by design. What makes it an outage is that the self-heal path can never run — it execs the wrong binary, then directs the operator to an upgrade that would change nothing.
Every relay-spawned agent inherits this variable, so it breaks Relayfile for the whole fleet, not one machine. Confirmed still set in the live environment as of 2026-08-15:
relayfile-sdk-auth-0814owns the real fix, per the principal: use the SDK, do not shell out. Do not re-solve it here; coordinate.What does NOT need changing — do not relitigate
The active dispatch contract is already correct.
<chief>/factory.config.jsonhasissueSource: "github",safetygated on thefactorylabel plus[factory]title prefix,mergePolicy: "never", and a repo list spanning the org.A cloud-node Factory needs its own resolved copy of
factory.khaliq.config.json, with its exact path passed via--configon every command and runtime. Routing scope lives inside that file — never in file placement. Afactory.config.jsonsitting in another repo is inert, not a fallback.Prior art — do not re-derive
provisionFleetSandboxNode()(cloud,packages/web/lib/fleet/sandbox-bridge.ts:464) is a complete, tested function with zero production callers. It may be exactly the mechanism this needs; it was simply never wired to anything.daytona-fleet-nodes.mdare STALE. Phase 1's 24-hour continuous-uptime bar was designed for a persistent node and is the wrong criterion for an ephemeral-per-agent model. Rewrite the acceptance bar before trusting it.relay#1499, draft, unmerged) may be solving a problem that mostly disappears under fresh-per-agent — a brand-new sandbox has no stale identity to reclaim. Reason about it in writing rather than assuming either way.Sequencing — three defects would follow Factory to the cloud unchanged
Moving hosts today buys "runs while the laptop sleeps" and inherits every current defect. Each of these reproduces identically on a cloud node:
relayfile-adapters#263— issue_index.jsonomitslabelsrelayfile-cloud#155— GitHub App writeback 403factory#267— unbounded fail-open index fallbackRecommendation: land those three first, so the cloud node starts working rather than starting broken. This issue should plan for that ordering, not race it.
Scope
AGENT_RELAY_BINcollision — or confirmrelayfile-sdk-auth-0814's SDK fix lands first and depend on it. State which.provisionFleetSandboxNode()if it fits rather than a parallel mechanism.--config.Definition of done
Verification — required, against the built CLI
Do not close this on a deployment succeeding.
Then a real dispatch from the node with the laptop's Factory stopped, showing the agent spawn and the PR. Attach real output.
Constraints
origin/main.mergePolicy: never— open the PR and stop at review.daytona-fleet-proof-0811sandbox; that is the model being moved away from.relayfile-cloud#155). If this issue's PR does not publish, report it rather than working around it.factory-cloud-node-dispatch.md(this),daytona-fleet-nodes.md,cross-node-attach.md.