Orkestia
Blog
Staff & Agents

Build a product team of actors

A pattern for running one product with Staff actors. A manager, a product manager, an engineer, a reviewer, QA and a release manager work from tickets, humans approve merges and releases, and a support actor answers people in the product's chat

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:

  1. Tickets are the queue. Every piece of work is a ticket. The assignee owns the next step.
  2. 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".
  3. 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

ActorWakesHolds (examples of workflow skills)Does not hold
ManagerA schedule (every couple of hours), an incident event, and invoketicket.search, ticket.get, ticket.comment, ticket.assign, ticket.transition; with the coding lane on, staff.invoke-actor to start the engineerMerge, release, chat space changes
Product managerHourly, a few tickets per waketicket.search, ticket.get, ticket.comment, ticket.assign, ticket.transition, staff.dispatch-event-to-actor (for critical incidents only)Everything else
EngineerInvoke only, by the managerThe coding-agent lane on a hosted coding runner. See Run a ticket end to endPush, merge, release, credentials
ReviewerEvery 30 minutes, a couple of pull requests per wakeYour Git provider's pull request read and review workflows, plus ticket reads and commentsApprove, merge
QAHourlybuzz.space.status, data.buzz.member.list, data.buzz.channel.list, data.buzz.member.directory for chat health; your Git provider's check status; ticketsPosting in chat, changing the space, fixing code
Release managerEvery few hoursPull request reads, data.buzz.space.get, buzz.space.status, ticketsTag, release, publish, roll out, merge
SupportChat messages only (see below)Seat mode: nothing but the app's end-user workflows. Internal mode: a narrow set of readsEverything 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

ActionWho
Triage, routing, review comments, health checks, proposalsActors
Code changes up to a publication requestThe engineer, through the coding lane
Opening the pull request, check evaluationThe delivery lane
MergingA person, or your governed merge lane for the change classes your policy allows
Tags, releases, package publishing, rollouts, migrationsA person
Attaching actors to chat, bridge sync, theme publish, chat page publish, member and channel changesA person (the chat workflows refuse agents)
Budgets, tools, schedules and permissions of the teamA 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 chat and chat:handoff, raising the chat.incident.raised event 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

  1. Apply the manager, PM and QA first, with the coding lane off. Code work goes to a person as a needs-human handoff.
  2. Watch a week of cost per actor and each actor's journal, then lower budgets from evidence.
  3. Turn on the reviewer and the release manager.
  4. Wire the coding lane for one repository and give the manager staff.invoke-actor.
  5. Add the support actor in chat.

Ask your AI assistant

prompts
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

RuleDetail
Verify toolsEvery skill in a roster must be a registered workflow. Check each with get_workflow_schema before proposing it
Handoffsticket.comment then ticket.assign. Never skip the comment
Structural gatesDo not add merge, release or chat admin tools to an actor to "save a step"
Chat adminbuzz.actor.attach, buzz.bridge.sync and theme or space changes need a person