defineAgent carries the agent’s LLM binding and its behavioral settings:
agents/qualifier.ts
Every agent needs both
connector and languageModel — defineAgent
throws at plan time if either is missing. The connector’s integration
(OpenAI, Anthropic, …) determines which model slugs are valid. A harness
only accepts connectors and models that list that runtime (Anthropic for
Claude Code / OpenCode / Deep Agents, OpenAI gpt-5* for Codex).Coding agents
A coding agent runs inside a sandbox with a cloned repository. Setharness to the runtime (claudeCode, codex, openCode, or deepAgents) and repository to control what the sandbox clones.
Automatic repository binding
Omitrepository and plan/deploy fill it from the checkout they run in — the owner/name of your git origin, the remote’s default branch, and this project’s path inside the repo — with the connector taken from the project’s GitHub defineConnector:
connectors/github.ts
connectors/anthropic.ts
agents/coder.ts
plan prints what it resolved (e.g. agent:coder bound to acme/app#main in infra/) and the resolved values are inside the content hash, so deploying the same code from a different repository is a real update.
Edge cases
Opting out
Passrepository: null to force an unbound agent whatever the checkout says:
Selecting a model
Theconnector handle picks the provider; languageModel picks the model slug within it. Cargo supports the leading LLM providers — OpenAI, Anthropic, and Google Gemini among them — each behind its own connector.
List the model slugs a provider currently exposes rather than hardcoding from memory:
Behavioral parameters
Reasoning steps (maxSteps)
The maximum number of logical sub-tasks the agent can perform to reach a conclusion. Defaults to 8.
Temperature
Controls the creativity and variability of outputs. Defaults to0.2.
Extended thinking (withReasoning)
withReasoning: true lets the model think through the problem before acting — better on hard multi-step tasks, at the cost of latency and tokens. Defaults to false.
Structured output
By default an agent answers in free text (output: { type: "text" }). To make every final answer machine-parseable — for workflows or API consumers downstream — declare a JSON Schema contract:
Evaluator
Theevaluator is an LLM-as-judge that scores each of the agent’s outputs against a natural-language rubric:
threshold are flagged, so you can spot quality regressions without reading every conversation. Pair it with prompt iterations: change the systemPrompt, re-deploy, and compare evaluator pass rates.
Triggers
Agents normally respond to messages, buttriggers make them start work on their own:
connector trigger references its connector by handle or connectorRef(uuid); config is integration-specific. agentConnectorTrigger types that config against the integration’s schema, which a bare object literal can’t do — TypeScript won’t infer a per-element type through an array. A defineConnector handle names its integration, so the helper reads it from there; pass integration: "slack" yourself when there’s no handle to read it from, either because you’re using connectorRef(uuid) or because the trigger names an integration with no specific connector.
The bare form still works, with config left as a loose object:
Heartbeat
Aheartbeat wakes the agent up on an interval inside an ongoing chat — useful for long-running missions that should make progress without a human prompting each turn:
Optimizing for cost and speed
Once your agent works correctly, consider:- Reduce
maxStepsif tasks complete in fewer steps - Try a faster model and verify quality remains acceptable (the
evaluatorpass rate is the signal) - Lower
temperaturefor more predictable outputs - Limit resources to reduce context size and processing time

