Repository navigation
[factory] Accept a persona in relay spawn and relayflow steps, via the SDK — not a CLI shell-out #306
Description
Note: this body was rewritten after the original claim was falsified. The comments below preserve how it got here — the first version asserted personas could not be launched non-interactively at all, which is false. Read this body, not the opening comment.
The gap
A persona can be launched three ways today, and only one of them takes a persona.
| Surface | Takes a persona? |
|---|---|
agentworkforce agent <persona> (interactive TTY) |
yes |
Agent Relay spawn action |
no — cli + free-text task + target_node |
| Relayflow steps | no — { name, cli, role, preset } (see relayflows/workflows/ci/fix-mcp-spawn.yaml) |
So anything placed on a fleet node, or run as a workflow step, is a hand-written prompt rather than a persona.
Why that loses more than convenience
A persona is not a prompt. nango-integrations declares agentsMdContent, skills (each with a source that gets installed), mcpServers, harness, model, and harnessSettings. Pasting its text into a task string carries one of those. The spawned agent has no skills installed and no MCP server — it works from memory of a workflow the persona exists to enforce.
And it fails silently. Nothing errors. The agent runs, sounds correct, and is missing its tools. A wrong path that works badly is worse than one that fails.
The practical consequence: every remote agent is a fresh, unversioned approximation of a capability that already exists in a reviewed file, and improvements to that file never reach the fleet.
The capability already exists — this is a caller problem
@agentworkforce/deploy exports a real programmatic entrypoint:
export async function deploy(opts: DeployOptions, resolvers?: DeployResolvers): Promise<DeployResult>plus preflightPersona, the mode launchers (devLauncher / sandboxLauncher / cloudLauncher), ModeLaunchHandle / ModeLaunchInput / ModeLauncher, and createBufferedIO. It validates declared persona inputs up front with typed errors rather than failing inside a child process.
@agentworkforce/local-surface already composes that into Agent Relay: defineWorkforcePersonaNode(options): FleetNodeDefinition, whose launchPersonaRunner calls deploy() with mode: 'dev', detach: true, bridged: true, noPrompt: true (local-surface/src/index.ts:145). The bridged flag exists specifically so the persona survives a non-interactive parent whose stdin ends.
So non-interactive, in-process persona launch is built, deliberate, and already wired to @agent-relay/fleet. What is missing is that spawn and relayflow steps do not reach for it.
Constraint — SDK surfaces only
Do not implement this by shelling out to agentworkforce agent. pear/src/main/broker.ts:2991 does exactly that, and it is not the pattern to copy. Shelling out:
- makes a CLI binary a runtime dependency of every calling host — unacceptable for an arbitrary fleet node or cloud sandbox;
- couples two release trains across a process boundary with no type checking (
relayfile mountrecently rejected--workspace/--local-dir, flags its own help text advertised); - forces stdout scraping for state — pear parses readiness out of log lines with
personaHarnessReadyFromOutput; - drives a TTY-oriented command from a daemon.
Notably pear already depends on @agentworkforce/deploy and shells out anyway. The library is there; the caller reaches past it.
What done looks like
- Agent Relay
spawnaccepts a persona (name or path) as an alternative tocli+task, resolved through the same registryagentworkforceuses (built-in / cwd / personal / configured dirs).harnessandmodelcome from the persona spec. Atasksupplied alongside layers the concrete assignment over the persona's standing instructions. - Relayflow steps accept a persona in place of
cli+role, with the same resolution. - Both go through
@agentworkforce/deploy/local-surfacein process. Noagentworkforcebinary required on the node, no output parsing. - Launch is deduped and verified. Borrow the discipline from pear even though not its mechanism: coalesce concurrent launches of the same persona (
personaSpawnRequestKeykeys on project + persona; a fleet needs the node-scoped equivalent), and confirm broker registration and harness readiness before reporting success, releasing the agent if either fails. A launched process is not a running persona. - Discoverability. Nothing today points a caller from
spawntowarddefineWorkforcePersonaNode. Whatever ships, make the working path findable from the wrong one.
Cross-repo
The persona resolution and SDK live here (workforce). The spawn action lives in relay. Relayflow step schema lives in relayflows. Expect changes in more than one repo; do not merge anything — the merge gate is the principal's.
Activity
khaliqgant commentedon Aug 7, 2026
Correcting this issue — the main claim was wrong
I filed this saying a persona cannot be launched by anything other than a human at a TTY. That is false, and I should have checked the packages in this repo before asserting it.
@agentworkforce/local-surfacealready exportsdefineWorkforcePersonaNode(options): FleetNodeDefinition— and thatFleetNodeDefinitionis imported from@agent-relay/fleet. A persona already runs as an Agent Relay fleet node.Internally it calls
launchPersonaRunner→deployPersonawithmode: 'dev',detach: true,bridged: true,noPrompt: true(packages/local-surface/src/index.ts:145). Thebridgedflag exists precisely so the persona survives a non-interactive parent whose stdin ends. So a fully non-interactive, programmatic persona launch is not only possible, it is deliberately built for and commented as such.There is also a whole persona SDK surface I overlooked:
@agentworkforce/persona-kit,@agentworkforce/personas-core, and per-persona packs published to npm — including@agentworkforce/persona-nango-integrations@0.1.9, which exports the very persona JSON I hand-copied into a prompt.So the loss I described was self-inflicted. I reached for relay's raw
spawnaction and pasted persona text into ataskstring, when the persona could have been run as a fleet node with its skills, MCP servers, harness and model intact.What remains genuinely missing — narrower, and worth keeping
Relay's
spawnaction still takes onlycli+ free-texttask+target_node. It has nopersonaparameter, and does not resolve the persona registry (built-in / cwd / personal / configured dirs) thatagentworkforce agentuses.That matters because
spawnis the ergonomic path — it is what an orchestrating agent reaches for, and what I reached for.defineWorkforcePersonaNoderequires standing up a fleet node definition with a channel and workspace connection; it is the right tool for a long-lived persona-backed node, not for "run this persona on that box for this task."So the remaining ask is narrower than the title suggests:
spawnshould accept apersona(name or path) resolved through the same registry, as an alternative tocli+task, withtasklayering the concrete assignment over the persona's standing instructions.spawntowarddefineWorkforcePersonaNode, and the failure mode is silent: pasting persona text into ataskproduces an agent that runs, sounds correct, and is missing its skills and MCP servers. Nothing errors. A wrong path that works badly is worse than one that fails.Retitling would be fair — the accurate framing is "relay
spawnhas no persona parameter, and the working path viadefineWorkforcePersonaNodeis undiscoverable from it", not "personas cannot be spawned".Also raised by Khaliq and belonging with this: a relayflow step should be able to name a persona too. Workflows in
relayflowsdeclare agents as{ name, cli, role, preset }(e.g.workflows/ci/fix-mcp-spawn.yaml) — free text and a CLI choice, with the same loss. Three launch surfaces exist — interactive CLI, relayspawn, relayflow steps — and only the first takes a persona.[-]Personas cannot be spawned through Agent Relay — remote placement silently drops skills, MCP servers, harness and model[/-][+]relay spawn and relayflow steps take a cli + free text, not a persona — and the working path (defineWorkforcePersonaNode) is undiscoverable from them[/+]khaliqgant commentedon Aug 7, 2026
pearalready does this, end to end — so this is a port, not a design problemKhaliq pointed out it works in pear. It does, and the implementation is small and readable:
pear/src/main/broker.ts,spawnPersona()at:2991andspawnPersonaOnce()at:3003.The whole mechanism:
resolveAgentWorkforceCommand(cwd), which throws a specific error if absent: "AgentWorkforce CLI not found — install it to launch personas".agentworkforce list --json→ persona summaries.agentworkforce show <personaId> --json→ the spec, from which pear reads onlyid,description,harness,tags.agentworkforce agent <persona>.verifyPersonaBrokerRegistration(), thenverifyPersonaHarnessReady(), andreleaseUnreadyPersona()if either fails.So
agentworkforce list --jsonandshow <id> --jsonalready exist as machine-readable resolution primitives. The registry lookup I described as missing is a solved problem with a JSON interface.The comment at
broker.ts:3009is the key insight and deserves quoting, because it removes most of the imagined work:A caller does not have to understand a persona to launch one. It resolves the harness, shells out, and the CLI does skills, sidecars and MCP wiring itself. That is precisely the loss I hit by pasting persona text into a
task— and pear avoids it by not trying to reconstruct the persona at all.What this changes about the ask
The remaining gap is genuinely narrow: relay's
spawnaction needs the same three steps pear already performs — resolve viashow --json, takeharnessfrom the spec, delegate toagentworkforce agent <persona>on the target node. Not new capability; the same call from a different caller.Two things worth lifting from pear rather than reinventing:
personaSpawnRequestKey(projectId, personaId)keys in-flight dedup by project + persona, so concurrent requests for the same persona coalesce into one launch. A fleet will need the node-scoped equivalent.The one prerequisite pear enforces and a fleet node must too: the AgentWorkforce CLI has to be installed on the host doing the launching.
khaliqgant commentedon Aug 7, 2026
Correction from Khaliq, and it overrides my last comment: delegating to another CLI is not acceptable. Use the SDK surface.
I posted pear's
spawnPersona()as the pattern to copy. Do not copy it. Pear shells out toagentworkforce agent <persona>, and shelling out is the wrong boundary here regardless of how neatly it is written.Khaliq's rule, stated plainly: we should always be using SDK surfaces.
Why the shell-out is the wrong answer, not just a less tidy one
relayfile mountrejected--workspace/--local-dirflags its own help text advertised.personaHarnessReadyFromOutput,personaHarnessFailedFromOutput). That is a parser against another program's log format, and it is precisely the "check the output rather than the effect" pattern that produced several wrong answers today.agentworkforce agentis TTY-oriented. It drops into an interactive harness session; there is no headless form. Driving an interactive command from a daemon is fragile by construction.The SDK surface already exists
@agentworkforce/deployexports a real programmatic entrypoint:plus
preflightPersona, the three mode launchers (devLauncher,sandboxLauncher,cloudLauncher),ModeLaunchHandle,ModeLaunchInput,ModeLauncher, andcreateTerminalIO/createBufferedIOfor controlling IO instead of scraping it. It validates declared persona inputs up front and throws typed errors — "Unknown input 'x'; persona declares: …" — rather than failing somewhere inside a child process.And
@agentworkforce/local-surfacealready composes exactly that into Agent Relay:defineWorkforcePersonaNode(options): FleetNodeDefinition, whoselaunchPersonaRunnercallsdeploy()withmode: 'dev',detach: true,bridged: true,noPrompt: true(local-surface/src/index.ts:145). That is the library path, in-process, no CLI, and it is already wired to@agent-relay/fleet.Notably pear already depends on
@agentworkforce/deploy@^4.1.16and shells out anyway. So this is not a missing capability — it is a caller reaching for the wrong surface, which is the same mistake I made when I pasted persona text into a relaytask.The ask, restated
Relay
spawn— and relayflow steps — should accept a persona and launch it through@agentworkforce/deploy/local-surface, in process. Noagentworkforcebinary on the node, no stdout scraping, no interactive command driven by a daemon.What is still worth taking from pear is the discipline, not the mechanism: dedup concurrent launches of the same persona, and verify registration and harness readiness before calling it running, releasing it if either fails. A launched process is not a running persona — today produced a long list of records asserting liveness with nothing behind them.
[-]relay spawn and relayflow steps take a cli + free text, not a persona — and the working path (defineWorkforcePersonaNode) is undiscoverable from them[/-][+][factory] Accept a persona in relay spawn and relayflow steps, via the SDK — not a CLI shell-out[/+]barryollama commentedon Aug 11, 2026
Merge receipt and remaining release handoff (2026-08-11)
The SDK implementation is now merged across all three repositories:
1ae498121b6b65ec154511d2218fdaf8cae6443c;@agent-relay/fleet@11.5.1is published and its packed runtime exportsFLEET_DYNAMIC_SPAWN_DELEGATION = true.4ac88ced57b9ebeaa51f9364d9b52d771fffa302; it implements the persona step schema/builder/execution path without a CLI shell-out.df37d32318d5c9efe0b2e70a160f80505e9d06b8from reviewed headf18ca6ef6acff082dbf7805034df86742bed8108. Main CI run 31520312096 passed.Workforce #307's final review inventory was 35 threads / 0 unresolved, with CI, CodeRabbit, and Cubic green. The final fix deterministically removes scratch directories in all stubbed-success persona spawn tests.
What remains before #306 is complete
Owner: Workforce release maintainer — AgentWorkforce/workforce
Publish the next lockstep Workforce release (the dependent relayflows code expects
4.1.38+). Acceptance criteria:@agentworkforce/persona-registry@4.1.38+exists on npm (it is currently unpublished).@agentworkforce/persona-kit@4.1.38+,@agentworkforce/local-surface@4.1.38+, and the other lockstep packages referenced by the release are available.No package was manually published as part of the PR merge.
Owner: Relayflows release maintainer — AgentWorkforce/relayflows
After the Workforce release is public, refresh/verify the clean install for main
4ac88ced57b9ebeaa51f9364d9b52d771fffa302, then rerun its normal publish workflow. Acceptance criteria:npm ci, build/typecheck, and persona runtime/schema/runner tests pass from a clean checkout using registry packages only.Current npm evidence:
@agentworkforce/persona-kitand@agentworkforce/local-surfaceare still 4.1.37;@agentworkforce/persona-registryreturns npm E404. Therefore this issue should remain open until those two release steps are complete.barryollama commentedon Aug 11, 2026
Workforce 4.1.38 partial publication / npm bootstrap blocker (2026-08-11)
The authorized canonical Workforce release was dispatched from exact reviewed main SHA
df37d32318d5c9efe0b2e70a160f80505e9d06b8:version=patch,tag=latest,dry_run=false4.1.38The workflow published the first six packages with npm provenance, then stopped at the first publication of the new package
@agentworkforce/persona-registry:latest@agentworkforce/eventse223fde087bdae0558b03c97b1c4e8e23f6164bf@agentworkforce/persona-kit3e3a47f7c2c7615d4127232d04c8cdaf40836718@agentworkforce/runtime88dfb989a301923ba76dfbda5b4b7f8f9d5a8065@agentworkforce/compose70a25ae24d98041fefb6b744c21ec2714264cff6@agentworkforce/delivery85dfd77a6e3f137a5ca07dd9c8e6a0d786cce6bc@agentworkforce/workload-router7cfedde475c46f5ed2ae1f5f7229397181715591@agentworkforce/persona-registryE404/no permission on first package creation@agentworkforce/deploy@agentworkforce/review-kit@agentworkforce/turn-kit@agentworkforce/mcp-workforce@agentworkforce/daytona-runner@agentworkforce/local-surface@agentworkforce/cliagentworkforceEvery published package's npm attestation identifies run
31521842745, workflow.github/workflows/publish.yml, and source commitdf37d32318d5c9efe0b2e70a160f80505e9d06b8.Preserved reviewed persona-registry artifact
The failed package was deterministically recreated twice from detached exact SHA
df37d32318d5c9efe0b2e70a160f80505e9d06b8, Node26.5.0, pnpm10.17.1, frozen lockfile, full workspace build, lockstep4.1.38versioning, and the workflow'spnpm packcommand. Both packs were byte-identical:agentworkforce-persona-registry-4.1.38.tgz918a8e0a41c3e2fc52cc6e918a604ac71ab2f9ab998337067daca125a8d7fc1fef8ac95df67c27954def2bdaf6cce111cb36787e0bc38129537aed4cf9da06a768bb662f5cda63ee0e59a55896191ee88c8e45b2sha512-mYM3Bn2soSWo1/wf74rJXfZ8J5VN7yva9szhEcs2eH4Lw4EpU3rtTPnaBqdou2YvXNpj7g5ZpViWGR7ojI5Fsg==@agentworkforce/persona-kit: 4.1.38,@agentworkforce/workload-router: 4.1.38.No local/manual publication was attempted.
Minimum safe recovery
This is an npm first-package bootstrap boundary, not a code or test failure. npm requires a package to exist before its trusted publisher can be configured. An authenticated
@agentworkforcenpm owner must:@agentworkforce/persona-registry@4.1.38from the exact preserved tarball above using the npm owner's normal 2FA-protected process.AgentWorkforce/workforce, workflow.github/workflows/publish.yml, allowed actionnpm publish.custom_version=4.1.38, existing versions must be verified as this release's artifacts and skipped, while missing versions are packed and published normally. The six existing packages are verifiable by npm provenance/source SHA; the bootstrapped registry artifact is verifiable by the preserved hashes above. Normal collision-fail behavior must remain the default.custom_version=4.1.38,tag=latest,dry_run=false, and the explicit resume input. This completes the remaining packages at4.1.38without drifting to4.1.39, then creates the release commit/tags/GitHub Release.Relayflows publication remains intentionally held until the Workforce lockstep set is complete and independently verified.
barryollama commentedon Aug 11, 2026
DONE — Workforce 4.1.39 + Relayflows 1.0.6
The authorized lockstep release lane is complete.
Workforce receipts
df37d32318d5c9efe0b2e70a160f80505e9d06b8(feat: expose SDK-backed persona fleet spawning #307); main CI31520312096passed.93883805338, release job93885015194.4.1.39.ff1b60d7ed656942532f122a2aa87c70b8254f23.latest=4.1.39and npm provenance.Exact npm SHA-1 receipts:
A registry-only install of all 15 exact packages passed. Packed/runtime checks confirmed persona-registry exact 4.1.39 kit/router deps and
resolvePersonaReference/loadLocalPersonas; persona-kitapplyPersonaMount; local-surface spawn exports andspawn:personamarker; workload-routerlistBuiltInPersonas.Relayflows receipts
6c487b254da4616a6f3bc2c5bf84b8908cc0f198.f691a4aa573d9544da3ade472e70ef226d543cee; Cubic confirmed all findings addressed.package=all,version=patch,dry_run=false,tag=latest.93899677306; GitHub93899909247; core93899909257; CLI93899909276; Slack93899909281; browser93899909318; release93900362857; summary93900456354.a9996679d8ba790fca4b7de5fe7ba829de9e36ef(annotated tag objectad8f0443f6f57340350e91d177146afba2bd030f).latest=1.0.6and SLSA provenance.Exact npm SHA-1 receipts:
Registry-only installation of all five exact packages passed. The packed core tarball reproduced its registry receipt exactly (186 files, 1,781,792 bytes unpacked; SHA-512
sha512-vBjkQqnyFqrNTgKZIk16lPqosPk8i0/Pw99rFrMlYP71bSgCvnP4LDSnnX0iQPHJPEu+04S+zk/AaH2uQaGE+A==). Runtime checks confirmed core builder/runner/workflow exports, all primitive clients, CLI 1.0.6, exact internal 1.0.6 deps, Workforce persona deps^4.1.39, persona config emission, and invalid CLI+persona rejection.khaliqgant commentedon Aug 13, 2026
Factory dispatch for 306
Implementers: ar-306-impl-workforce
Reviewer: ar-306-review-workforce
khaliqgant commentedon Aug 16, 2026
Factory observed pull request #307 merge and completed this issue.