The agent() step

Hand a prompt to the Claude Code session driving the run and get back a typed, schema-validated result.

agent(name, opts, fn) is the inverse of a connector. Instead of calling out to a service, the run parks (WAITING_AGENT) and asks the driving Claude Code session to run a prompt and return a typed result. The handler is required and receives the answer as data.result.

Prerequisite: channels must be set up

An agent() step only works when Claude Code channels are configured and the run is started from a Claude Code session with a channel attached (flowctl run start … —channel <id>). That’s how the prompt reaches an agent. Without a live channel the run parks at WAITING_AGENT with no one to answer it — set up channels first. Support for OpenAI Codex as the driving editor is in progress.

agent("triage", {
  prompt: "Classify ticket {{ticket_id}}: {{subject}}. Return {category, severity}.",
  resultType: "json",                 // "json" | "text" (default "text")
  context: ["ticket_id", "subject"],  // REQUIRED allowlist of vars sent as context
  resultSchema: {                     // optional; validates a json result
    type: "object",
    required: ["category", "severity"],
    properties: { category: { type: "string" }, severity: { type: "string" } },
  },
  onError: "triage_failed",           // optional; route here if the agent reports an error
  next: "route",
}, function onTriage(ctx, data) {
  return { category: data.result.category, severity: data.result.severity };
});

How it behaves

  • prompt is {{var}}-templated against the run’s variables.
  • context is an explicit allowlist — only those variables are sent with the prompt. Omit it and nothing is sent.
  • resultType "json" makes data.result an object (validated against resultSchema if present); "text" makes it a string.
  • The agent answers from the shell:
flowctl agent list <exec>
flowctl agent get  <exec> triage                                  # prompt, result_type, context, schema
flowctl agent submit <exec> triage --type json --result '{"category":"auth","severity":"high"}'
flowctl agent submit <exec> triage --error 'could not classify'   # routes to onError
context is a required allowlist

If you don’t list the variables the prompt needs in context, the agent receives no context and will guess. Always include every variable the prompt interpolates or relies on.

When to use it

Use agent() for the judgement steps in an otherwise deterministic workflow — classify, extract, summarize, decide — when the run is being driven interactively by Claude Code. It keeps no model credentials in the workflow and lets a human or agent supply the answer.

For unattended automation (a scheduled job, a webhook with no human present), call a model directly with the LLM connector instead.

How the prompt reaches an agent

The mechanism is the Claude Code channel bridge. When you start a run with --channel <id> from a session running the bridge, the engine pushes the prompt (and its allowlisted context) into that session as a <channel interaction="agent"> event; the agent does the work and submits the result. This isn’t optional polish — it’s how an agent() step is answered at all. Set up channels before relying on agent() in a workflow.

Next: Claude Code channels.