Skip to content

Pipeline policies

These are the built-in policies the office runs, in evaluation order (decision 0018). Each is a module in packages/office/src/pipeline/policies/, and this page is generated from them. Every policy that listens to an event receives it and proposes; the aggregation layer turns the proposals into the decisions. What outstaff does on its own explains the events and the decisions, and Writing a policy how to add a policy of your own.

A team changes a policy under pipeline.policies.<id> in team.yaml: enabled: false turns it off (it stays in the trace), instruction replaces the instruction of a wake or the note of an act, and when narrows it, so both its own condition and the team’s must hold. Policies of the team’s own, under policies.custom, run after these.

Policy Listens to Decides
chat_to_addressed chat.message wake addressed (kind chat)
review_to_author pr.review_submitted, pr.comment wake author (kind review_feedback)
merged_feedback_to_author pr.review_submitted, pr.comment wake author (kind merged_feedback)
merged_closes_ticket pr.merge_checks_passed act for author, else assignee, else last_worker: move the ticket to done, assign it to the agent acted for
merge_checks_failed_to_agent pr.merge_checks_failed wake author, else assignee, else last_worker (kind merge_checks_failed)
rebase_to_author pr.conflicted, pr.behind_base, pr.base_merged wake author (kind rebase)
ci_failed_to_author pr.ci_failed wake author (kind ci_failed)
merge_ready pr.review_submitted, pr.ci_passed, pr.base_merged wake author (kind merge) with the merge context, when its checks are green and the repository is in policies.merge.repos
opened_to_review pr.opened act for author, else assignee, else last_worker: move the ticket to review
link_pr_on_ticket pr.opened, pr.linked act for author: link the pull request on the ticket, when the tracker can link pull requests (tracker.development)
assigned_to_assignee ticket.assigned, ticket.created wake assignee (kind assigned)
ticket_comment_to_agent ticket.commented wake assignee (kind ticket_comment)
ticket_comment_to_mentioned_agent ticket.commented wake mentioned (kind asked)
ticket_comment_to_blocked_agent ticket.commented wake blocked_agent (kind ticket_comment)
ticket_comment_to_last_worker ticket.commented wake last_worker (kind ticket_comment)
moved_active_to_assignee ticket.moved wake assignee (kind assigned)
moved_active_to_last_worker ticket.moved act for last_worker: assign it to the agent acted for, then wake them (kind assigned)
closed_stops_work ticket.closed stop the work on the ticket of every agent but the one who closed it; a ticket closed as done by an unknown closer or an automation stops nothing
subticket_closed_to_agent ticket.closed wake assignee, else last_worker, else the parent’s agent (kind assigned) on the ticket’s parent, the first of them with more unfinished sub-tickets of the parent
subtickets_closed_move_parent ticket.closed act for the parent’s agent: move the parent to done and assign it to the agent, when its own pull requests merged, else to review and assign it to the requester; when the closed ticket was its last open sub-ticket
subtickets_closed_close_parent ticket.closed act for the parent’s agent (the one it is assigned to, else the one that last worked it, else the closed sub-ticket’s): move the parent to done and assign it to the agent, when it has no open pull request of its own, else to review and assign it to the requester; when the closed ticket was its last open sub-ticket
subtickets_in_review_move_parent ticket.moved, ticket.closed act for the parent’s agent (the one it is assigned to, else the one that last worked it, else the sub-ticket’s): move the parent to review and assign it to the requester; when every sub-ticket is done, canceled or in review, at least one in review, and no open pull request of its own is a draft
milestone_done_to_pm ticket.closed wake the PM (role:pm, kind milestone) on the closed ticket, when every other ticket of its milestone the office knows is done or canceled
unblocked_to_blocked_agent ticket.unblocked wake blocked_agent (kind unblocked)
unblocked_to_ready ticket.unblocked act for assignee: move the ticket to ready, then wake them (kind assigned), unless the blocker is a sub-ticket of the same parent and the parent is with that agent (parentAgent): then only move it; with no agent assigned, act for closer: move the ticket to ready
doc_comment_to_agent doc.commented wake mentioned, else doc_author (kind doc_feedback)
doc_comment_to_mentioned_agent doc.commented wake mentioned (kind doc_feedback)
link_doc_on_ticket doc.linked act for doc_author, else actor: link the document on the ticket, when the knowledge base can link documents on tickets (knowledge.issueLinks)
start_marks_active agent.started act for actor: assign it to the agent acted for, move the ticket to active
hand_back_done agent.handed_back act for actor: move the ticket to review, assign it to the requester, unless the agent handed the ticket over to someone else; a ticket with open sub-tickets stays active with the agent instead, unless every sub-ticket is in review or closed; the item’s other tickets awaiting review (the ones it created that are in review, and the ones whose pull request it opened) move to review and go to the requester
hand_back_silent_restores agent.handed_back act for the agent: move the ticket back to the status it had before the round, and assign it back to whom it had, for each of the two still as the round’s start set it; the item’s other tickets awaiting review (the ones it created that are in review, and the ones whose pull request it opened) move to review and go to the requester
hand_back_blocked agent.handed_back act for actor: move the ticket to blocked, assign it to the requester, when no PM unblocks it, unless the agent handed the ticket over to someone else; the item’s other tickets awaiting review (the ones it created that are in review, and the ones whose pull request it opened) move to review and go to the requester
hand_back_blocked_to_pm agent.handed_back act for actor: move the ticket to blocked, assign it to role:pm; then wake role:pm (kind unblock), when the PM is not the blocked agent, unless the agent handed the ticket over to someone else; the item’s other tickets awaiting review (the ones it created that are in review, and the ones whose pull request it opened) move to review and go to the requester
notify_human_on_handoff agent.handed_back, ticket.assigned, pr.opened notify the human in chat, as the agent: the requester on a hand-back as done (or the human the agent handed the ticket over to; nothing more when the work came from a chat thread, which gets the result), with every other ticket of the item the hand-back gives the requester for review, the assignee when an agent gives a ticket in review or blocked to a human (not the echo of an office act, nor the agent blocked on it), the requester of the ticket of an agent’s pull request opened for review; on policies.notify_handoff
idle_pulls_next agent.idle wake actor (kind assigned), with its next ready ticket (for a sub-ticket, on its parent)

A chat message wakes the agent it was written to.

Listens to chat.message. Decides: wake addressed (kind chat).

When:

  • actor_kind: human

Instruction:

{{actor.id}} wrote to you in chat. Answer in the thread. If they ask for work, decide how it fits your queue.

A human’s review or comment on an agent’s open pull request wakes its author.

Listens to pr.review_submitted, pr.comment. Decides: wake author (kind review_feedback).

When:

  • all of:
    • actor_kind: human
    • pr_author_kind: agent
    • pr_open: true
    • not:
      • all of:
        • review_state: approved
        • has_body: false

Instruction:

{{actor.id}} left feedback on your pull request #{{pr.number}} ({{pr.title}}). Address each point, answer in its thread and push.

A human’s review or comment on an agent’s merged pull request wakes its author.

Listens to pr.review_submitted, pr.comment. Decides: wake author (kind merged_feedback).

When:

  • all of:
    • actor_kind: human
    • pr_author_kind: agent
    • pr_merged: true
    • not:
      • all of:
        • review_state: approved
        • has_body: false

Instruction:

{{actor.id}} commented on your merged pull request #{{pr.number}} ({{pr.title}}). Answer there. If they ask for a change, open a follow-up pull request.

A merge into the default branch closes the ticket once the checks on its merge commit pass (or none start), unless another of its pull requests or one of its sub-tickets is open; the ticket ends with the agent who did the work: for the author, or, for a human’s pull request, the agent the ticket is assigned to, else the agent who last worked on it.

Listens to pr.merge_checks_passed. Decides: act for author, else assignee, else last_worker: move the ticket to done, assign it to the agent acted for.

When:

  • all of:
    • ticket_status: backlog, ready, active, review, blocked
    • pr_base_default: true
    • not:
      • ticket_prs_open: true
    • not:
      • open_subtickets: true

Note posted with the change:

Moved to done: pull request #{{pr.number}} by {{pr.author}} merged and the checks on its merge commit passed.

A check that fails on the merge commit of a pull request in the default branch, such as a deploy, wakes the ticket’s agent with the failed step’s log: the pull request’s author, or, for a human’s pull request, the agent the ticket is assigned to, else the agent who last worked on it. The ticket stays open.

Listens to pr.merge_checks_failed. Decides: wake author, else assignee, else last_worker (kind merge_checks_failed).

When:

  • all of:
    • pr_merged: true
    • not:
      • ticket_status: canceled

Instruction:

Pull request #{{pr.number}} ({{pr.title}}) by {{pr.author}} merged, but checks on its merge commit failed: {{checks}}. The end of the failed step's log is in the context; `ost ci log <check link>` reads more. Fix it the way the repository asks, for example with a follow-up pull request on the same ticket. The ticket stays open until a merge for it passes its checks.

An agent’s open pull request that conflicts, is behind its base, or whose base merged wakes its author, naming the merge that caused it.

Listens to pr.conflicted, pr.behind_base, pr.base_merged. Decides: wake author (kind rebase).

When:

  • all of:
    • pr_author_kind: agent
    • pr_open: true
    • not:
      • ticket_status: canceled

Instruction:

Your pull request #{{pr.number}} ({{pr.title}}) {{pr.problem}}{{cause}}. Bring it up to date with `{{pr.base}}` the way the repository asks, and push. Then keep the pull request description current; if the approach changed, comment with what changed and why.

Failing checks on an agent’s open pull request wake its author.

Listens to pr.ci_failed. Decides: wake author (kind ci_failed).

When:

  • all of:
    • pr_author_kind: agent
    • pr_open: true
    • not:
      • ticket_status: canceled

Instruction:

Your pull request #{{pr.number}} ({{pr.title}}) {{pr.problem}}. The failing checks are in the feedback. Fix them and push.

An agent’s approved pull request that may be ready to merge wakes its author to decide (policies.merge.on_approval): an allowed approver approves it with its checks green, its checks turn green, or the pull request it was stacked on merges. Not while an allowed approver’s request for changes is outstanding.

Listens to pr.review_submitted, pr.ci_passed, pr.base_merged. Decides: wake author (kind merge) with the merge context, when its checks are green and the repository is in policies.merge.repos.

On only while policies.merge.on_approval is on.

When:

  • all of:
    • all of:
      • pr_author_kind: agent
      • pr_open: true
      • not:
        • ticket_status: canceled
    • pr_draft: false
    • pr_approved: true

Instruction:

#{{pr.number}} ({{pr.title}}) is approved and may be ready to merge. Decide whether to merge it now, wait, or coordinate first; follow the repository's instructions on merging.

A pull request opened for review moves its ticket to review: for the author, or, for a human’s pull request, the agent the ticket is assigned to, else the agent who last worked on it. A ticket with open sub-tickets stays active until the last one closes.

Listens to pr.opened. Decides: act for author, else assignee, else last_worker: move the ticket to review.

When:

  • all of:
    • not:
      • pr_draft: true
    • ticket_status: backlog, ready, active
    • not:
      • open_subtickets: true

Note posted with the change:

Moved to review: pull request #{{pr.number}} by {{pr.author}} is open for review.

An agent’s pull request opened for a ticket, or linked to one after it was opened, is shown on the ticket in the tracker (its development section), by the author with its own tracker account. Bookkeeping: it wakes no one.

Listens to pr.opened, pr.linked. Decides: act for author: link the pull request on the ticket, when the tracker can link pull requests (tracker.development).

When: always.

Note posted with the change: none, since the ticket shows the change. A team can add one with pipeline.policies.link_pr_on_ticket.instruction.

A ticket assigned to an agent, by anyone but that agent, wakes the agent.

Listens to ticket.assigned, ticket.created. Decides: wake assignee (kind assigned).

When:

  • all of:
    • assignee_kind: agent
    • not:
      • actor_kind: automation
    • not:
      • actor_is: assignee
    • not:
      • ticket_status: done, canceled

Instruction:

{{ticket}} is assigned to you. Work on it the way the repository asks.

A human’s comment, mentioning no agent, on a ticket assigned to an agent wakes that agent.

Listens to ticket.commented. Decides: wake assignee (kind ticket_comment).

When:

  • all of:
    • actor_kind: human
    • not:
      • ticket_status: done, canceled
    • not:
      • agent_mentioned: true
    • assignee_kind: agent

Instruction:

{{actor.id}} commented on {{ticket}}. Read the comment and act on it.

A comment on a ticket, by a human or another agent, wakes the agent it mentions first, to answer or act on it; the ticket stays with its assignee. An agent’s comment that mentions no other agent wakes no one.

Listens to ticket.commented. Decides: wake mentioned (kind asked).

When:

  • all of:
    • not:
      • actor_kind: automation
    • not:
      • ticket_status: done, canceled
    • agent_mentioned: true

Instruction:

{{actor.id}} mentioned you in a comment on {{ticket}}. Read the comment and judge first whether anything in it is for you: a question you can answer, or an action that is yours. If something is, answer it, or do what it asks, on the ticket, once. If nothing is, end the round silently: no comment and no message; finish with `ost handback silent` and a one-line journal note. Never restate what someone else already said or asked. The ticket stays with its assignee: leave its assignee and status as they are, unless the comment asks you to take the ticket over.

A comment on a blocked ticket, by a human or an agent other than the agent blocked on it, wakes the agent blocked on it; unless the ticket is with an agent (who is unblocking it), the comment mentions an agent (that agent is woken), or an agent comments during its own round on the ticket.

Listens to ticket.commented. Decides: wake blocked_agent (kind ticket_comment).

When:

  • all of:
    • blocked_agent: true
    • not:
      • actor_kind: automation
    • not:
      • actor_is: blocked_agent
    • not:
      • assignee_kind: agent
    • not:
      • agent_mentioned: true
    • not:
      • actor_in_round: true

Instruction:

{{actor.id}} commented on {{ticket}}, which you handed back as blocked. Read the comment. If it unblocks the work, assign the ticket to yourself, move it to active and continue. Otherwise answer on the ticket what is still missing.

A human’s comment, mentioning no agent, on a ticket handed back to a human (in review, or blocked with no agent blocked on it) wakes the agent who last worked on it.

Listens to ticket.commented. Decides: wake last_worker (kind ticket_comment).

When:

  • all of:
    • actor_kind: human
    • not:
      • agent_mentioned: true
    • assignee_kind: human
    • ticket_status: review, blocked
    • not:
      • blocked_agent: true

Instruction:

{{actor.id}} commented on {{ticket}}, which you handed back. Answer the comment on the ticket. If it needs more work, assign the ticket to yourself, move it to active and do the work.

A human moving a ticket to active wakes the agent assigned.

Listens to ticket.moved. Decides: wake assignee (kind assigned).

When:

  • all of:
    • actor_kind: human
    • moved_to: active
    • assignee_kind: agent

Instruction:

{{actor.id}} moved {{ticket}} to active. Pick the work up.

A human moving a ticket assigned to a human to active, without the needs-human label, gives it back to the agent who last worked on it and wakes them.

Listens to ticket.moved. Decides: act for last_worker: assign it to the agent acted for, then wake them (kind assigned).

When:

  • all of:
    • actor_kind: human
    • moved_to: active
    • assignee_kind: human
    • not:
      • has_label: $needs_human

Instruction:

{{actor.id}} moved {{ticket}} to active and it is assigned to you again. Pick the work up.

Note posted with the change: none; the instruction is the wake’s.

A ticket canceled, or closed as done by someone other than the agent working on it, stops the work on it: every agent’s queued work on it and its pull requests is canceled, and an agent running such work is told to stop when its round ends. The agent who closed the ticket is left alone.

Listens to ticket.closed. Decides: stop the work on the ticket of every agent but the one who closed it; a ticket closed as done by an unknown closer or an automation stops nothing.

When:

  • ticket_status: done, canceled

Note posted with the change:

{{ticket}} was {{closed}} by {{closer}} at {{closed.at}}. Stop, and don't open a pull request for it. If the work belongs to another ticket, say which and hand back.

A sub-ticket closing wakes an agent on the parent ticket when the parent is open and that agent has more unfinished sub-tickets of it: the closed sub-ticket’s agent, else the parent’s. The agent planned their order when it split the parent, and picks the next one.

Listens to ticket.closed. Decides: wake assignee, else last_worker, else the parent’s agent (kind assigned) on the ticket’s parent, the first of them with more unfinished sub-tickets of the parent.

When:

  • all of:
    • ticket_status: done, canceled
    • parent_status: backlog, ready, active, review, blocked

Instruction:

{{ticket}} was {{closed}}. The open sub-tickets of {{parent}}: {{parent.open}}. Continue with the next one in the order you planned, the way the repository asks. When none is for you to do now (it waits on a human's review, or on a sub-ticket someone else has), you are waiting, not blocked: hand back silent, with no new message.

The last open sub-ticket of an active parent closing moves the parent on, for its agent: to done, with the agent, when the parent’s own pull requests merged; otherwise to review, with the requester.

Listens to ticket.closed. Decides: act for the parent’s agent: move the parent to done and assign it to the agent, when its own pull requests merged, else to review and assign it to the requester; when the closed ticket was its last open sub-ticket.

When:

  • all of:
    • ticket_status: done, canceled
    • parent_status: active

Note posted with the change: none, since the ticket shows the change. A team can add one with pipeline.policies.subtickets_closed_move_parent.instruction.

The last open sub-ticket of a parent in review or blocked closing closes the parent, for the agent that last worked it, with a note listing the closed sub-tickets: to done, with the agent, when the parent has no open pull request of its own; otherwise to review, with the requester. A parent canceled or done is left alone.

Listens to ticket.closed. Decides: act for the parent’s agent (the one it is assigned to, else the one that last worked it, else the closed sub-ticket’s): move the parent to done and assign it to the agent, when it has no open pull request of its own, else to review and assign it to the requester; when the closed ticket was its last open sub-ticket.

When:

  • all of:
    • ticket_status: done, canceled
    • parent_status: review, blocked

Note posted with the change:

{{ticket}} was the last open sub-ticket of {{parent}}. Its closed sub-tickets: {{parent.closed}}.

A sub-ticket moving to review, or closing, moves an active parent to review and gives it to the requester, for the parent’s agent, once every sub-ticket of it is done, canceled or in review, with at least one in review. A parent’s own open pull request counts only once it is open for review, not a draft. When every sub-ticket closed, subtickets_closed_move_parent moves it instead.

Listens to ticket.moved, ticket.closed. Decides: act for the parent’s agent (the one it is assigned to, else the one that last worked it, else the sub-ticket’s): move the parent to review and assign it to the requester; when every sub-ticket is done, canceled or in review, at least one in review, and no open pull request of its own is a draft.

When:

  • all of:
    • any of:
      • moved_to: review
      • ticket_status: done, canceled
    • parent_status: ready, active

Note posted with the change: none, since the ticket shows the change. A team can add one with pipeline.policies.subtickets_in_review_move_parent.instruction.

The last unfinished ticket of a milestone (a tracker initiative) closing wakes the team’s PM, to close the milestone, propose the next one and ask a trusted human to confirm it. The office counts the milestone’s tickets it knows; the PM checks the milestone in the tracker first.

Listens to ticket.closed. Decides: wake the PM (role:pm, kind milestone) on the closed ticket, when every other ticket of its milestone the office knows is done or canceled.

When:

  • all of:
    • ticket_status: done, canceled
    • in_milestone: true

Instruction:

{{ticket}} was {{closed}}, and it was the last open ticket of milestone "{{milestone}}" ({{milestone.id}}) that the office knows. Check with `ost milestone show {{milestone.id}}` that nothing in it is left. If it is finished, close it (`ost milestone status {{milestone.id}} done`), update the roadmap, propose the next milestone with what it will deliver, and ask a trusted human to confirm it. File its tickets only once they confirm.

A blocked ticket whose last open blocker was closed wakes the agent blocked on it, to check whether it can go on; the ticket stays where it is, since it may be blocked for other reasons too.

Listens to ticket.unblocked. Decides: wake blocked_agent (kind unblocked).

When:

  • blocked_agent: true

Instruction:

{{blocker}}, which blocked {{ticket}}, is closed, and no other ticket blocks it. You handed {{ticket}} back as blocked: check whether you can continue now. If so, assign it to yourself, move it to active and continue. Otherwise answer on the ticket what is still missing.

A blocked ticket whose last open blocker was closed, with no agent blocked on it, was only waiting on its blockers: it moves to ready, for the agent it is assigned to, who is then woken; else for the agent who closed the blocker. When the blocker is a sub-ticket of the same parent and that parent is with the same agent, the ticket is only moved and no one is woken here: the agent holding the parent coordinates its sub-tickets, and the idle pull starts this one when it has nothing queued.

Listens to ticket.unblocked. Decides: act for assignee: move the ticket to ready, then wake them (kind assigned), unless the blocker is a sub-ticket of the same parent and the parent is with that agent (parentAgent): then only move it; with no agent assigned, act for closer: move the ticket to ready.

When:

  • all of:
    • ticket_status: blocked
    • not:
      • blocked_agent: true

Instruction:

{{blocker}}, which blocked {{ticket}}, is closed, and no other ticket blocks it: {{ticket}} is ready again. Work on it the way the repository asks.

Note posted with the change: none; the instruction is the wake’s.

A human’s comment on a document wakes the agent it mentions, else the agent who wrote it.

Listens to doc.commented. Decides: wake mentioned, else doc_author (kind doc_feedback).

When:

  • actor_kind: human

Instruction:

{{actor.id}} commented on the document {{doc.title}}. Answer in the document and change it if needed.

An agent’s comment on a document wakes the other agent it mentions. An agent’s comment that mentions no other agent wakes no one.

Listens to doc.commented. Decides: wake mentioned (kind doc_feedback).

When:

  • all of:
    • actor_kind: agent
    • agent_mentioned: true

Instruction:

{{actor.id}} mentioned you in a comment on the document {{doc.title}}. Answer in the document and change it if needed.

A document an agent wrote for a ticket, in a round on the ticket or attached to it later, is shown on the ticket in the tracker, by its author with its own account. Bookkeeping: it wakes no one.

Listens to doc.linked. Decides: act for doc_author, else actor: link the document on the ticket, when the knowledge base can link documents on tickets (knowledge.issueLinks).

When: always.

Note posted with the change: none, since the ticket shows the change. A team can add one with pipeline.policies.link_doc_on_ticket.instruction.

A round of work starting on a ticket assigns the ticket to the agent and moves it to active, for the agent.

Listens to agent.started. Decides: act for actor: assign it to the agent acted for, move the ticket to active.

When:

  • all of:
    • work_kind: assigned, review_feedback, ticket_comment, rebase, ci_failed, merge_checks_failed
    • not:
      • ticket_status: done, canceled

Note posted with the change: none, since the ticket shows the change. A team can add one with pipeline.policies.start_marks_active.instruction.

A hand-back as done moves the ticket to review and gives it to the requester, for the agent, unless the agent handed the ticket over to someone else during the work; a ticket with open sub-tickets stays active with the agent instead, unless every sub-ticket is in review or closed. The work item’s other tickets awaiting review (the ones it created that are in review, and the ones whose pull request it opened) go to review and to the requester too. A merge round’s hand-back leaves the ticket as it is: nothing in it is left for the human.

Listens to agent.handed_back. Decides: act for actor: move the ticket to review, assign it to the requester, unless the agent handed the ticket over to someone else; a ticket with open sub-tickets stays active with the agent instead, unless every sub-ticket is in review or closed; the item’s other tickets awaiting review (the ones it created that are in review, and the ones whose pull request it opened) move to review and go to the requester.

When:

  • all of:
    • hand_back_status: done
    • not:
      • work_kind: merge
    • not:
      • ticket_status: blocked, done, canceled

Note posted with the change: none, since the ticket shows the change. A team can add one with pipeline.policies.hand_back_done.instruction.

A silent hand-back leaves the ticket as it was before the round: what the round’s start changed (the move to active, the assignment to the agent) is undone, for the agent. A field someone changed since is left alone, and so is a parent the agent kept active for its open sub-tickets. The work item’s other tickets awaiting review go to review and to the requester too. A blocked hand-back the office found waiting on work in flight (the ticket’s pull requests open for review, its sub-tickets in review or with an agent) comes as silent, and its trace names that work: no PM is woken, and no human is told again.

Listens to agent.handed_back. Decides: act for the agent: move the ticket back to the status it had before the round, and assign it back to whom it had, for each of the two still as the round’s start set it; the item’s other tickets awaiting review (the ones it created that are in review, and the ones whose pull request it opened) move to review and go to the requester.

When:

  • all of:
    • hand_back_status: silent
    • not:
      • ticket_status: done, canceled

Note posted with the change: none, since the ticket shows the change. A team can add one with pipeline.policies.hand_back_silent_restores.instruction.

A hand-back as blocked, or as done on a ticket the agent moved to blocked, on a team with no PM to unblock it (none, or the PM is the blocked agent), moves the ticket to blocked and gives it to the requester, for the agent, unless the agent handed the ticket over to someone else during the work. The work item’s other tickets awaiting review (the ones it created that are in review, and the ones whose pull request it opened) go to review and to the requester.

Listens to agent.handed_back. Decides: act for actor: move the ticket to blocked, assign it to the requester, when no PM unblocks it, unless the agent handed the ticket over to someone else; the item’s other tickets awaiting review (the ones it created that are in review, and the ones whose pull request it opened) move to review and go to the requester.

When:

  • all of:
    • any of:
      • hand_back_status: blocked
      • all of:
        • hand_back_status: done
        • ticket_status: blocked
    • not:
      • ticket_status: done, canceled

Note posted with the change: none, since the ticket shows the change. A team can add one with pipeline.policies.hand_back_blocked.instruction.

A hand-back as blocked, or as done on a ticket the agent moved to blocked, on a team with a PM other than the blocked agent, moves the ticket to blocked and gives it to the PM, for the agent, then wakes the PM to unblock it; unless the agent handed the ticket over to someone other than the PM during the work. The work item’s other tickets awaiting review (the ones it created that are in review, and the ones whose pull request it opened) go to review and to the requester, not the PM.

Listens to agent.handed_back. Decides: act for actor: move the ticket to blocked, assign it to role:pm; then wake role:pm (kind unblock), when the PM is not the blocked agent, unless the agent handed the ticket over to someone else; the item’s other tickets awaiting review (the ones it created that are in review, and the ones whose pull request it opened) move to review and go to the requester.

When:

  • all of:
    • any of:
      • hand_back_status: blocked
      • all of:
        • hand_back_status: done
        • ticket_status: blocked
    • not:
      • ticket_status: done, canceled

Instruction:

{{actor.id}} handed {{ticket}} back as blocked, and it is assigned to you to unblock. Try everything before involving a human: answer from what you know, find the information, or ask the right teammate with `ost ask`. When it is unblocked, comment the answer on the ticket and assign it back to {{actor.id}}. Only if a human is needed, assign it to the requester, {{requester}}, with a comment that says exactly what is needed. If all it waits on is a review the human already has (the ticket or its pull request is in review with them), nothing is blocked: leave it, send no new message, and hand back silent.

Note posted with the change: none; the instruction is the wake’s.

When work lands on a human, the agent tells them in a direct message in chat, with the ticket and pull request links and what is needed: a hand-back as done that gives the ticket to them, listing every ticket it gives them (the item’s sub-tickets in review and the tickets of the pull requests it opened too), a ticket in review or blocked that an agent gives to them (a PM that cannot unblock it, for example), or an agent’s pull request opened for review, for the requester of its ticket. The office batches one agent’s messages to one human.

Listens to agent.handed_back, ticket.assigned, pr.opened. Decides: notify the human in chat, as the agent: the requester on a hand-back as done (or the human the agent handed the ticket over to; nothing more when the work came from a chat thread, which gets the result), with every other ticket of the item the hand-back gives the requester for review, the assignee when an agent gives a ticket in review or blocked to a human (not the echo of an office act, nor the agent blocked on it), the requester of the ticket of an agent’s pull request opened for review; on policies.notify_handoff.

On only while policies.notify_handoff is on.

When:

  • any of:
    • all of:
      • hand_back_status: done
      • not:
        • ticket_status: blocked, done, canceled
    • all of:
      • actor_kind: agent
      • assignee_kind: human
      • ticket_status: review, blocked
    • all of:
      • pr_author_kind: agent
      • not:
        • pr_draft: true

An agent with nothing queued or running is woken with its next ready ticket: the highest tracker priority, then the one ready the longest (policies.pull_ready). For a sub-ticket of an open parent the agent is woken on the parent, so it takes the sub-tickets in the order it planned.

Listens to agent.idle. Decides: wake actor (kind assigned), with its next ready ticket (for a sub-ticket, on its parent).

On only while policies.pull_ready is on.

When: always.

Instruction:

You have nothing queued. Your next ready work is {{next.ticket}}. Work on it the way the repository asks.

Every event the pipeline decides on. A policy’s on lists some of them.

  • chat.message
  • pr.opened
  • pr.review_submitted
  • pr.comment
  • pr.merged
  • pr.closed
  • pr.conflicted
  • pr.ci_failed
  • pr.ci_passed
  • pr.behind_base
  • pr.base_merged
  • pr.linked
  • pr.merge_checks_passed
  • pr.merge_checks_failed
  • ticket.commented
  • ticket.assigned
  • ticket.moved
  • ticket.created
  • ticket.unblocked
  • ticket.closed
  • doc.commented
  • doc.linked
  • agent.started
  • agent.handed_back
  • agent.idle

An instruction or note may use these placeholders, written {{name}}. One the event does not have is empty, and an unknown name in pipeline.policies.<id>.instruction keeps the default instruction, with a warning in the office log.

  • ticket
  • status
  • actor.id
  • actor.kind
  • event.type
  • pr.number
  • pr.title
  • pr.url
  • pr.repo
  • pr.base
  • pr.head
  • pr.author
  • stack
  • stack.count
  • ticket.prs
  • ticket.prs.count
  • person
  • doc.title
  • pr.problem
  • cause
  • cause.number
  • cause.title
  • next.ticket
  • requester
  • blocker
  • checks
  • closer
  • closed
  • closed.at
  • parent
  • parent.open
  • parent.closed
  • milestone
  • milestone.id