Platform Pipelines Agents Human review Self-improvement Observability Deployment Security Use cases Compare Docs Pricing Roadmap Get early access

Agents

In Millstream an LLM agent is an action like any other. It declares its prompt, its model, the schema of its answer and what it may touch, and the platform does the rest: rendering, sandboxing, validation, cost, transcripts and tests.


The manifest

An agent action is a directory with an action.yaml, a prompt.md and JSON Schemas for its input, output and config.

name: lab/score-listing
version: 2.1.0
description: Scores a listing for renovation potential
kind: agent
effects: none
input:  { $ref: schema/input.json }
output: { $ref: schema/output.json }
runtime:
  agent:
    harness: claude-code
    model: claude-sonnet-5-5
    prompt: prompt.md
    tools: [WebFetch]
    mcp: []
    network: [api.anthropic.com]
    maxTurns: 20
    maxCostUsd: 0.50

For each item, the agent adapter renders prompt.md with the payload, the config, the variables and the step's lessons, runs the harness, obtains a structured answer and validates it against the output schema. An answer that does not match is a retryable error and never reaches the next step. Each answer is emitted with its metrics: tokens in and out, cost, turns and duration, labelled with the model.


Answers are untrusted input

Crawled pages and documents reach agents, and a page can steer a model. Millstream treats every answer as data from outside the system.


Any harness, any model behind it

The engine never knows which model ran. The adapter speaks the action protocol on one side and drives a harness on the other.

Harness Runs
claude-code Claude Code in headless mode, the manifest's tools and MCP servers as an explicit allowlist, the output schema enforced natively
api A direct model call: Anthropic's Messages API, or any OpenAI-compatible endpoint such as Mistral or a local model, set with provider and baseUrl

Agents can also abstain. An output schema that allows {"abstain": "<why>"} lets the model hand an item it is unsure of to the step's fallback, such as a stronger model or a person.


Open-ended work, inside one step

Some work has no fixed plan: searching, reading documents, writing and running code until a result holds. With the claude-code harness, an agent step does that work with the tools its manifest lists, such as Bash, Read and WebFetch, inside its sandbox and with the interpreters its sandbox image holds, for up to maxTurns turns and maxCostUsd. The pipeline around it stays a fixed graph that millstream check validates, and the step's final answer passes the output schema like any other. The api harness makes one model call per item; its tool loop is on the roadmap.


A sandbox per call

Agents run per item, in a fresh container, so no context leaks between items.


Budgets that stop spending

Cost is taken from the harness when it reports it, otherwise computed from token counts and the price table in the environment file.

budget:
  runUsd: 25
  dayUsd: 120

Transcripts for every attempt

The full transcript of each attempt, prompts, tool calls, results and the final answer, is stored compressed in the artifact store and shown on the item's page. A failed attempt keeps its transcript too, and its error points to it. Every secret value of the pipeline is redacted from every string, the harness's own records included. Transcripts have their own retention.


Evals, and tests that never call a model

An agent action ships an evals/ directory of cases: an input, assertions in CEL, and optionally an LLM judge with a rubric. millstream eval scores each case, records the scores against the action's digest, and shows the previous score beside each one, so a prompt or model change is compared before it ships.

name: renovated flat
input: { url: https://example.com/listings/2 }
assert:
  - output.score < 30
judge:
  rubric: The score reflects the recent renovation.
  model: claude-haiku-5-5

Every harness call can be recorded and replayed. A recording is keyed by the harness, the model, the rendered prompt and the output schema, so tests and evals in CI run offline, need no API key, and are deterministic. Editing a lessons file changes the prompt and misses the old recording, so a stale answer is never replayed.

millstream eval ./actions/score-listing
millstream test action ./actions/score-listing --harness-mode replay

Lessons from past runs

Each agent step can carry a lessons file of rules and corrected examples, each citing where it came from: a reviewer's edit, an insight, an accepted proposal. Lessons belong to the step, not the action, so a shared action learns what is specific to each pipeline. The file is part of the revision, so replay stays deterministic.

rules:
  - text: Listings without a surface area are not scored; return score 0 and reason "missingSurface".
    source: proposal/p-0142
examples:
  - input: { … }
    output: { … }
    why: "Reviewer lowered the score: ground-floor flats on a main road."
    source: review/r-8812

Next

How pipelines learn Human review Security