Skip to content

Reference: `team-compose.yaml`

The compose tree has two layers:

  • One global file (team-compose.yaml) — broker, supervisor, budget, HITL policy, interfaces, and the list of project files.
  • One per-project file (projects/<id>.yaml) — channels, managers, workers.

Global

version: 2
broker:
type: sqlite # sqlite (default); redis-streams is planned
path: state/mailbox.db
supervisor:
type: tmux # tmux (default) | systemd | launchd
tmux_prefix: a- # tmux session name prefix
budget:
daily_usd_limit: 25.0
warn_threshold_pct: 75
message_ttl_hours: 24
per_project_usd_limit:
newsroom: 15.0
hitl:
globally_sensitive_actions:
- publish
- release
- deploy
- payment
- external_email
- external_api_post
- merge_to_main
- dns_change
auto_approve_windows:
- action: publish
project: newsroom
scope: "morning-brief-*"
until: "2026-05-01T09:00:00Z"
interfaces:
- type: telegram
name: tg-main
config:
bot_token_env: TEAMCTL_TELEGRAM_TOKEN
authorized_chat_ids: [75473051]
manager: news:head_editor # optional — scope bot to one manager
projects:
- file: projects/newsroom.yaml
- file: projects/blog-site.yaml

Per-project

version: 2
project:
id: newsroom
name: Newsroom
cwd: .
channels:
- name: editorial
members: [head_editor, fact_checker, news_writer]
- name: all
members: "*"
managers:
head_editor:
runtime: claude-code
model: claude-opus-4-7
role_prompt: roles/head_editor.md
permission_mode: auto
telegram_inbox: true
reports_to_user: true
autonomy: low_risk_only
can_dm: [fact_checker, news_writer, seo]
can_broadcast: [editorial, all]
workers:
fact_checker:
runtime: gemini
model: gemini-3.0-pro
role_prompt: roles/fact_checker.md
reports_to: head_editor
can_dm: [head_editor, news_writer]
can_broadcast: [editorial]
news_writer:
runtime: claude-code
model: claude-sonnet-4-6
role_prompt: roles/news_writer.md
reports_to: head_editor
can_dm: [head_editor, fact_checker]
can_broadcast: [editorial]

Field reference

Global

FieldTypeDefaultNotes
versionintMust be 2.
broker.typestringsqliteOnly sqlite is shipping.
broker.pathstringstate/mailbox.dbResolved relative to the compose root.
supervisor.typestringtmuxtmux · systemd · launchd.
supervisor.tmux_prefixstringa-Tmux session name = <prefix><project>-<agent>.
budget.daily_usd_limitfloatOverall ceiling.
budget.per_project_usd_limitmap{}Per-project overrides.
budget.message_ttl_hoursint24teamctl gc horizon.
hitl.globally_sensitive_actionslist(see default)Actions that always gate through approval.
hitl.auto_approve_windowslist[]Pre-authorization windows.
interfaceslist[]Human-facing channels (telegram, discord, imessage, cli, webhook, email).
projectslist[]Each entry: { file: <path> }.

Per-project

FieldTypeDefaultNotes
versionintMust be 2.
project.idstringUnique id; used in tmux session names, mailbox scoping.
project.namestringHuman label.
project.cwdpathWorking directory for runtimes. Relative paths resolve against the compose root.
channels[].namestringChannel name (project-scoped).
channels[].memberslist or "*"Agent short-names or "*" for every agent in this project.
managers / workersmapKeyed by agent short-name.

Agent

FieldTypeDefaultNotes
runtimestringclaude-codeMust match a runtimes/<name>.yaml.
modelstringruntime defaultRuntime-specific model id.
role_promptpathSystem prompt file; passed via runtime-specific flag.
permission_modestringruntime defaulte.g. auto, plan, acceptAll.
telegram_inboxboolfalseManager-only. Set true to receive Telegram forwards.
reports_to_userboolfalseManager-only. May call reply_to_user.
autonomystringlow_risk_onlyfull · low_risk_only · proposal_only.
can_dmlist[] = unrestrictedShort-names this agent may DM.
can_broadcastlist[] = unrestrictedChannel names this agent may post to.
reports_tostringWorker-only. The manager this worker answers to.