Skip to main content
Version: Current

Playbooks

A playbook is a set of tasks that leads to a result: the tasks a selection must cover before it is submitted, the order in which they open, the choices between several ways of doing a task, and the tasks that only hold for some selections.

playbooks:
- name: open-company
goal: "open a company: the structure, then (optionally) the accounting"
tasks:
formation: {skill: formation, label: "Your company"}
accounting: {skill: accounting, required: false, label: "Your accounting", after: [formation]}

- name: take-meal-order
goal: "order a meal: the dishes, then pickup or delivery"
tasks:
dishes: {skill: takeMealSelection, label: "Your dishes"}
handover:
label: "Pickup or delivery"
after: [dishes]
one_of: # two methods, one skill: each is one of its kinds
pickup: {skill: takeDeliveryOption, kind: pickup}
delivery: {skill: takeDeliveryOption, kind: delivery}
choose: customer # the person picks (the default)

The goal and the tasks​

  • goal is the result the playbook leads to, in a sentence. It is what the agent sees in order to offer it (start_playbook, its brief). Absent, the playbook's name is shown.
  • tasks are keyed by name: the name after, all_of and $submitted[<task>.<call>] cite, never the skill's.

A task is written in exactly one of these three forms:

formmeaning
{skill: x}, or {skill: x, kind: k}the action of a skill; with kind, of a single kind of that skill
{one_of: {method: {skill, kind, when, params}}, choose: …}several methods; only one does the task
{all_of: [a, b]}done when a and b are done; a meeting point for after

And on the task:

keymeaning
whenthe task only holds if this condition holds (Conditions) — on every form
requiredthe playbook cannot be submitted without it — true by default. Not on an all_of
labelthe task's title as the person reads it, in their language: in the stepper and at the head of its lines in the selection. Absent, the skill's name made readable, in English. Not on an all_of
afterthe tasks that must be done before this one opens. Not on an all_of
paramsbinds parameters of its skill to what another task filed (A task's params). On the {skill} form and on each method of a one_of; never on the one_of itself nor on an all_of

An all_of is not a step: it has no title, no place in the stepper, no lines of its own, and it never blocks the submit. Each task it names says for itself whether it is required.

A skill is the action of a single task of a playbook: a card finds its task by its skill. Two methods of one one_of may share a skill, as long as each names its own kind. Two playbooks may give the same task name; only a $submitted[…] written on a skill's call, which holds for the whole station, refuses a name that designates two different calls (The submit).

Choosing a method — choose​

A one_of has at least two methods. Each is the action of a skill (skill), or of a single one of its kinds (kind), and may carry a when. Only one method does the task.

valuewho chooses
customer (default)the person, among the methods whose when holds. The step presents them, each with the tool that shows it; the agent is told to call one or the other, depending on what the person asks for
rulethe first method whose when holds. The others' lines are refused. If that method's skill is withheld from the station, the task has no method: it is skipped, the next method is not taken in its place

A method without when is mandatory: it always holds, so the task always has a method. Under rule, it is the last one.

Conditions — when​

A when, on a task or on a method, reads one thing only: $selection.kinds, the kinds of the lines still in the selection and of what this journey has already filed. It is read as a list, on the right of in or not in:

      wrapping:
skill: gift-wrap
required: false
when: "'gift' in $selection.kinds"
  • A task whose when is false is skipped: it is not a step, never blocks the submit, and its lines are refused. The tasks placed after it do not wait on it. If the condition cannot be evaluated, the task holds.
  • A method only holds if its when is true.
  • A when does not look at its own task's kinds: a task's line is not chosen yet when it is added, so the condition would close it for ever. Condition a task on what comes before it.

A task's params​

A skill reads its parameters ($params.<name>) in the args of its submit calls. A task binds a parameter of its skill to what another task of the same playbook filed: $submitted[<task>.<call>].<output>.

skills:
- name: repondre
params:
refund_id: {} # no default: only a task sets it
invoke: {method: draftReply}
kinds: {reply: {}}
submit:
- {name: send, tool: sendReply, args: {body.draft: "$item.ref", body.refund_id: "$params.refund_id"}}

playbooks:
- name: ticket
tasks:
geste:
label: "Gesture"
one_of: # each method has a call `pay` that keeps `id`
remboursement: {skill: rembourser}
avoir: {skill: avoir}
reponse:
skill: repondre
label: "Reply"
params: {refund_id: "$submitted[geste.pay].id"}
  • The reference makes the order. reponse waits for geste, as if after: [geste] were written: a line of reponse is refused until geste is done ("Reply opens once Gesture is done — choose that first").
  • A binding is read in its own playbook. Two playbooks may give the same name to different tasks: each reads its own.
  • A choice is one reference. Both methods of geste have a call pay: $submitted[geste.pay] reads the one that was filed.
  • At submit, the call of reponse leaves after the call of geste, in the same submit, with its answer. Outside this playbook, the parameter is its default; what the submit does when nothing sets it is in The submit.

How it opens​

  • auto_trigger on a skill: using it opens the playbook.
  • start_playbook: the agent opens it itself, when it judges it is the right journey.

The agent chooses. A playbook without auto_trigger is flagged at load time ("only reachable through start_playbook").

What it guarantees​

  • A task is done when the selection contains an item of a kind of its methods that hold (a method's kind, else every kind of its skill). This is read from the selection, never from the conversation: the person can stop and come back. A skipped task counts as done for the tasks that wait on it; an all_of is done when each task it names is. A choice that holds two methods, or a method ruled out, is not done: the journey stays on it.

  • The order and the choices, at each choice (step_open). While the playbook is active, a line is refused, with the reason, in the station's language, and nothing is written, when:

    • a task of its after is not done: "Your accounting opens once Your company is done — choose that first";
    • its task does not hold for this selection: "wrapping does not apply to this selection";
    • it is of a kind of the skill its task does not take (kind): "Pickup does not take this choice";
    • its method does not hold: "delivery is not available for Pickup or delivery with this selection";
    • under choose: rule, another method is the one: "Pickup or delivery is done by pickup with this selection";
    • another method of the task is already in the selection: "Pickup or delivery: pickup is already in your selection — remove it to take delivery instead". An add that replaces the other method in its part (max_items: 1) goes through: the order is checked on the selection as the add leaves it.

    What this journey already filed counts as chosen. In the stepper, a waiting task is shown as not available, with the kinds still missing. A task also waits for the tasks its params read. Without after or params, tasks can be done in any order.

  • The submit is blocked, with the reason:

    • as long as a required task that holds is not done: "Pickup or delivery is required by this order — add pickup or delivery first";

    • as long as the selection keeps a line the submit must not file — chosen before the journey opened, or made wrong by a later choice:

      • a line of a task that no longer holds (its when turned false after the choice: pickup replaced the delivery a courier message was written for): "Courier message does not apply to this selection";
      • a line of a kind its task does not take: "Pickup does not take this choice";
      • a method ruled out by the rule or by its when: "Pickup or delivery is done by pickup with this selection", "delivery is not available for Pickup or delivery with this selection";
      • two methods of one choice: "Pickup or delivery takes one choice — keep only one of: pickup, delivery".

      The agent reads it too: while it is so, it says what holds the submit and lets the person remove the line, instead of offering to confirm.

    A task already filed by a partial submit of this journey stays done — for a choice, the filed method stays its method, whatever the rule or a when says afterwards, and another method's line is refused: the rest can be retried.

  • If the journey's state cannot be read, choosing a line a playbook rule binds and the submit are blocked too, with a sentence that says so ("the order of this flow cannot be checked right now — try again in a moment"): never an order out of sequence or without its required tasks.

These sentences come from Convoy's catalogue, in French or English according to global.language; the tenant's widget.labels do not change them.

What load refuses​

writtenrefused because
a task with none of the three forms, or severalnobody could tell what it does
kind without skill, choose without one_ofthey apply to nothing
a skill or a kind that is not declaredthe task would have nothing to show it done
a skill in two tasks of the same playbooka card could not tell which task it belongs to
two methods that take the same kinda line could not tell which method it is
a one_of with fewer than two methods, or where every method has a whenit is no choice; or a selection could leave no method at all
under choose: rule, the method without when before another onethe methods after it could never be chosen
a method whose skill produces no kindnothing could show it chosen
a required task that nothing produces a kind fornothing could show it done
a when that reads anything other than $selection.kinds ($memory, $submitted[…], $read[…], $result[…], $item…), or does not read it as a listthe reason is given: it cannot be read here
a when that looks for a kind the station does not havethe condition would never hold (or always, with not in)
a task's or a method's when that looks for a kind of its own task (for an all_of, of the tasks it joins)the line is not chosen yet when it is added: the task would stay closed, or change between the choice and the submit
an all_of of fewer than two tasks, that names itself or a missing taskthe meeting point would never be reached
required, label or after on an all_ofit is not a step
an all_of over tasks ordered between themthey cannot be done together
an after that names a missing task, or a task nothing can show donethe task would never open
an after or an all_of that loopsno task of the loop would ever open
a required task placed after an optional one, directly or through an all_ofit would make the optional one required in practice
params on a one_of (write them on each method) or on an all_ofthey run no skill of their own
a binding to $read[…]a read leaves no trace a task can read yet
a binding to $result[…]sub-playbooks do not exist yet
a binding to a fixed value, or to any other $… referencea fixed value is the skill's default; a task binds only to $submitted[<task>.<call>].<output>
a binding to a parameter the skill does not declare, or that its invoke.args readsit would set nothing; or the invoke would read the default while the submit reads the binding
a binding to a task missing from the playbook, to the task itself, to a call the task does not make, to an output the call does not keep, to a call that is not a requestthe reference would resolve empty
a binding to a task that has a whenit may be skipped: its answer would never exist
a binding to a one_of with a method that does not make the callchosen, that method would leave nothing to read
an after contrary to a binding (geste placed after reponse, which reads it)the written order contradicts the data
a required task whose params read an optional taskit would make the optional one required in practice
a skill parameter without default that no task bindsnothing would set it: every call reading it would be held

What it does not guarantee yet​

  • Conditions on anything but the chosen kinds. A when reads neither a room fact, nor a total, nor what a task read or filed. For a real data dependency, use depends_on on the skill: it holds even outside the journey.
  • Choice by the model. No choose: clm, no fallback.
  • What a task sets or starts. No params bound to $read[…] or $result[…]; no depends_on, on_open or guards on a task; no result, no playbook-level submit_guard, no activation, no sub-playbooks. Every tool stays presented to the model, whichever task is open.
  • Reads (the skills that only answer) cannot be required tasks, nor be cited by an after: they produce no kind, nothing shows them done.

See Current limits.