Skip to content

[factory] Accept a persona in relay spawn and relayflow steps, via the SDK — not a CLI shell-out #306

Description

@khaliqgant

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 nocli + 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 mount recently 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

  1. Agent Relay spawn accepts a persona (name or path) as an alternative to cli + task, resolved through the same registry agentworkforce uses (built-in / cwd / personal / configured dirs). harness and model come from the persona spec. A task supplied alongside layers the concrete assignment over the persona's standing instructions.
  2. Relayflow steps accept a persona in place of cli + role, with the same resolution.
  3. Both go through @agentworkforce/deploy / local-surface in process. No agentworkforce binary required on the node, no output parsing.
  4. Launch is deduped and verified. Borrow the discipline from pear even though not its mechanism: coalesce concurrent launches of the same persona (personaSpawnRequestKey keys 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.
  5. Discoverability. Nothing today points a caller from spawn toward defineWorkforcePersonaNode. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent:teamFactory recipe: dispatch a team of agentsfactoryFactory dispatch gate labelworkforceFactory route: AgentWorkforce/workforce

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions