Skip to the documentation

Documentation · v1

The .Worker file

Everything a .Worker file can contain, what each field means, and the rules the linter applies.

Status: v1 draft. You can write, format and lint .Worker files today in the viewer. Applying a file to the platform with agw apply is in development. Field names may still change before v1 is final.

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.

inbox-triage.Worker
apiVersion: agenticworkers.com/v1
kind: Worker
id: inbox-triage
name: 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: chat

The 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:

Fields every document has
FieldRequiredDescription
apiVersionYesAlways agenticworkers.com/v1.
kindYesOne of Worker, Assignment, Box.
idYesLowercase 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.
inbox-triage.Worker
# One worker and the client deployment that uses it.
apiVersion: agenticworkers.com/v1
kind: Worker
id: inbox-triage
# ...
---
apiVersion: agenticworkers.com/v1
kind: Assignment
id: inbox-triage-acme
worker: ./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.

Worker fields
FieldRequiredDescription
nameNoDisplay name. Safe to change.
versionNoVersion of this definition, such as 2.1.0.
fromNoA base worker to start from. Fields in this file override the base.
hostedNoSet to false for a worker that runs in chat only, without a machine. Defaults to true.
job.summaryNoOne sentence describing the job. The linter warns when it is missing.
job.done_whenNoHow a reviewer can tell a run succeeded.
job.stop_and_askNoSituations where the worker should stop and ask a person. These are instructions to the model. To enforce a limit, use policy.
interfaceNoThe output the worker produces: output.schema (a JSON Schema file) and artifacts (file types it saves).
model.idNoModel to use, or auto to let the platform choose.
model.providerNoopenrouter, bedrock. openai-codex and custom (with model.base_url) are accepted and applied as box configuration.
model.reasoning, fallback, max_turnsNoReasoning effort, fallback models, and the maximum number of steps per run.
instructions.soulNoPath to a Markdown file with the worker’s instructions, up to 50,000 characters.
instructions.memoryNo{ enabled: true } lets the worker keep notes between runs.
skillsNoSkills to install, by registry key and optional version.
connectionsNoThe accounts and tools the worker needs. See Connections.
policyNoWhat the worker may do with them. See Policy.
channelsNoWhere people talk to the worker: web, telegram, slack.
triggersNoWhat starts a run. See Triggers.
evalsNoA test suite and the pass rate a new version must reach.
dataNoRetention (retention.sessions: 90d) and fields to redact.
networkNoOutbound access: egress: limited with an allow list of hosts.
resourcesNoMemory 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.

needs, in kind: Worker
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
Connection fields
FieldRequiredDescription
idYesLocal name, unique in the worker.
viaYescomposio, mcp, env. env is a credential in an environment variable, used by command-line tools.
providerNoRequired for composio and mcp: the toolkit or MCP server name.
authNooauth, api_key, bearer, service_account, none, token
envNoRequired for env: the variable name, in uppercase.
checkNoA command that proves the credential works. Run before the worker starts.
scopesNoOAuth scopes to request.
tools.allowNoThe tools the worker may call. Required for MCP connections, because an empty list would expose every tool on the server.
requiredNoWhen true, the worker doesn’t start until this connection works.
on_missingNoblock, degrade, connect_link, fail, notify_owner
on_expiredNopause_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.

bindings, in kind: Assignment
bind:
crm:
owner: client
invite: { email: ops@acme.com, expires: 7d }
github:
secret: vault://box/ACME_GH_TOKEN
Who owns the account behind a connection
ownerWhose accountWho connects it
orgYour team’s shared accountThe team owner
agentAn account only this worker usesWhoever completes the connect link
clientYour client’s own accountThe client, through an invite link. No Agentic Workers login needed. Links expire in 1d, 7d, 30d.
userThe account of the person chattingEach 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 (agent and client), not both.
  • Each provider has one account per worker. Two Gmail accounts on one worker aren’t supported yet.
  • An invite requires owner: client or owner: 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
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
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. }
  • cron takes five fields: minute, hour, day of month, month, day of week.
  • every takes a number and a unit: 30s, 5m, 1h, 1d.
  • event names 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 sleep windows.

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.

acme.Worker
apiVersion: agenticworkers.com/v1
kind: Assignment
id: weekly-pipeline-acme
worker: agenticworkers/weekly-pipeline:2.1.0
team: acme-client
box: 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 } }
Assignment fields
FieldRequiredDescription
workerYesThe worker to deploy: a registry reference (agenticworkers/weekly-pipeline:2.1.0) or a file path (./weekly-pipeline.Worker).
teamNoThe team workspace the deployment belongs to. Required for hosted workers.
boxNoThe Box it runs on.
identity.sponsorNoThe person accountable for this deployment. Receives approvals and alerts.
identity.billingNoprovider or client: who pays.
bindNoAccount for each connection. See Binding accounts.
channelsNoChannel credentials for this deployment, such as a Telegram bot token reference.
secretsNoEnvironment variables from the vault. See Secrets.
overridesNoPer-client changes to worker fields, such as instructions.bootstrap with the client’s company notes.
budgetNousd_per_day and on_exceed: pause or alert.
storage.backupsNocadence (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.

provider-us-east.Worker
apiVersion: agenticworkers.com/v1
kind: Box
id: provider-us-east
team: northwind-ai
image: agw/hermes:fcd5e2c
region: iad
machine: { cpus: 4, memory: 8Gi }
volume: { size: 40Gi }
availability: always-on
assignments:
- ./acme.Worker
- ./globex.Worker
Box fields
FieldRequiredDescription
imageNoRuntime image, pinned to a version.
regionNoWhere the machine runs, such as iad.
machine.cpusNo1, 2, 4, 6, 8.
machine.memoryNoUp to 16Gi. The linter warns when the workers’ memory requests add up to more.
volume.sizeNoUp to 100Gi. Volumes can grow but not shrink, and growing one restarts the machine.
availabilityNoalways-on, or idle to sleep when unused and wake on the next message.
sleepNoA timezone and windows when the box sleeps.
telemetryNoWhere to send traces, such as an otlp endpoint.
assignmentsNoThe 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.

.Worker lint rules
RuleSeverityWhat it checks
yaml/syntaxerrorThe file must be valid YAML.
doc/api-versionerrorEvery document declares apiVersion: agenticworkers.com/v1.
doc/kinderrorkind is Worker, Assignment or Box.
doc/iderrorid is required, lowercase, and unique in the file. It never changes when the name does.
doc/unknown-keywarningTop-level keys must be known for the kind. Close misspellings get a suggestion.
job/summarywarningA Worker states its job in one sentence.
model/providerwarningopenai-codex and custom providers are applied as box config, not stored by the platform yet.
connection/shapeerrorEach connection has an id, a via of composio, mcp or env, and the fields that via needs.
connection/allow-listerrorAn MCP connection lists the tools it may use. An empty list would expose every tool.
connection/enumerrorauth, on_missing and on_expired use the documented values.
policy/ruleerrorpolicy.default is allow or deny, and each rule is allow, require_approval, forbid or require.
policy/unknown-connectionwarningA dotted tool reference starts with a declared connection id.
trigger/shapeerrorEach trigger has an id and exactly one of cron, every, event or webhook.
trigger/cronerrorcron has five fields; every is a number and a unit (5m, 1h).
trigger/deliverwarningdeliver is chat, telegram, chat_and_telegram or none.
trigger/event-connectionerrorAn event trigger names a declared connection.
secret/inlineerrorSecret values never appear in the file. Use vault://box/NAME.
secret/nameerrorSecret names are uppercase and avoid reserved prefixes (AGW_, HERMES_, COMPOSIO, GATEWAY_, API_SERVER_, BOX_GATEWAY).
secret/agent-scopewarningvault://agent/ references are not supported by the platform yet.
bind/unknown-connectionerrorAn Assignment binds only connections its Worker declares.
bind/missingerrorAn Assignment binds every required connection.
bind/mixed-ownerserrorComposio connections on one worker share one owner: org, or agent and client. The platform uses one Composio account set per agent.
bind/inviteerrorClient invites need owner client or agent, and expire in 1d, 7d or 30d.
box/machineerrorBox cpus are 1, 2, 4, 6 or 8, memory is at most 16Gi, and volumes are at most 100Gi.
box/capacitywarningWorker memory requests on a box fit inside its machine memory.
resources/limitserrorA memory limit is at least the memory request.
value/todowarningTODO values must be filled in before apply.

Commands

The agw command line tool is in development. These are the planned commands:

Planned commands
CommandDescription
agw validateRun the same checks as the viewer.
agw planCheck that every required connection is connected, then list what would change and whether anything restarts.
agw applyMake the change. Nothing restarts when nothing changed.
agw push / pullShare workers through a registry, with versions.
agw exportWrite a .Worker file from a worker that is already running.