Teamwork
Most of what makes a good teammate is communication: they say what they’re planning, what they did, where they’re stuck, and what’s still on their list. OpenRoutines teamwork primitives give your agent the same habits: declaring intentions, reporting progress, calling out blockers, and tracking tasks.
The primitives are built on the agent’s knowledge. Routines that do work write down plain facts as they go, and reporting routines read those facts later to compose updates for the team. That split means you can write working routines without thinking about reporting at all, and point any number of reports and destinations at the facts they leave behind.
The pieces
Every outcome is carried by a small set of plain files:
| Outcome | Carried by |
|---|---|
| Declare intentions | Every run receives schedule.md, the runtime’s list of what runs next. A report pairs it with the open Agent-owned tasks in tasks.md to say what the agent will do next and what it still owes. |
| Report progress | Working routines record what happened as events in events.md. When a reporting routine runs, the runtime hands it changes.md: everything added to knowledge since that routine last reported. |
| Call out blockers | Anything that needs a person becomes a Human-owned task in tasks.md. Routines file them when they hit a wall, and the supervisor files its own when a run fails or gives up. |
| Track tasks | Any routine that finds work someone must do files a task in tasks.md. Each task is one record with a stable id and an owner, updated in place from discovery to resolution. |
There’s one piece you never see in a prompt: the runtime injects standing instructions into every run that teach the model these files and the rules for using them. Routine prompts never explain the primitives; they only describe the job.
Declaring intentions
The runtime does the hard part here. It parses every routine’s schedule, works out which ones run before the next report, and hands the reporting run that list as a generated ./schedule.md (see Scheduling). The reporting routine pairs those with any open Agent-owned tasks they could pick up in the same window.
Reporting progress
Progress has two halves: recording and delivery.
Recording is automatic. As a working routine does its job, its runs land as events in events.md: raw facts with links, including finding nothing (“checked 5 PRs, no doc drift”). Events stay rough on purpose, since polishing them into something readable is the delivery half’s job.
Delivery reads the record and passes it on. A routine that declares reports: true receives changes.md, everything recorded since its last report. It turns that into an update, sends it wherever it’s pointed, and consumes the batch once the update actually lands. A failed send means the same changes come back next run, so nothing is lost and nothing goes out twice. Each reporting routine keeps its own place in the feed, so a second destination is just a second routine, starting from the current state rather than replaying history.
Calling out blockers
A blocker is a Human-owned task in tasks.md, so there’s no separate blockers file or alert channel to wire up. A handoff a routine can’t complete becomes one, and a genuinely blocked task names the dependency it waits on. The supervisor files them too, for a run it gave up on, a tripped circuit breaker, or a sync it can’t complete, because a person is the only one who can act. When the condition heals it completes its own task in place, so a three-minute outage doesn’t read as an open blocker days later.
Blockers are two-way. Answer one through any channel a routine watches, a reply to the check-in in Steady or Slack, say, and the next relevant run reads your answer, files the follow-up as an Agent-owned task, and gets on with the work.
Tracking tasks
A task is one record from discovery to resolution: a stable id (task-YYYYMMDD-<n>), a section naming the owner (## Agent-owned or ## Human-owned), and transitions made in place, so completing, cancelling, or transferring one shows up as a diff on that entry rather than a new record elsewhere. Tasks track where things stand, where events record what happened. A transition is itself a change the feed delivers, so completing a task is also how it gets reported. tasks.md is exempt from retention trimming, since age doesn’t make a task done.
How loudly a routine participates
One frontmatter key, a three-value ladder:
teamwork: full(the default) — runs are recorded as events, and upcoming runs appear in the scheduleteamwork: events— runs are still recorded, but upcoming runs stay out of the schedule, and so out of reported intentionsteamwork: off— invisible to the team: for reporting routines, where checking in is not work
Declaring reports: true sets teamwork to off; set it explicitly for a routine that both reports and does record-worthy work of its own. Whatever the tier, tasks and context stay writable, since even an invisible routine must be able to file a task.
What this looks like in routines
A working routine needs no teamwork instructions at all. The prompt is just the job:
---
schedule: "0 9 * * 1-5"
credentials: [github_token]
---
Review yesterday's merged PRs in acme/widgets for documentation drift, and
open a PR fixing whatever you find.
Everything it contributes comes free: its runs land as events, a no-drift day included, work it can’t finish becomes a task with an owner, and its fires appear in every other run’s schedule.md.
A reporting routine decides three things: composition, destination, and what counts as delivered.
---
schedule: "0 17 * * 1-5"
reports: true
skills: [slack-post]
credentials: [slack_bot_token]
---
Post this agent's end-of-day summary to #eng-agents, with three short
sections: what happened (group related items), what's coming before
tomorrow's summary, and where a human is needed.
Posting is delivery.
Notice what the prompt never mentions: no file names, nothing about where events, the schedule, or tasks live. That last line is what makes the routine consume its changes only once the post lands, so a failed post means the same changes return next run.
The check-in routine that ships with a new agent is the same shape, recording its report in its own ledger instead of posting somewhere real. Treat it as a starting point: change its cadence and sections, point it at a destination by granting a skill and a credential, or replace it with reporting routines of your own.