team.yaml reference
The team config lives at .outstaff/team.yaml in your repository. For a prose tour of the sections, see Team config. Problems found by ost validate are listed in Validation codes. The same schema is published as JSON Schema in packages/core/schema/team.schema.json.
Paths use [] for list items and <key> for a map entry whose key you choose.
Only the office loads this file. Each agent receives it from the office when it connects, whole, so it holds no secrets: fields such as people[].network.http[].token name a secret, and each container reads the value from its own secrets.
Example
Section titled “Example”A complete file for the synthetic team “acme”.
# Synthetic example: the "acme" team does not exist. All names, handles,# addresses and URLs below are made up. It is used by tests and docs.
# Schema version of this file; currently 1.version: 1
# Who the team is.team: name: acme product: Acme Shop description: The team that builds and runs Acme Shop.
# Trusted humans. Optional; when omitted, trusted humans are repo writers and full chat-workspace members.humans: - name: Ada Admin identities: vcs: ada-admin tracker: ada.admin chat: U0ADA0001 email: ada@acme.example - name: Grace Lead identities: vcs: grace-lead chat: U0GRACE02
# Which catalog of roles and skills the team uses.catalog: version: 0.0.0
# Repositories the team works in; at least one.repos: - name: shop url: github.com/acme-example/shop kind: primary checks: - pnpm lint - pnpm vitest related --run - name: infra url: github.com/acme-example/infra kind: infra - name: design-system url: github.com/acme-example/design-system kind: baseline - name: docs-site url: github.com/acme-example/docs-site kind: other
# The agents on the team; may be empty.people: - handle: priya name: Priya Raman pronouns: she/her role: pm model: sonnet identities: vcs: acme-priya[bot] chat: U0PRIYA03 tracker: priya.raman repos: "*": read docs-site: write - handle: tomas name: Tomas Novak pronouns: he/him role: product model: sonnet identities: vcs: acme-tomas[bot] chat: U0TOMAS04 tracker: tomas.novak repos: "*": read docs-site: write - handle: mira name: Mira Okafor pronouns: she/her role: architect model: opus extends: [developer] identities: vcs: acme-mira[bot] chat: U0MIRA005 tracker: mira.okafor repos: shop: write "kind:baseline": read - handle: leo name: Leo Fischer pronouns: he/him role: designer model: sonnet identities: chat: U0LEO0006 tracker: leo.fischer - handle: sam name: Sam Duarte pronouns: they/them role: developer model: sonnet identities: vcs: acme-sam[bot] chat: U0SAM0007 tracker: sam.duarte repos: shop: write "kind:baseline": read - handle: noor name: Noor Haddad pronouns: she/her role: developer model: sonnet identities: vcs: acme-noor[bot] chat: U0NOOR008 tracker: noor.haddad repos: shop: write "kind:baseline": read - handle: ines name: Ines Varga pronouns: she/her role: reviewer model: sonnet identities: vcs: acme-ines[bot] chat: U0INES009 tracker: ines.varga repos: "*": read - handle: kofi name: Kofi Mensah pronouns: he/him role: devops model: sonnet identities: vcs: acme-kofi[bot] chat: U0KOFI010 tracker: kofi.mensah repos: infra: write shop: read
# Which adapters connect Outstaff to your tools.integrations: chat: adapter: slack vcs: adapter: github runtime: adapter: claude-agent-sdk tracker: adapter: itsaplan url: https://tracker.acme.example project: SHOP knowledge: adapter: itsaplan avatars: adapter: dicebear style: notionists
# Where agents keep their memory: the lasting lessons and preferences they note.memory: # Each agent's notes on a page of its own in the knowledge integration. The default, volume, keeps them in memory/ on # each agent's home volume, which you then back up. store: knowledge
# How the tracker's statuses and labels map onto outstaff's.workflow: statuses: backlog: Backlog ready: Ready active: In Progress review: In Review blocked: Blocked done: Done canceled: Canceled
# Team-wide guardrails, message style and switches for what outstaff does on its own.policies: # What outstaff does on its own. Everything below is on by default; set a switch to false (or none) to turn it off. acknowledge: chat: true vcs: true chat: profile: true design: canvas: true feedback: follow_up_round: true hand_back: fallback: first_human tickets: prs_per_ticket: one messages: max_lines: 3 # Event pipeline policies of the team's own, loaded from this repository. See "Writing a policy" in the docs. custom: - module: ./policies/release-freeze.ts settings: until: "2026-12-01T00:00:00Z" label: hotfixFields
Section titled “Fields”version
Section titled “version”Schema version of this file; currently 1.
- Type:
number - Required
- Must be
1
Who the team is.
- Type:
object - Required
team.name
Section titled “team.name”Team slug: lowercase letters, digits and dashes, starting with a letter.
- Type:
string - Required
- Minimum length 1
- Maximum length 40
- Must match
^[a-z][a-z0-9-]*$
team.product
Section titled “team.product”Name of the product the team builds.
- Type:
string - Optional
team.description
Section titled “team.description”One-line description of the team.
- Type:
string - Optional
humans
Section titled “humans”Trusted humans. Optional; when omitted, trusted humans are repo writers and full chat-workspace members.
- Type:
list of object - Optional
humans[]
Section titled “humans[]”A trusted human.
- Type:
object - Optional
humans[].name
Section titled “humans[].name”Display name of the trusted human.
- Type:
string - Required
- Minimum length 1
humans[].identities
Section titled “humans[].identities”How this human is known on each connected system; at least one is required.
- Type:
object - Required
humans[].identities.vcs
Section titled “humans[].identities.vcs”Username on the VCS host.
- Type:
string - Optional
- Minimum length 1
humans[].identities.tracker
Section titled “humans[].identities.tracker”Username or id in the issue tracker.
- Type:
string - Optional
- Minimum length 1
humans[].identities.chat
Section titled “humans[].identities.chat”Username or id in the chat workspace.
- Type:
string - Optional
- Minimum length 1
humans[].identities.email
Section titled “humans[].identities.email”Email address.
- Type:
string - Optional
- Minimum length 1
catalog
Section titled “catalog”Which catalog of roles and skills the team uses.
- Type:
object - Required
catalog.version
Section titled “catalog.version”Exact catalog release this team uses, for example “1.0.0”; must match the catalog in the agent images.
- Type:
string - Required
- Minimum length 1
catalog.path
Section titled “catalog.path”Directory of ejected catalog files, relative to this file.
- Type:
string - Optional
- Default:
catalog - Minimum length 1
Repositories the team works in; at least one.
- Type:
list of object - Required
- Minimum items 1
repos[]
Section titled “repos[]”A repository the team works in.
- Type:
object - Optional
repos[].name
Section titled “repos[].name”Short name used to refer to this repository in grants.
- Type:
string - Required
- Minimum length 1
- Maximum length 40
- Must match
^[a-z][a-z0-9-]*$
repos[].url
Section titled “repos[].url”Repository location: host/owner/repo, an https URL or a git@ address.
- Type:
string - Required
- Must match
^(https?:\/\/\S+|git@\S+:\S+|[A-Za-z0-9.-]+\/[\w.-]+\/[\w.-]+)$
repos[].kind
Section titled “repos[].kind”Role of the repository: primary (the product, at most one), baseline, infra or other.
- Type:
string - Required
- Allowed values:
primary,baseline,infra,other
repos[].default_branch
Section titled “repos[].default_branch”Branch that pull requests target.
- Type:
string - Optional
- Default:
main - Minimum length 1
repos[].checks
Section titled “repos[].checks”Commands an agent runs before pushing, covering only what a change affects (for example lint and the tests related to changed files). CI runs the full suite. When omitted, agents work out the affected checks themselves.
- Type:
list of string - Optional
- Minimum items 1
repos[].checks[]
Section titled “repos[].checks[]”- Type:
string - Optional
- Minimum length 1
repos[].conventions
Section titled “repos[].conventions”How work is done in this repository, as free text: commits, branches, pull request title and body, tests. For repositories whose own files (CONTRIBUTING.md, AGENTS.md, the pull request template) cannot say it. Agents read it in addition to those files.
- Type:
string - Optional
- Minimum length 1
repos[].ticket_link
Section titled “repos[].ticket_link”Extra ways this repository’s pull request body names its ticket, as regular expressions with one {key} placeholder for the ticket key (for example Ticket: {key}). A pull request is always linked by the ticket key in its branch name, its title, or a closing keyword in its body (Closes ACME-12); these patterns add to the last. A key mentioned in the body in any other way links nothing.
- Type:
list of string - Optional
- Minimum items 1
repos[].ticket_link[]
Section titled “repos[].ticket_link[]”- Type:
string - Optional
- Minimum length 1
- Maximum length 200
repos[].instructions
Section titled “repos[].instructions”Extra files in this repository that agents read before they work, relative to its root, for example [“CLAUDE.md”]. A project CLAUDE.md is not loaded into agent sessions unless it is listed here.
- Type:
list of string - Optional
- Minimum items 1
repos[].instructions[]
Section titled “repos[].instructions[]”- Type:
string - Optional
- Minimum length 1
repos[].tracker
Section titled “repos[].tracker”Which tracker tickets this repository serves. Agents use it to decide where a ticket’s work goes when the ticket does not name a repository.
- Type:
object - Optional
repos[].tracker.labels
Section titled “repos[].tracker.labels”Ticket labels that mean the work belongs in this repository.
- Type:
list of string - Required
- Minimum items 1
repos[].tracker.labels[]
Section titled “repos[].tracker.labels[]”- Type:
string - Optional
- Minimum length 1
people
Section titled “people”The agents on the team; may be empty.
- Type:
list of object - Required
people[]
Section titled “people[]”An AI agent on the team.
- Type:
object - Optional
people[].handle
Section titled “people[].handle”Unique lowercase handle; used as the agent’s hostname label and mention name.
- Type:
string - Required
- Minimum length 1
- Maximum length 30
- Must match
^[a-z][a-z0-9-]*$
people[].name
Section titled “people[].name”Display name of the agent.
- Type:
string - Required
- Minimum length 1
people[].pronouns
Section titled “people[].pronouns”Pronouns shown in the agent’s profile.
- Type:
string - Optional
people[].role
Section titled “people[].role”Catalog role this agent plays, for example “developer”.
- Type:
string - Required
- Minimum length 1
people[].extends
Section titled “people[].extends”Extra catalog roles or skill bundles layered on top of the role.
- Type:
list of string - Optional
people[].extends[]
Section titled “people[].extends[]”- Type:
string - Optional
- Minimum length 1
people[].model
Section titled “people[].model”LLM model this agent runs on, as the runtime adapter names it, for example “sonnet”. Required: there is no default model.
- Type:
string - Required
- Minimum length 1
people[].runtime
Section titled “people[].runtime”Runtime adapter for this agent, in the same shape as integrations.runtime: adapter and that adapter’s options. It replaces the team’s runtime for this agent as a whole (options are not merged); integrations.runtime when omitted.
- Type:
object - Optional
people[].runtime.adapter
Section titled “people[].runtime.adapter”Name of the adapter package to use, for example “github”.
- Type:
string - Required
- Minimum length 1
people[].identities
Section titled “people[].identities”How this agent is known on each connected system. The office recognizes the agent’s own activity only by an exact match with these.
- Type:
object - Optional
people[].identities.vcs
Section titled “people[].identities.vcs”Login of this agent on the VCS host, for example “acme-sam[bot]”.
- Type:
string - Optional
- Minimum length 1
people[].identities.tracker
Section titled “people[].identities.tracker”Username or id of this agent in the issue tracker.
- Type:
string - Optional
- Minimum length 1
people[].identities.chat
Section titled “people[].identities.chat”Username or id of this agent in the chat workspace.
- Type:
string - Optional
- Minimum length 1
people[].repos
Section titled “people[].repos”Repository access by repo name, “kind:<primary|baseline|infra|other>” or “*”; values are “read” or “write”.
- Type:
map - Optional
- Default:
{}
people[].tools
Section titled “people[].tools”Tools for this agent only; they replace team-level tools of the same name.
- Type:
map - Optional
people[].tools.
Section titled “people[].tools.”A tool installed at agent start, and optionally a narrower set of commands it may run.
- Type:
object - Optional
people[].tools..version
Section titled “people[].tools..version”Exact version to install, for example “1.23.4”.
- Type:
string - Required
people[].tools..source
Section titled “people[].tools..source”Where mise gets the tool, as a mise backend and name such as ubi:vendor/their-cli or npm:their-cli. Defaults to the tool name, which mise looks up in its registry.
- Type:
string - Optional
- Must match
^[a-z0-9_-]+:\S+$
people[].tools..options
Section titled “people[].tools..options”Options mise passes to the tool’s backend, such as url, bin_path and checksum for an http: source. A value is a string, or a map for platform-keyed options: platforms: { linux-x64: { url: “…” } }. Needs source.
- Type:
map - Optional
people[].tools..valued_options
Section titled “people[].tools..valued_options”Options of the tool that take their value as the next word, such as -c or –context. Their values are never taken for a subcommand, so a rule finds delete in acmectl -c prod delete. --option=value is one word and needs no entry.
- Type:
list of string - Optional
- Minimum items 1
people[].tools..valued_options[]
Section titled “people[].tools..valued_options[]”- Type:
string - Optional
- Must match
^--?[^\s=-][^\s=]*$
people[].tools..allow
Section titled “people[].tools..allow”Narrows what the agent may run of the tool: “all” (the default: any arguments), a list of subcommands, or structured rules. With a list or rules, only the commands they match run. When an option before the subcommand is not in valued_options and might take the next word as its value, every way of reading the command must be allowed. Deny rules and the built-in denies still win.
- Type:
string or list of string or list of object - Optional
people[].tools..allow[]
Section titled “people[].tools..allow[]”- Type:
string - Optional
- Minimum length 1
people[].tools..deny
Section titled “people[].tools..deny”Commands of the tool the agent may never run: a list of subcommands, or structured rules. Deny always wins over allow, including “all”. A deny rule also looks past the value of a leading option that is not in valued_options, so -x value delete cannot hide a denied delete.
- Type:
list of string or list of object - Optional
people[].tools..deny[]
Section titled “people[].tools..deny[]”- Type:
string - Optional
- Minimum length 1
people[].network
Section titled “people[].network”Network grants for this agent, merged over those of its roles.
- Type:
object - Optional
people[].network.http
Section titled “people[].network.http”Services reachable with ost http.
- Type:
list of object - Optional
people[].network.http[]
Section titled “people[].network.http[]”A service the agent may reach with ost http.
- Type:
object - Optional
people[].network.http[].name
Section titled “people[].network.http[].name”Name the agent gives to ost http, for example hub.
- Type:
string - Required
- Minimum length 1
- Maximum length 30
- Must match
^[a-z][a-z0-9-]*$
people[].network.http[].url
Section titled “people[].network.http[].url”Origin of the service, for example https://hub.acme.example.
- Type:
string - Required
people[].network.http[].token
Section titled “people[].network.http[].token”Key of a secret in this person’s secrets; sent as Authorization: Bearer <value> to this service. The agent never sees the value.
- Type:
string - Optional
- Must match
^[A-Za-z0-9_]+$
people[].avatar
Section titled “people[].avatar”Avatar settings.
- Type:
object - Optional
people[].avatar.seed
Section titled “people[].avatar.seed”Seed for a generated avatar.
- Type:
string - Optional
people[].avatar.url
Section titled “people[].avatar.url”Image URL to use as the avatar.
- Type:
string - Optional
integrations
Section titled “integrations”Which adapters connect Outstaff to your tools.
- Type:
object - Required
integrations.chat
Section titled “integrations.chat”Chat adapter where humans and agents talk.
- Type:
object - Required
integrations.chat.adapter
Section titled “integrations.chat.adapter”Name of the adapter package to use, for example “github”.
- Type:
string - Required
- Minimum length 1
integrations.vcs
Section titled “integrations.vcs”Version control adapter (repositories and pull requests).
- Type:
object - Required
integrations.vcs.adapter
Section titled “integrations.vcs.adapter”Name of the adapter package to use, for example “github”.
- Type:
string - Required
- Minimum length 1
integrations.runtime
Section titled “integrations.runtime”LLM runtime adapter that runs the agents; the default for everyone without a runtime of their own (people[].runtime).
- Type:
object - Required
integrations.runtime.adapter
Section titled “integrations.runtime.adapter”Name of the adapter package to use, for example “github”.
- Type:
string - Required
- Minimum length 1
integrations.tracker
Section titled “integrations.tracker”Issue tracker adapter.
- Type:
object - Optional
integrations.tracker.adapter
Section titled “integrations.tracker.adapter”Name of the adapter package to use, for example “github”.
- Type:
string - Required
- Minimum length 1
integrations.knowledge
Section titled “integrations.knowledge”Knowledge base adapter.
- Type:
object - Optional
integrations.knowledge.adapter
Section titled “integrations.knowledge.adapter”Name of the adapter package to use, for example “github”.
- Type:
string - Required
- Minimum length 1
integrations.avatars
Section titled “integrations.avatars”Avatar generation adapter.
- Type:
object - Optional
integrations.avatars.adapter
Section titled “integrations.avatars.adapter”Name of the adapter package to use, for example “github”.
- Type:
string - Required
- Minimum length 1
Email addresses for agents.
- Type:
object - Optional
email.pattern
Section titled “email.pattern”Address pattern for agents, for example “{handle}@acme.example”.
- Type:
string - Required
office
Section titled “office”Office settings: event intake and the doctor checks.
- Type:
object - Optional
office.events
Section titled “office.events”How the office learns about changes: polling or webhooks.
- Type:
string - Optional
- Default:
poll - Allowed values:
poll,webhook
office.poll_interval_seconds
Section titled “office.poll_interval_seconds”Seconds between polls when events is “poll”.
- Type:
integer - Optional
- Default:
60 - Minimum 10
- Maximum 3600
office.poll_warn_after_minutes
Section titled “office.poll_warn_after_minutes”Minutes without a successful poll of an event source before the office logs a warning. Default 10.
- Type:
integer - Optional
- Minimum 1
- Maximum 1440
office.channel
Section titled “office.channel”Team chat channel where the office mirrors agent-to-agent questions and answers, so humans can follow them. Without it they go to the ticket of the asking work item, or only to its journal.
- Type:
string - Optional
- Minimum length 1
office.doctor
Section titled “office.doctor”When the office runs the doctor checks itself, and which it leaves out.
- Type:
object - Optional
office.doctor.daily_at
Section titled “office.doctor.daily_at”Time of day (HH:MM, 24-hour, in the office’s time zone: the container’s TZ, UTC unless set) the office runs the doctor checks every day. It also runs them at start, on demand and, while one fails or warns, every retry_minutes.
- Type:
string - Optional
- Default:
06:00 - Must match
^([01]\d|2[0-3]):[0-5]\d$
office.doctor.retry_minutes
Section titled “office.doctor.retry_minutes”Minutes between the office’s re-runs of its doctor checks while one of them fails or warns, or a run could not finish. They stop once every check passes. 0 turns the re-runs off.
- Type:
integer - Optional
- Default:
15 - Minimum 0
- Maximum 1440
office.doctor.skip
Section titled “office.doctor.skip”Ports (for example chat) whose adapter’s live checks the office does not run, for a provider the office cannot or should not call. Their secrets are still checked; ost doctor still runs them.
- Type:
list of string - Optional
- Allowed values:
chat,vcs,runtime,tracker,knowledge,avatars
office.doctor.skip[]
Section titled “office.doctor.skip[]”- Type:
string - Optional
- Allowed values:
chat,vcs,runtime,tracker,knowledge,avatars
Tools every agent of the team installs at start, with the commands they may run.
- Type:
map - Optional
tools.
Section titled “tools.”A tool installed at agent start, and optionally a narrower set of commands it may run.
- Type:
object - Optional
tools..version
Section titled “tools..version”Exact version to install, for example “1.23.4”.
- Type:
string - Required
tools..source
Section titled “tools..source”Where mise gets the tool, as a mise backend and name such as ubi:vendor/their-cli or npm:their-cli. Defaults to the tool name, which mise looks up in its registry.
- Type:
string - Optional
- Must match
^[a-z0-9_-]+:\S+$
tools..options
Section titled “tools..options”Options mise passes to the tool’s backend, such as url, bin_path and checksum for an http: source. A value is a string, or a map for platform-keyed options: platforms: { linux-x64: { url: “…” } }. Needs source.
- Type:
map - Optional
tools..valued_options
Section titled “tools..valued_options”Options of the tool that take their value as the next word, such as -c or –context. Their values are never taken for a subcommand, so a rule finds delete in acmectl -c prod delete. --option=value is one word and needs no entry.
- Type:
list of string - Optional
- Minimum items 1
tools..valued_options[]
Section titled “tools..valued_options[]”- Type:
string - Optional
- Must match
^--?[^\s=-][^\s=]*$
tools..allow
Section titled “tools..allow”Narrows what the agent may run of the tool: “all” (the default: any arguments), a list of subcommands, or structured rules. With a list or rules, only the commands they match run. When an option before the subcommand is not in valued_options and might take the next word as its value, every way of reading the command must be allowed. Deny rules and the built-in denies still win.
- Type:
string or list of string or list of object - Optional
tools..allow[]
Section titled “tools..allow[]”- Type:
string - Optional
- Minimum length 1
tools..deny
Section titled “tools..deny”Commands of the tool the agent may never run: a list of subcommands, or structured rules. Deny always wins over allow, including “all”. A deny rule also looks past the value of a leading option that is not in valued_options, so -x value delete cannot hide a denied delete.
- Type:
list of string or list of object - Optional
tools..deny[]
Section titled “tools..deny[]”- Type:
string - Optional
- Minimum length 1
Settings per catalog role, for everyone who plays it.
- Type:
map - Optional
roles.
Section titled “roles.”Settings for everyone who plays this role.
- Type:
object - Optional
roles..network
Section titled “roles..network”Network grants every person with this role gets, merged with their own.
- Type:
object - Optional
roles..network.http
Section titled “roles..network.http”Services reachable with ost http.
- Type:
list of object - Optional
roles..network.http[]
Section titled “roles..network.http[]”A service the agent may reach with ost http.
- Type:
object - Optional
roles..network.http[].name
Section titled “roles..network.http[].name”Name the agent gives to ost http, for example hub.
- Type:
string - Required
- Minimum length 1
- Maximum length 30
- Must match
^[a-z][a-z0-9-]*$
roles..network.http[].url
Section titled “roles..network.http[].url”Origin of the service, for example https://hub.acme.example.
- Type:
string - Required
roles..network.http[].token
Section titled “roles..network.http[].token”Key of a secret in this person’s secrets; sent as Authorization: Bearer <value> to this service. The agent never sees the value.
- Type:
string - Optional
- Must match
^[A-Za-z0-9_]+$
workflow
Section titled “workflow”How the tracker’s statuses and labels map onto outstaff’s.
- Type:
object - Optional
workflow.statuses
Section titled “workflow.statuses”Maps canonical statuses to the status names used in your tracker.
- Type:
map - Optional
- Allowed keys:
backlog,ready,active,review,blocked,done,canceled
workflow.needs_human_label
Section titled “workflow.needs_human_label”Ticket label that keeps work with a human. Default “needs-human”.
- Type:
string - Optional
- Minimum length 1
pipeline
Section titled “pipeline”The event pipeline, which decides what the office does with every event (decision 0018): changes to its default policies, how wakes are batched, and the context every wake carries.
- Type:
object - Optional
pipeline.policies
Section titled “pipeline.policies”Changes to the built-in and custom policies, by policy id.
- Type:
map - Optional
pipeline.policies.
Section titled “pipeline.policies.”Changes to one policy of the event pipeline.
- Type:
object - Optional
pipeline.policies..enabled
Section titled “pipeline.policies..enabled”Set to false to turn the policy off. Default: the policy’s own default.
- Type:
boolean - Optional
pipeline.policies..instruction
Section titled “pipeline.policies..instruction”The instruction a woken agent is given, with {{variable}} placeholders. Replaces the policy’s default text.
- Type:
string - Optional
- Minimum length 1
pipeline.policies..when
Section titled “pipeline.policies..when”An extra condition that must hold as well: narrows the policy, never widens it.
- Type:
object - Optional
pipeline.policies..when.all
Section titled “pipeline.policies..when.all”- Type:
list of condition - Required
- Minimum items 1
pipeline.policies..when.all[]
Section titled “pipeline.policies..when.all[]”- Type:
condition - Optional
pipeline.policies..when.any
Section titled “pipeline.policies..when.any”- Type:
list of condition - Required
- Minimum items 1
pipeline.policies..when.any[]
Section titled “pipeline.policies..when.any[]”- Type:
condition - Optional
pipeline.policies..when.not
Section titled “pipeline.policies..when.not”- Type:
condition - Required
pipeline.policies..when.ticket_status
Section titled “pipeline.policies..when.ticket_status”- Type:
list of string - Required
- Allowed values:
backlog,ready,active,review,blocked,done,canceled - Minimum items 1
pipeline.policies..when.ticket_status[]
Section titled “pipeline.policies..when.ticket_status[]”- Type:
string - Optional
- Allowed values:
backlog,ready,active,review,blocked,done,canceled
pipeline.policies..when.parent_status
Section titled “pipeline.policies..when.parent_status”- Type:
list of string - Required
- Allowed values:
backlog,ready,active,review,blocked,done,canceled - Minimum items 1
pipeline.policies..when.parent_status[]
Section titled “pipeline.policies..when.parent_status[]”- Type:
string - Optional
- Allowed values:
backlog,ready,active,review,blocked,done,canceled
pipeline.policies..when.moved_to
Section titled “pipeline.policies..when.moved_to”- Type:
list of string - Required
- Allowed values:
backlog,ready,active,review,blocked,done,canceled - Minimum items 1
pipeline.policies..when.moved_to[]
Section titled “pipeline.policies..when.moved_to[]”- Type:
string - Optional
- Allowed values:
backlog,ready,active,review,blocked,done,canceled
pipeline.policies..when.actor_kind
Section titled “pipeline.policies..when.actor_kind”- Type:
string - Required
- Allowed values:
human,agent,automation
pipeline.policies..when.assignee_kind
Section titled “pipeline.policies..when.assignee_kind”- Type:
string - Required
- Allowed values:
human,agent,none
pipeline.policies..when.has_label
Section titled “pipeline.policies..when.has_label”- Type:
string - Required
- Minimum length 1
pipeline.policies..when.pr_author_kind
Section titled “pipeline.policies..when.pr_author_kind”- Type:
string - Required
- Allowed values:
human,agent,bot
pipeline.policies..when.approver
Section titled “pipeline.policies..when.approver”- Type:
boolean - Required
pipeline.policies..when.pr_draft
Section titled “pipeline.policies..when.pr_draft”- Type:
boolean - Required
pipeline.policies..when.pr_open
Section titled “pipeline.policies..when.pr_open”- Type:
boolean - Required
pipeline.policies..when.pr_merged
Section titled “pipeline.policies..when.pr_merged”- Type:
boolean - Required
pipeline.policies..when.pr_base_default
Section titled “pipeline.policies..when.pr_base_default”- Type:
boolean - Required
pipeline.policies..when.has_body
Section titled “pipeline.policies..when.has_body”- Type:
boolean - Required
pipeline.policies..when.agent_mentioned
Section titled “pipeline.policies..when.agent_mentioned”- Type:
boolean - Required
pipeline.policies..when.review_state
Section titled “pipeline.policies..when.review_state”- Type:
list of string - Required
- Minimum items 1
pipeline.policies..when.review_state[]
Section titled “pipeline.policies..when.review_state[]”- Type:
string - Optional
- Minimum length 1
pipeline.policies..when.hand_back_status
Section titled “pipeline.policies..when.hand_back_status”- Type:
list of string - Required
- Allowed values:
done,waiting,blocked,silent - Minimum items 1
pipeline.policies..when.hand_back_status[]
Section titled “pipeline.policies..when.hand_back_status[]”- Type:
string - Optional
- Allowed values:
done,waiting,blocked,silent
pipeline.policies..when.work_kind
Section titled “pipeline.policies..when.work_kind”- Type:
list of string - Required
- Minimum items 1
pipeline.policies..when.work_kind[]
Section titled “pipeline.policies..when.work_kind[]”- Type:
string - Optional
- Minimum length 1
pipeline.policies..when.pr_approved
Section titled “pipeline.policies..when.pr_approved”- Type:
boolean - Required
pipeline.policies..when.ticket_prs_all_closed
Section titled “pipeline.policies..when.ticket_prs_all_closed”- Type:
boolean - Required
pipeline.policies..when.ticket_prs_open
Section titled “pipeline.policies..when.ticket_prs_open”- Type:
boolean - Required
pipeline.policies..when.ticket_prs_several
Section titled “pipeline.policies..when.ticket_prs_several”- Type:
boolean - Required
pipeline.policies..when.open_subtickets
Section titled “pipeline.policies..when.open_subtickets”- Type:
boolean - Required
pipeline.policies..when.in_milestone
Section titled “pipeline.policies..when.in_milestone”- Type:
boolean - Required
pipeline.policies..when.ticket_handed_back
Section titled “pipeline.policies..when.ticket_handed_back”- Type:
boolean - Required
pipeline.policies..when.blocked_agent
Section titled “pipeline.policies..when.blocked_agent”- Type:
boolean - Required
pipeline.policies..when.actor_in_round
Section titled “pipeline.policies..when.actor_in_round”- Type:
boolean - Required
pipeline.wake
Section titled “pipeline.wake”How wakes are batched.
- Type:
object - Optional
pipeline.wake.coalesce_seconds
Section titled “pipeline.wake.coalesce_seconds”Wakes for the same person and subject within this many seconds of the first become one run, which starts when the window closes. A chat message is answered at once: its wake waits for no window, though a message for a session still queued joins it. Default 60; 0 turns it off.
- Type:
integer - Optional
- Minimum 0
- Maximum 3600
pipeline.notify
Section titled “pipeline.notify”How the direct messages that tell a human about work that landed on them are batched.
- Type:
object - Optional
pipeline.notify.debounce_seconds
Section titled “pipeline.notify.debounce_seconds”How long a direct message to a human about work that landed on them (the notify_human_on_handoff policy) waits for more to join it: an agent’s messages to one human within this many seconds of the latest go as one. A message also waits while the agent’s round on its ticket runs, so a pull request opened in a round goes with the round’s hand-back. Default 60, or office.poll_interval_seconds plus 15 when that is longer, so a pull request the office reads after the hand-back still joins its message.
- Type:
integer - Optional
- Minimum 0
- Maximum 3600
pipeline.context
Section titled “pipeline.context”The context bundle every wake carries: the tickets, pull requests and chat threads the work is linked to, with their recent comments, threads and messages.
- Type:
object - Optional
pipeline.context.comments
Section titled “pipeline.context.comments”The latest comments of each ticket handed over. Default 5.
- Type:
integer - Optional
- Minimum 0
- Maximum 50
pipeline.context.messages
Section titled “pipeline.context.messages”The latest messages of each chat thread handed over. Default 10.
- Type:
integer - Optional
- Minimum 0
- Maximum 50
pipeline.context.threads
Section titled “pipeline.context.threads”The unresolved review threads of each pull request handed over. Default 5.
- Type:
integer - Optional
- Minimum 0
- Maximum 50
pipeline.context.reviews
Section titled “pipeline.context.reviews”The latest review comments on the pull requests of the ticket being worked on and of its parent, resolved and merged ones included. Default 10.
- Type:
integer - Optional
- Minimum 0
- Maximum 50
pipeline.context.items
Section titled “pipeline.context.items”How many tickets, pull requests, documents and chat threads one wake carries at most, the closest to what woke the agent first. Default 8.
- Type:
integer - Optional
- Minimum 1
- Maximum 50
pipeline.context.body_chars
Section titled “pipeline.context.body_chars”Longer descriptions, comments and messages are cut to this many characters; the link has the rest. Default 1500.
- Type:
integer - Optional
- Minimum 100
- Maximum 20000
Proposed (decision 0016): a monitoring or management service the office connects out to, with the secret OUTSTAFF_LINK_TOKEN, that shows its people, queues and event traces (a dashboard, for example). Without it, or without the token, the office connects to none.
- Type:
object - Optional
link.url
Section titled “link.url”Where the office connects, for example wss://ops.acme.example/link.
- Type:
string - Required
- Must match
^wss?:\/\/\S+$
policies
Section titled “policies”Team-wide guardrails, message style and switches for what outstaff does on its own.
- Type:
object - Optional
policies.agent_loop_guard
Section titled “policies.agent_loop_guard”Stops agents from triggering each other in endless loops. Limits only runs triggered by agents or automation; humans are never limited.
- Type:
object - Optional
- Default:
{"max_runs_per_subject_per_hour":12}
policies.agent_loop_guard.max_runs_per_subject_per_hour
Section titled “policies.agent_loop_guard.max_runs_per_subject_per_hour”Maximum runs per hour, triggered by agents or automation, of one person on one ticket, pull request or document, counted across the person’s work items on it (an item without one counts alone). Humans are never limited.
- Type:
integer - Optional
- Default:
12 - Minimum 1
policies.usage
Section titled “policies.usage”Thresholds that slow down work as the LLM usage limit approaches.
- Type:
object - Optional
- Default:
{"defer_scheduled_at":0.85,"pause_automatic_at":0.95}
policies.usage.defer_scheduled_at
Section titled “policies.usage.defer_scheduled_at”Fraction of the usage limit at which scheduled work is deferred.
- Type:
number - Optional
- Default:
0.85 - Minimum 0
- Maximum 1
policies.usage.pause_automatic_at
Section titled “policies.usage.pause_automatic_at”Fraction of the usage limit at which all automatic work pauses.
- Type:
number - Optional
- Default:
0.95 - Minimum 0
- Maximum 1
policies.usage.shared
Section titled “policies.usage.shared”Groups of people who use one LLM subscription, as lists of handles. A usage report from any member applies to all of them.
- Type:
list of list of string - Optional
policies.usage.shared[]
Section titled “policies.usage.shared[]”- Type:
list of string - Optional
- Minimum items 2
policies.usage.shared[][]
Section titled “policies.usage.shared[][]”- Type:
string - Optional
- Minimum length 1
policies.acknowledge
Section titled “policies.acknowledge”The reactions that show people their message or comment was picked up.
- Type:
object - Optional
- Default:
{"chat":true,"vcs":true}
policies.acknowledge.chat
Section titled “policies.acknowledge.chat”React with eyes to a chat message from a trusted person when the agent has seen it. Default on.
- Type:
boolean - Optional
- Default:
true
policies.acknowledge.vcs
Section titled “policies.acknowledge.vcs”React with eyes to each pull request comment the agent is about to answer, when its round starts. Needs a vcs adapter with vcs.reactions. Default on.
- Type:
boolean - Optional
- Default:
true
policies.feedback
Section titled “policies.feedback”How agents act on feedback from trusted people beyond the first round.
- Type:
object - Optional
- Default:
{"follow_up_round":true}
policies.feedback.follow_up_round
Section titled “policies.feedback.follow_up_round”Start another round when feedback arrived after the agent was offered its work. Default on.
- Type:
boolean - Optional
- Default:
true
policies.hand_back
Section titled “policies.hand_back”What happens to a ticket when an agent hands its work back.
- Type:
object - Optional
- Default:
{"blocked_notify":"pm","fallback":"first_human"}
policies.hand_back.blocked_notify
Section titled “policies.hand_back.blocked_notify”Who tells the requester about blocked work that did not come from chat: agent has the blocked agent tell them itself, in its own direct message; pm leaves it to the team’s PM, who gives the ticket to the requester, saying what is needed, only when it cannot unblock it, and the blocked agent sends nothing. Either way a blocked ticket goes to the PM to unblock when the team has one; this only decides who sends the chat message. Without a PM role the agent always does. The office never posts to people. Default pm.
- Type:
string - Optional
- Default:
pm - Allowed values:
pm,agent
policies.hand_back.fallback
Section titled “policies.hand_back.fallback”Who stands in when a ticket has no known requester: the first human in humans with a tracker identity, or none to skip. Default first_human.
- Type:
string - Optional
- Default:
first_human - Allowed values:
first_human,none
policies.tickets
Section titled “policies.tickets”How tickets and pull requests relate.
- Type:
object - Optional
- Default:
{"prs_per_ticket":"one"}
policies.tickets.prs_per_ticket
Section titled “policies.tickets.prs_per_ticket”How many pull requests a ticket may have. one: ost pr open refuses a second one for a ticket; many: several are allowed. Either way the ticket moves to done when its last open pull request merges into the default branch. Default one.
- Type:
string - Optional
- Default:
one - Allowed values:
one,many
policies.notify_handoff
Section titled “policies.notify_handoff”Have an agent tell a human in a direct message in chat when work lands on them: a ticket it hands back to them for review, a blocked ticket given to them (a PM that cannot unblock it, for example), or a pull request it opens for their review. The message links the ticket and the pull requests and says, in a line or two from the hand-back, what is needed. One agent’s messages to one human are batched (pipeline.notify.debounce_seconds). A human with no identities.chat is sent nothing, and the office logs it. Default on.
- Type:
boolean - Optional
- Default:
true
policies.pull_ready
Section titled “policies.pull_ready”Let an agent with nothing queued or running start its next ready ticket: assigned to it, in the ready status, highest tracker priority first, then the one ready the longest. Counts as automatic work. Default on.
- Type:
boolean - Optional
- Default:
true
policies.retry
Section titled “policies.retry”How a failing work item is retried: exponential backoff, then blocked.
- Type:
object - Optional
- Default:
{"base_minutes":1,"cap_minutes":30,"max_failures":3}
policies.retry.base_minutes
Section titled “policies.retry.base_minutes”Wait after the first failed run of a work item; doubles with each failure.
- Type:
integer - Optional
- Default:
1 - Minimum 1
policies.retry.cap_minutes
Section titled “policies.retry.cap_minutes”Longest wait between two attempts at a failing work item.
- Type:
integer - Optional
- Default:
30 - Minimum 1
policies.retry.max_failures
Section titled “policies.retry.max_failures”Consecutive failed runs after which the work item is blocked.
- Type:
integer - Optional
- Default:
3 - Minimum 1
policies.merge
Section titled “policies.merge”Agents merging their own approved pull requests, each merge their decision, woken when a pull request may be ready (opt-in).
- Type:
object - Optional
- Default:
{"on_approval":false,"approvers":["humans"]}
policies.merge.on_approval
Section titled “policies.merge.on_approval”Let agents merge their own approved pull requests. When an agent’s pull request may be ready to merge (an allowed approver approves it with its checks green, its checks turn green while it is approved, or the pull request it was stacked on merges), the office wakes its author to decide: merge it with ost pr merge, wait, or coordinate first. ost pr merge checks the approvals and the required checks, and where the repository has a merge queue merging means joining it. Off by default: no one is woken to merge, ost pr merge refuses, and people merge. Needs a vcs adapter with vcs.merge.
- Type:
boolean - Optional
- Default:
false
policies.merge.approvers
Section titled “policies.merge.approvers”Who may approve a merge with ost pr merge: humans (the people in humans, or anyone with write access when humans is omitted), human:
- Type:
list of string - Optional
- Default:
["humans"] - Minimum items 1
policies.merge.approvers[]
Section titled “policies.merge.approvers[]”- Type:
string - Optional
- Must match
^(humans|human:\S+|role:[a-z][a-z0-9-]*|[A-Za-z0-9][A-Za-z0-9._[\]-]*)$
policies.merge.method
Section titled “policies.merge.method”How ost pr merge merges: queue (the host’s merge queue), merge or squash. When omitted, outstaff uses what the repository has: its merge queue, else a method its settings allow.
- Type:
string - Optional
- Allowed values:
queue,merge,squash
policies.merge.repos
Section titled “policies.merge.repos”Names of the repos (from repos) whose pull requests agents may merge, and are woken to merge. Default: every repo an agent can write to.
- Type:
list of string - Optional
- Minimum items 1
policies.merge.repos[]
Section titled “policies.merge.repos[]”- Type:
string - Optional
- Minimum length 1
policies.merge_checks
Section titled “policies.merge_checks”The checks that run on a pull request’s merge commit in the default branch, such as a deploy. A ticket closes only once they pass; when one fails, the author is woken with its log.
- Type:
object - Optional
- Default:
{"wait_for_start_minutes":5,"timeout_minutes":120,"settle_minutes":2}
policies.merge_checks.wait_for_start_minutes
Section titled “policies.merge_checks.wait_for_start_minutes”Minutes the office waits for a check to appear on a merge commit. With none by then, the merge counts as passed and its ticket can close. Fractions are allowed. Default 5.
- Type:
number - Optional
- Default:
5 - Maximum 1440
policies.merge_checks.timeout_minutes
Section titled “policies.merge_checks.timeout_minutes”Minutes after the merge after which a check still running on the merge commit counts as failed, naming that check. Fractions are allowed. Default 120.
- Type:
number - Optional
- Default:
120 - Maximum 10080
policies.merge_checks.settle_minutes
Section titled “policies.merge_checks.settle_minutes”Minutes the checks on a merge commit must stay finished, with none failed and no new one appearing, before the merge counts as passed, so a workflow that starts after the first ones finish is still waited for. Fractions are allowed. Default 2.
- Type:
number - Optional
- Default:
2 - Minimum 0
- Maximum 1440
policies.messages
Section titled “policies.messages”How agents write chat messages.
- Type:
object - Optional
- Default:
{"max_lines":3,"always_link":true,"omit":["ci","mergeability","hashes"]}
policies.messages.max_lines
Section titled “policies.messages.max_lines”Guidance for agents: keep chat replies to about this many lines. It is a hard limit only for the office’s own automatic notices (status lines, run notifications). An agent’s reply is never cut; one over a high safety cap is split into several messages.
- Type:
integer - Optional
- Default:
3 - Minimum 1
- Maximum 20
policies.messages.always_link
Section titled “policies.messages.always_link”Link tickets, pull requests and documents instead of mentioning bare ids.
- Type:
boolean - Optional
- Default:
true
policies.messages.omit
Section titled “policies.messages.omit”Details left out of chat messages.
- Type:
list of string - Optional
- Default:
["ci","mergeability","hashes"] - Allowed values:
ci,mergeability,hashes,file_lists
policies.messages.omit[]
Section titled “policies.messages.omit[]”- Type:
string - Optional
- Allowed values:
ci,mergeability,hashes,file_lists
policies.design
Section titled “policies.design”What design roles may use.
- Type:
object - Optional
- Default:
{"canvas":true}
policies.design.canvas
Section titled “policies.design.canvas”Let roles that declare the design.canvas capability use Claude’s Artifact tools (the Design canvas), and roles that declare design.canvas.read read those canvases. Needs the claude-agent-sdk runtime signed in with a Claude account. Default on; it does nothing for a role without either capability.
- Type:
boolean - Optional
- Default:
true
policies.chat
Section titled “policies.chat”How agents take chat messages, and what they show in chat.
- Type:
object - Optional
- Default:
{"parallel_sessions":2,"profile":true}
policies.chat.parallel_sessions
Section titled “policies.chat.parallel_sessions”How many chat sessions an agent runs at once, beside its active work item. A message beyond that waits for a free session.
- Type:
integer - Optional
- Default:
2 - Minimum 1
- Maximum 10
policies.chat.profile
Section titled “policies.chat.profile”Publish the agent’s profile in chat: role, status, and current work grouped by ticket or pull request. Needs a chat adapter with chat.agentProfile. Default on.
- Type:
boolean - Optional
- Default:
true
policies.commands
Section titled “policies.commands”Command rules for this team’s own tools, on top of the built-in and toolset rules.
- Type:
object - Optional
policies.commands.allow
Section titled “policies.commands.allow”Commands agents may run of a program. Everything runs by default; once a rule here names a program, the program runs only what such rules allow, and built-in default denies for it (such as kubectl apply) are lifted.
- Type:
list of object - Optional
policies.commands.allow[]
Section titled “policies.commands.allow[]”A command rule.
- Type:
object - Optional
policies.commands.allow[].program
Section titled “policies.commands.allow[].program”Program name, for example make. Git is governed by repository grants.
- Type:
string - Required
- Minimum length 1
- Must match
^[^\s/]+$
policies.commands.allow[].subcommand
Section titled “policies.commands.allow[].subcommand”Leading positional words, for example [“pr”, “view”].
- Type:
list of string - Optional
- Minimum items 1
policies.commands.allow[].subcommand[]
Section titled “policies.commands.allow[].subcommand[]”- Type:
string - Optional
- Minimum length 1
policies.commands.allow[].args
Section titled “policies.commands.allow[].args”Every condition must hold for the rule to apply.
- Type:
list of any - Optional
- Minimum items 1
policies.commands.allow[].args[]
Section titled “policies.commands.allow[].args[]”A condition on the command arguments.
- Type:
any - Optional
policies.commands.allow[].reason
Section titled “policies.commands.allow[].reason”Why the rule exists; shown when it decides a call.
- Type:
string - Required
- Minimum length 1
policies.commands.allow[].requires_repo
Section titled “policies.commands.allow[].requires_repo”The working repository must have at least this grant.
- Type:
string - Optional
- Allowed values:
read,write
policies.commands.deny
Section titled “policies.commands.deny”Commands agents may never run. Deny always wins over allow.
- Type:
list of object - Optional
policies.commands.deny[]
Section titled “policies.commands.deny[]”A command rule.
- Type:
object - Optional
policies.commands.deny[].program
Section titled “policies.commands.deny[].program”Program name, for example make. Git is governed by repository grants.
- Type:
string - Required
- Minimum length 1
- Must match
^[^\s/]+$
policies.commands.deny[].subcommand
Section titled “policies.commands.deny[].subcommand”Leading positional words, for example [“pr”, “view”].
- Type:
list of string - Optional
- Minimum items 1
policies.commands.deny[].subcommand[]
Section titled “policies.commands.deny[].subcommand[]”- Type:
string - Optional
- Minimum length 1
policies.commands.deny[].args
Section titled “policies.commands.deny[].args”Every condition must hold for the rule to apply.
- Type:
list of any - Optional
- Minimum items 1
policies.commands.deny[].args[]
Section titled “policies.commands.deny[].args[]”A condition on the command arguments.
- Type:
any - Optional
policies.commands.deny[].reason
Section titled “policies.commands.deny[].reason”Why the rule exists; shown when it decides a call.
- Type:
string - Required
- Minimum length 1
policies.commands.deny[].requires_repo
Section titled “policies.commands.deny[].requires_repo”The working repository must have at least this grant.
- Type:
string - Optional
- Allowed values:
read,write
policies.custom
Section titled “policies.custom”Event pipeline policies of the team’s own, which run after the built-in ones: each a module of the team’s repository or an npm package that exports policy (or a policies list). They run in the office process, as trusted as this repository. ost validate and the office load and check each one.
- Type:
list of object - Optional
policies.custom[]
Section titled “policies.custom[]”A custom policy to load: module or package, and its settings.
- Type:
object - Optional
policies.custom[].module
Section titled “policies.custom[].module”Path of the module, relative to this file, for example ./policies/release-freeze.ts.
- Type:
string - Required
- Minimum length 1
policies.custom[].settings
Section titled “policies.custom[].settings”Values the policy reads as ctx.settings; what it accepts is up to the policy.
- Type:
map - Optional
policies.custom[].package
Section titled “policies.custom[].package”Name of an installed npm package, for example @acme/outstaff-policy-oncall.
- Type:
string - Required
- Minimum length 1
memory
Section titled “memory”Where agents keep their memory: the lasting lessons and preferences they note.
- Type:
object - Optional
memory.store
Section titled “memory.store”Where agents keep their notes (ost note): volume, files in memory/ on each agent’s home volume, which must then be backed up; or knowledge, a page per agent in the knowledge integration, which must provide knowledge.notes.
- Type:
string - Optional
- Default:
volume - Allowed values:
volume,knowledge
Tokens and cost of agent work, per run and per ticket.
- Type:
object - Optional
usage.track_cost
Section titled “usage.track_cost”Record the tokens and cost of every run and total them per ticket, sub-tickets rolled up into their parent. The cost is what the runs would cost at API prices (API-equivalent), not what a subscription bills. Default on.
- Type:
boolean - Optional
- Default:
true
usage.tracker_fields
Section titled “usage.tracker_fields”Show each ticket’s totals in two custom fields of the tracker, “Agent tokens” and “Agent cost, USD (API-equivalent)”, written by the agent whose run it was. Needs a tracker with tracker.fields. Off keeps the totals in the office only. Default on.
- Type:
boolean - Optional
- Default:
true