Documentation · v1
The .Worker file
Everything a .Worker file can contain, what each field means, and the rules the linter applies.
Overview
A .Worker file defines an agentic worker: an AI agent with a recurring job, the accounts it acts through, limits on what it may do, what starts each run, and a person who answers for its results.
The format is YAML. A file can describe three things, each as its own document:
- Worker: the definition. It contains no account ids and no machine settings, so the same worker can be deployed for many clients.
- Assignment: one deployment of a worker. It says whose accounts fill each connection, who approves risky actions, and the budget.
- Box: the machine that runs one or more assignments.
Quick start
The smallest useful worker has an id, a job, the connections it needs, what it may do with them, and a trigger. Copy this into the viewer to see it checked.
apiVersion: agenticworkers.com/v1kind: Workerid: inbox-triagename: Inbox Triage job: summary: Label new support email and draft a reply for a person to approve. done_when: Every new email has a label and a draft reply. connections: - id: mail provider: gmail via: composio auth: oauth required: true tools: { allow: [GMAIL_FETCH_EMAILS, GMAIL_ADD_LABEL_TO_EMAIL, GMAIL_CREATE_EMAIL_DRAFT] } policy: default: deny rules: - allow: [mail.GMAIL_FETCH_EMAILS, mail.GMAIL_ADD_LABEL_TO_EMAIL] - require_approval: [mail.GMAIL_CREATE_EMAIL_DRAFT] triggers: - id: every-15-minutes every: 15m run: { prompt: Triage new email since the last run. } deliver: chatThe worker can read and label email on its own, but a person approves every draft before it’s created. It can’t touch anything outside the mail connection, because policy.default is deny.
File structure
Name files with the .Worker extension. A file holds one or more YAML documents separated by a line containing only ---. Every document starts with the same three fields:
| Field | Required | Description |
|---|---|---|
| apiVersion | Yes | Always agenticworkers.com/v1. |
| kind | Yes | One of Worker, Assignment, Box. |
| id | Yes | Lowercase letters, digits and dashes, up to 63 characters, unique in the file. The id never changes, even when the name does, so the platform can always match a document to what is running. |
# One worker and the client deployment that uses it.apiVersion: agenticworkers.com/v1kind: Workerid: inbox-triage# ... ---apiVersion: agenticworkers.com/v1kind: Assignmentid: inbox-triage-acmeworker: ./inbox-triage.Worker# ...kind: Worker
The definition of the worker. It describes what the worker needs and is allowed to do, never whose accounts it uses.
| Field | Required | Description |
|---|---|---|
| name | No | Display name. Safe to change. |
| version | No | Version of this definition, such as 2.1.0. |
| from | No | A base worker to start from. Fields in this file override the base. |
| hosted | No | Set to false for a worker that runs in chat only, without a machine. Defaults to true. |
| job.summary | No | One sentence describing the job. The linter warns when it is missing. |
| job.done_when | No | How a reviewer can tell a run succeeded. |
| job.stop_and_ask | No | Situations where the worker should stop and ask a person. These are instructions to the model. To enforce a limit, use policy. |
| interface | No | The output the worker produces: output.schema (a JSON Schema file) and artifacts (file types it saves). |
| model.id | No | Model to use, or auto to let the platform choose. |
| model.provider | No | openrouter, bedrock. openai-codex and custom (with model.base_url) are accepted and applied as box configuration. |
| model.reasoning, fallback, max_turns | No | Reasoning effort, fallback models, and the maximum number of steps per run. |
| instructions.soul | No | Path to a Markdown file with the worker’s instructions, up to 50,000 characters. |
| instructions.memory | No | { enabled: true } lets the worker keep notes between runs. |
| skills | No | Skills to install, by registry key and optional version. |
| connections | No | The accounts and tools the worker needs. See Connections. |
| policy | No | What the worker may do with them. See Policy. |
| channels | No | Where people talk to the worker: web, telegram, slack. |
| triggers | No | What starts a run. See Triggers. |
| evals | No | A test suite and the pass rate a new version must reach. |
| data | No | Retention (retention.sessions: 90d) and fields to redact. |
| network | No | Outbound access: egress: limited with an allow list of hosts. |
| resources | No | Memory request (memory: 2Gi) and limit (limits.memory). The limit must be at least the request. |
Connections
A worker that looks healthy but has no connected accounts fails on its first tool call. Connections are declared in two halves so that never happens silently:
- The Worker lists what it needs: a provider, how it signs in, which tools it may call, and whether it can run without it.
- The Assignment binds each need to a real account.
Skills, policy rules and triggers refer to a connection by its id, never by a vendor or an account.
connections: - id: crm # the name skills, policy and triggers use provider: hubspot # Composio toolkit or MCP registry name via: composio auth: oauth scopes: [crm.objects.deals.read] tools: { allow: [HUBSPOT_LIST_DEALS, HUBSPOT_GET_DEAL] } required: true on_missing: block on_expired: pause_and_notify - id: github # a CLI credential via: env env: GH_TOKEN check: gh auth status # readiness probe required: true| Field | Required | Description |
|---|---|---|
| id | Yes | Local name, unique in the worker. |
| via | Yes | composio, mcp, env. env is a credential in an environment variable, used by command-line tools. |
| provider | No | Required for composio and mcp: the toolkit or MCP server name. |
| auth | No | oauth, api_key, bearer, service_account, none, token |
| env | No | Required for env: the variable name, in uppercase. |
| check | No | A command that proves the credential works. Run before the worker starts. |
| scopes | No | OAuth scopes to request. |
| tools.allow | No | The tools the worker may call. Required for MCP connections, because an empty list would expose every tool on the server. |
| required | No | When true, the worker doesn’t start until this connection works. |
| on_missing | No | block, degrade, connect_link, fail, notify_owner |
| on_expired | No | pause_and_notify, connect_link, ignore |
Binding accounts
In an Assignment, bind maps each connection id to an account. Every required connection must be bound, and only connections the worker declares may be.
bind: crm: owner: client invite: { email: ops@acme.com, expires: 7d } github: secret: vault://box/ACME_GH_TOKEN| owner | Whose account | Who connects it |
|---|---|---|
| org | Your team’s shared account | The team owner |
| agent | An account only this worker uses | Whoever completes the connect link |
| client | Your client’s own account | The client, through an invite link. No Agentic Workers login needed. Links expire in 1d, 7d, 30d. |
| user | The account of the person chatting | Each user. Chat workers only. |
Current limits, enforced by the linter:
- A worker’s Composio connections use either your team’s accounts (
org) or its own (agentandclient), not both. - Each provider has one account per worker. Two Gmail accounts on one worker aren’t supported yet.
- An invite requires
owner: clientorowner: agent.
Policy
Policy is enforced; job.stop_and_ask is only advice to the model. default is allow or deny. Each rule has exactly one of allow, require_approval, forbid, require. Tools are written as connection.TOOL, and * matches any characters.
policy: default: deny rules: - allow: [crm.HUBSPOT_LIST_DEALS, crm.HUBSPOT_GET_DEAL] - require_approval: [crm.HUBSPOT_UPDATE_DEAL] - forbid: [mail.GMAIL_SEND_EMAIL] - require: { tools: [mailchimp.schedule], lead_time: ">= 12h" }When rules overlap, forbid wins over require_approval, which wins over allow. Approvals go to the Assignment’s identity.sponsor. unattended: same applies the same rules to scheduled runs, where nobody is watching.
Triggers
Each trigger has a stable id and exactly one of cron, every, event, webhook. run has exactly one of prompt, skill, script. deliver sends the result to chat, telegram, chat_and_telegram, none.
triggers: - id: monday-summary cron: "0 8 * * 1" run: { skill: crm-weekly-summary } deliver: chat - id: board-check every: 5m run: { script: ./probes/board.py } - id: deal-won event: { connection: crm, type: HUBSPOT_DEAL_STAGE_CHANGED } run: { prompt: Add this deal to the current summary draft. }crontakes five fields: minute, hour, day of month, month, day of week.everytakes a number and a unit:30s,5m,1h,1d.eventnames a declared connection and an event type from that provider.- A trigger can set its own
model, for example a cheaper model for a frequent check. - Schedules don’t run while the box is asleep. Check the Box’s
sleepwindows.
kind: Assignment
One deployment of a worker for one client or team. Use one Assignment per client, so each client has separate accounts, approvals, spend and backups.
apiVersion: agenticworkers.com/v1kind: Assignmentid: weekly-pipeline-acmeworker: agenticworkers/weekly-pipeline:2.1.0team: acme-clientbox: provider-us-east identity: { sponsor: ops@acme.com, billing: provider } bind: crm: { owner: client, invite: { email: ops@acme.com, expires: 7d } } secrets: HUBSPOT_PORTAL_ID: vault://box/ACME_HUBSPOT_PORTAL_ID budget: { usd_per_day: 15, on_exceed: pause }storage: backups: { cadence: daily, hour_utc: 3, keep: { count: 7, days: 30 } }| Field | Required | Description |
|---|---|---|
| worker | Yes | The worker to deploy: a registry reference (agenticworkers/weekly-pipeline:2.1.0) or a file path (./weekly-pipeline.Worker). |
| team | No | The team workspace the deployment belongs to. Required for hosted workers. |
| box | No | The Box it runs on. |
| identity.sponsor | No | The person accountable for this deployment. Receives approvals and alerts. |
| identity.billing | No | provider or client: who pays. |
| bind | No | Account for each connection. See Binding accounts. |
| channels | No | Channel credentials for this deployment, such as a Telegram bot token reference. |
| secrets | No | Environment variables from the vault. See Secrets. |
| overrides | No | Per-client changes to worker fields, such as instructions.bootstrap with the client’s company notes. |
| budget | No | usd_per_day and on_exceed: pause or alert. |
| storage.backups | No | cadence (daily or weekly), hour_utc, and keep (count and days). |
kind: Box
The machine that runs assignments. One Box can run several workers; each gets its own process, files and schedules.
apiVersion: agenticworkers.com/v1kind: Boxid: provider-us-eastteam: northwind-aiimage: agw/hermes:fcd5e2cregion: iadmachine: { cpus: 4, memory: 8Gi }volume: { size: 40Gi }availability: always-onassignments: - ./acme.Worker - ./globex.Worker| Field | Required | Description |
|---|---|---|
| image | No | Runtime image, pinned to a version. |
| region | No | Where the machine runs, such as iad. |
| machine.cpus | No | 1, 2, 4, 6, 8. |
| machine.memory | No | Up to 16Gi. The linter warns when the workers’ memory requests add up to more. |
| volume.size | No | Up to 100Gi. Volumes can grow but not shrink, and growing one restarts the machine. |
| availability | No | always-on, or idle to sleep when unused and wake on the next message. |
| sleep | No | A timezone and windows when the box sleeps. |
| telemetry | No | Where to send traces, such as an otlp endpoint. |
| assignments | No | The Assignment files this box runs. |
Secrets
Secret values never go in a .Worker file. Store them in your workspace vault and reference them as vault://box/NAME. That way a file can be committed, shared and reviewed safely.
- Names use uppercase letters, digits and underscores.
- Names can’t start with a reserved prefix:
AGW_,HERMES_,COMPOSIO,GATEWAY_,API_SERVER_,BOX_GATEWAY. - The linter flags values that look like tokens or keys, such as
sk-…,ghp_…, Slack tokens, AWS keys and JWTs.
Formatting
The formatter produces one canonical form, so diffs show real changes only. Format in the viewer with the Format button or Cmd+S.
- Two-space indentation, and one
---between documents. - Top-level keys in a fixed order per kind. For a Worker:
apiVersion,kind,id,name,version,from,hosted,scope,description, and so on. - Every comment is kept. Trailing comments in a block are aligned to one column.
- Lines wrap at 100 characters. Formatting an already formatted file changes nothing.
Lint rules
The viewer runs these checks as you type. Errors must be fixed before a file can be applied. Warnings point at things that work today but are likely mistakes or not fully supported yet.
| Rule | Severity | What it checks |
|---|---|---|
| yaml/syntax | error | The file must be valid YAML. |
| doc/api-version | error | Every document declares apiVersion: agenticworkers.com/v1. |
| doc/kind | error | kind is Worker, Assignment or Box. |
| doc/id | error | id is required, lowercase, and unique in the file. It never changes when the name does. |
| doc/unknown-key | warning | Top-level keys must be known for the kind. Close misspellings get a suggestion. |
| job/summary | warning | A Worker states its job in one sentence. |
| model/provider | warning | openai-codex and custom providers are applied as box config, not stored by the platform yet. |
| connection/shape | error | Each connection has an id, a via of composio, mcp or env, and the fields that via needs. |
| connection/allow-list | error | An MCP connection lists the tools it may use. An empty list would expose every tool. |
| connection/enum | error | auth, on_missing and on_expired use the documented values. |
| policy/rule | error | policy.default is allow or deny, and each rule is allow, require_approval, forbid or require. |
| policy/unknown-connection | warning | A dotted tool reference starts with a declared connection id. |
| trigger/shape | error | Each trigger has an id and exactly one of cron, every, event or webhook. |
| trigger/cron | error | cron has five fields; every is a number and a unit (5m, 1h). |
| trigger/deliver | warning | deliver is chat, telegram, chat_and_telegram or none. |
| trigger/event-connection | error | An event trigger names a declared connection. |
| secret/inline | error | Secret values never appear in the file. Use vault://box/NAME. |
| secret/name | error | Secret names are uppercase and avoid reserved prefixes (AGW_, HERMES_, COMPOSIO, GATEWAY_, API_SERVER_, BOX_GATEWAY). |
| secret/agent-scope | warning | vault://agent/ references are not supported by the platform yet. |
| bind/unknown-connection | error | An Assignment binds only connections its Worker declares. |
| bind/missing | error | An Assignment binds every required connection. |
| bind/mixed-owners | error | Composio connections on one worker share one owner: org, or agent and client. The platform uses one Composio account set per agent. |
| bind/invite | error | Client invites need owner client or agent, and expire in 1d, 7d or 30d. |
| box/machine | error | Box cpus are 1, 2, 4, 6 or 8, memory is at most 16Gi, and volumes are at most 100Gi. |
| box/capacity | warning | Worker memory requests on a box fit inside its machine memory. |
| resources/limits | error | A memory limit is at least the memory request. |
| value/todo | warning | TODO values must be filled in before apply. |
Commands
The agw command line tool is in development. These are the planned commands:
| Command | Description |
|---|---|
| agw validate | Run the same checks as the viewer. |
| agw plan | Check that every required connection is connected, then list what would change and whether anything restarts. |
| agw apply | Make the change. Nothing restarts when nothing changed. |
| agw push / pull | Share workers through a registry, with versions. |
| agw export | Write a .Worker file from a worker that is already running. |