Build a product team of actors
This page is a pattern, not a product. It shows how to put one product in the hands of a small team of Staff actors, using pieces you already have: actors, tickets, the coding agent and chat. The example is a fictional "Orders" product at Acme. Change the names, keep the shape.
The shape
Orders manager (routes work, keeps it moving)
│
┌──────────────┬──────────┼───────────────┬──────────────────┐
Orders PM Orders engineer Orders reviewer Orders QA Orders release
(triage) (code, invoke (reviews, never (health, (release
only) approves) check gate) proposals)
Orders support (in the product's chat) ──► hands off to a ticket when stuck
Humans: merge, release, roll out, change chat spaces, budgets and permissions
Three rules make it work:
- Tickets are the queue. Every piece of work is a ticket. The assignee owns the next step.
- Gates are structural. An actor that must not merge simply does not hold a tool that merges. You do not rely on a prompt saying "please don't".
- Humans approve what is hard to undo. Merges outside what your policy allows, releases, rollouts and chat space changes go to a person.
The roster
| Actor | Wakes | Holds (examples of workflow skills) | Does not hold |
|---|---|---|---|
| Manager | A schedule (every couple of hours), an incident event, and invoke | ticket.search, ticket.get, ticket.comment, ticket.assign, ticket.transition; with the coding lane on, staff.invoke-actor to start the engineer | Merge, release, chat space changes |
| Product manager | Hourly, a few tickets per wake | ticket.search, ticket.get, ticket.comment, ticket.assign, ticket.transition, staff.dispatch-event-to-actor (for critical incidents only) | Everything else |
| Engineer | Invoke only, by the manager | The coding-agent lane on a hosted coding runner. See Run a ticket end to end | Push, merge, release, credentials |
| Reviewer | Every 30 minutes, a couple of pull requests per wake | Your Git provider's pull request read and review workflows, plus ticket reads and comments | Approve, merge |
| QA | Hourly | buzz.space.status, data.buzz.member.list, data.buzz.channel.list, data.buzz.member.directory for chat health; your Git provider's check status; tickets | Posting in chat, changing the space, fixing code |
| Release manager | Every few hours | Pull request reads, data.buzz.space.get, buzz.space.status, tickets | Tag, release, publish, roll out, merge |
| Support | Chat messages only (see below) | Seat mode: nothing but the app's end-user workflows. Internal mode: a narrow set of reads | Everything else |
Turn the platform default tools off in each actor's launch settings and bind only the skills in its row, so its tool list is exactly what you meant. Use loop-style schedules (the next wake starts after the previous run finishes) so the team does not pile sessions onto your agent runner group. Manage schedules with staff.list-actor-schedules and staff.manage-actor-schedule.
How work flows
The handoff
A handoff is always two calls: a ticket.comment with a small, fixed block, then ticket.assign to the next owner.
PRODUCT-HANDOFF v1
from: orders-pm
to: orders-manager
stage: plan # triage | plan | build | review | qa | release | done | blocked
repo: acme/orders-web
pr: none
verdict: needs-code # pass | fail | needs-code | no-code | duplicate | needs-human | none
summary: checkout button stays disabled on Safari
next: start build against the acceptance lines
severity: high
acceptance: given a signed-in Safari user, when they add an item, then checkout is enabled
The newest block addressed to an actor says what its next step is. Ticket status follows the normal lifecycle (open, triaged, in_progress, blocked, resolved) with ticket.transition.
A bug, from report to release
sequenceDiagram autonumber participant R as Reporter or QA participant PM as PM actor participant M as Manager actor participant E as Engineer actor participant RV as Reviewer actor participant QA as QA actor participant RM as Release actor participant H as Human R->>PM: ticket labelled for the product PM->>M: handoff (plan), ticket triaged M->>E: staff.invoke-actor with the ticket E->>RV: pull request opened by the delivery lane, handoff (review) RV->>QA: review comment, handoff (qa) QA->>RM: checks green, handoff (release) RM->>H: release proposal ticket H->>H: merge if needed, release, roll out RM->>M: verified landed, handoff (done) M->>M: ticket resolved
A reviewer's "changes needed" or a QA failure hands the ticket back to the manager, which invokes the engineer again in repair mode on the same work.
Decision rights
| Action | Who |
|---|---|
| Triage, routing, review comments, health checks, proposals | Actors |
| Code changes up to a publication request | The engineer, through the coding lane |
| Opening the pull request, check evaluation | The delivery lane |
| Merging | A person, or your governed merge lane for the change classes your policy allows |
| Tags, releases, package publishing, rollouts, migrations | A person |
| Attaching actors to chat, bridge sync, theme publish, chat page publish, member and channel changes | A person (the chat workflows refuse agents) |
| Budgets, tools, schedules and permissions of the team | A person |
The support actor in chat
Put one more actor in the product's chat space to answer the people who use it.
- For customers, use seat mode: bind the actor to an end-user seat in the app, attach it with mention and DM triggers and a low reply ceiling, and sync the bridge. It can use only the workflows your app exposes to end users. When it cannot help, people ask for a person and the chat opens a ticket labelled
chatandchat:handoff, raising thechat.incident.raisedevent your manager actor can listen to. See Actors in chat. - For your own team, use internal mode: the actor answers only listed people, with a narrow set of organization reads such as actor state, recent failed sessions, ticket search and pull request status, and memory turned off.
Keep the support actor separate from the PM or manager. An actor that acts as an app seat applies that to every run, and a seat session carries no organization tools.
Start small
- Apply the manager, PM and QA first, with the coding lane off. Code work goes to a person as a
needs-humanhandoff. - Watch a week of cost per actor and each actor's journal, then lower budgets from evidence.
- Turn on the reviewer and the release manager.
- Wire the coding lane for one repository and give the manager
staff.invoke-actor. - Add the support actor in chat.
Ask your AI assistant
Draft a product team of Staff actors for my "<product>" product: manager, PM, engineer, reviewer, QA and release. For each, propose the schedule, budget and the exact workflow skills it should hold, using only workflow types that exist in my catalog.
List the open tickets labelled "<product>" with ticket.search and tell me which ones have no assignee.
Show the schedules of my product team actors with staff.list-actor-schedules and flag any that are disabled.
For AI agents
| Rule | Detail |
|---|---|
| Verify tools | Every skill in a roster must be a registered workflow. Check each with get_workflow_schema before proposing it |
| Handoffs | ticket.comment then ticket.assign. Never skip the comment |
| Structural gates | Do not add merge, release or chat admin tools to an actor to "save a step" |
| Chat admin | buzz.actor.attach, buzz.bridge.sync and theme or space changes need a person |
Run a ticket end to end
How to use the coding agent — write a ticket it can implement, launch the delivery, watch it code, publish, review and merge on its own, and close the loop when it lands
Troubleshooting
Sessions that never heartbeat, actors that will not act, runner gates, seats, tokens, and where to look next
