Building a Loop
A loop is one document, its record, that says what the loop is for and everything a run of it may do. You write the record as a draft, try the draft in My conversations, and publish it. The version you publish is what runs, exactly as you approved it.
Two ways to start
Loops lists the loops that are yours. Reactor’s own assistants, such as LoopAssistant, are not listed there: they answer the Assistant button, New agent on Agents and Add tools from API docs on Tools, and are not changed or archived from Loops. An account with no loop of its own opens Loops on Start your first loop: copy a demo (the same ones Home offers), write one with New loop, or ask the Assistant to build one.
With LoopAssistant
Open My conversations. LoopAssistant asks what the loop is for, who will use it, what you already have, what a run must produce and what it may cost. It always asks what you already have, such as an endpoint, a price sheet or your docs, and it does not propose a new loop until you answer. “Nothing” is an answer. It chooses the agents the loop runs itself, from the platform’s agents or one it proposes for you, so it does not ask you which agent to use.
When the loop needs an agent of your own, LoopAssistant starts a second agent that writes it. Its card, Install agent, appears in the same chat. Approving installs the agent into your account and runs nothing; LoopAssistant then names that agent in the loop it proposes. The agent’s role is one of the platform’s roles, or one your account defined if you name it.
It then proposes the loop as a card that names, in words, every tool, collection, output and cost the loop would get. Its first lines say what the loop does, who can use it, what it saves, what it reads, and which collections are new: “Approving creates Leads.” names each one your account does not have yet. Before you see the card, the proposal is checked against the rules publish applies to the record, so a loop that publish would refuse goes back to LoopAssistant to fix. Read the card, then press Save as draft to keep it or Decline to throw it away. The card says when it must be answered, Answer by a time in your own time zone, and once that time has passed it says so and that nothing was saved. The chat stays open: say “save it” and LoopAssistant shows the card again from what you already told it. After a Decline, LoopAssistant asks what to change and does not offer the same change again, and its next card is the one you declined with only that change in it; anything more it thinks the loop needs, it asks you about first. If the next card changes more than that, the card says which parts differ from the one you declined, by the card’s own headings, such as “What it may spend”, under Check before you approve above Save as draft, so you can decline it again. The same box says when the loop may do something no tool it calls needs, has fewer than three test cases, has a test case that expects a record saved but leaves empty an answer the loop’s form requires, or promises an email that nothing sends. A test case that expects nothing saved, such as a question about prices, is not named, because its run may never show the form. Pressing Save as draft with a warning in that box is your answer to it: LoopAssistant keeps the draft as you approved it, and changes it only if you ask. The model that drafts a loop never publishes it by itself.
Once a draft is saved and its test cases ran, the chat says so, with Open it on Loops and Try it in My conversations under that line: the second opens a new chat on the draft, so you can try it before anyone else can. Try it in My conversations on the loop’s own page does the same. Once the test cases passed, LoopAssistant asks to publish it with a Publish card in the chat. A card is answered in its own conversation: in any other conversation, and on a new chat, it shows as one line, such as Go to “Bike quote log”, that opens the conversation it belongs to. The card leads with what the draft changes against the version people reach now, by the same headings as an edit’s card, and the whole loop is one press away; a loop never published shows itself whole. Pressing Publish publishes that draft in your name, with the same checks as the Publish button in Loops. If the draft was saved again after the card opened, or a check refuses it, nothing is published and the card says why. Decline leaves the draft unpublished, and you can still publish it in Loops.
While LoopAssistant works, or waits on a card or another agent, Stop takes the place of Send in the box, and Stop stays beside the chat’s name too. Enter still sends a message, which it reads before its next step. While a card waits, its next step comes after you answer the card, so a line under the chat says your message is held until then. When it waits on your own answer, Send is back.
LoopAssistant also changes a loop you already have. It proposes the change as an edit to the record, and the card leads with the change:
- It names the version the edit changes: “Changes published v3. Approving saves draft v4.”, or “Changes draft v3, which is not published yet. Published v2 keeps serving until you publish.”
- Under What changes against that version, it lists what the edit adds, removes and changes. A long text, such as what a run is told, shows only the words that change: added words are underlined, removed words are struck through, and the unchanged words around them are cut to ”…”. What a run returns, a collection’s fields and the input that fills a field are said in words, such as “Now holds bike, name and email, and needs name and email.” or “adds the field bike (Text)”, with the definition as written under As written. A test is named by its first question, and a changed test says what its run must reach and what it enters when asked for details, such as “Now it must finish and save the phone in Repair requests.” A change to the tests is marked This changes what publishing tests: a test that fails stops the publish.
- A change that alters what a run is told or may do is marked changes what a run is told or may do. A change to who can reach the loop, such as a site you add, is marked changes who can reach it.
- Show the whole definition opens the whole loop as it will be after the change.
An edit names only what
changes and keeps the rest: a list such as checks merges by the name of each entry, and a group
of settings such as end_messages merges by key. So “change the closing message” changes
end_messages.completed and leaves the other end messages as they were.
A conversation with LoopAssistant shows what it says and what it asks you. The steps it takes on the way, such as reading your loop, are folded into the working steps line at the top: press show to read them, with what you were charged for them. Each step is named in words, such as List files or Propose a loop. A step that did not run says why in one sentence, such as Not run — what it sent was not valid, so it was told what to fix. Your answer to a proposal names what you decided, such as You approved the loop proposal. A conversation with your own loop shows every step, named in the same words, such as Save a record — saved in demo_helpdesk_tickets. Press a step to open what was called and the full result, because that is where you check what your loop does. A step that did not run keeps its reason on the step itself. Above the box, Thinks before answering or Answers directly, and Asks you before it acts or Allows without asking (yolo), say how the next chat runs; hold the pointer on one to read what it changes. An answer to one of its approvals names the step in the words its card used, such as You approved the step to save a record. A step that saved a record opens to the record as it was saved, read from its collection, including the fields the platform filled from the person’s form; a record keyed on a value the person gave links to its collection instead.
By hand
- Open Loops and press New loop.
- Type a loop id: a lower-case letter, then lower-case letters, digits or underscores —
lead_qualification, notlead-qualification. The id names the loop and never changes. - Press Write its first draft. The editor opens on a starter record that already saves.
- Edit the record, then press Save draft v1.
The record
The record is YAML. Every key in the starter is required, and the starter’s comments say what each one is for. The keys you will change most:
| Key | What it says |
|---|---|
name, description | How the console names the loop. |
entry | The standing instruction. The model reads it on every turn; your users never see it. Every turn is also told today’s date and weekday, in UTC, so the entry can say “next Monday” or “this year” without naming a date. The console shows a line break inside a paragraph as a space, and keeps the breaks of paragraphs, lists, headings and code; the model reads the entry exactly as you wrote it. |
agents | The only agents a run may use. With more than one, entry_agent names the one a person meets. |
capabilities | The ceiling. A tool that needs anything outside this list is not available to a run, unless grantable lets a run ask for it. Permissions and trust says how the two combine with an agent’s role. |
collections | The only collections a run may write. |
tools | Your own endpoints that a run may call. |
sources, indexes | What a run may read, and which of your search indexes it may search. |
checks | What a run’s work must pass, including the test cases that run before publish. |
outputs | Where a result goes: a collection, a signed webhook, or an email. |
gates | Which steps wait for a decision, and who decides. |
identity | How a user proves who they are, and the per-address and per-user limits. |
delivery | Where users reach the loop, and from which web origins. |
on_topic | Optional. Which messages the loop answers: about is one sentence that names everything the loop answers, and reply is what a person reads when their message is not. With refuses: true an off-topic message gets reply in place of the answer; without it the topic check only records what it decided. A loop anyone can reach should declare it; see Keep the chat on topic. |
chat | Optional. show_activity: true shows the visitor each step the loop takes while it works, then folds them into one line under its reply that they can open. Absent, the chat shows the conversation alone. See What your visitor sees. |
ends | Optional. How a conversation may end. finish: false means the loop never ends a conversation itself: it answers each follow-up, and the conversation ends when the person goes quiet. Use it for a search or Q&A loop. idle_minutes (1 to 60) is how long the person may stay quiet, after a reply or with a question open, before the conversation ends. Absent, the loop may end the conversation when its job is done, and a reply waits 10 minutes. See Asking the user. |
triggers | What starts a run: a conversation, a schedule, an event, or your own server. |
budgets | What one run, one user and one month may spend. Per run must not be more than per user, and per user not more than monthly. Per run and per user must each cover at least one model call at pay-as-you-go prices ($0.0010), because a Pro plan can lapse and the loop must still run. |
end_messages | The user’s last line for each way a run can end, and otherwise for every ending you did not name. |
When the platform refuses a save or a publish, the refusal names the field and what to change.
Help in the editor
Hover a key in the editor to read what it is for. More shows the key’s full definition, and a key with a fixed set of values lists them. Hover a capability to read what it lets a run do.
The editor marks problems as you type and says each one in words: a key it does not know, a value
outside its set (`emial` is not allowed here: `kind` must be one of: email, text, choice, choices, boolean.), a missing key, a capability the platform does not have, and a rule that depends on
another key, such as an upload source that names no file. A yellow mark is a guess: an agent or a
tool your account does not seem to have. Publishing decides it.
The platform still checks the draft when you save, with every rule publish applies to the record itself, in the same words. So a draft that saves is refused at publish only for something outside the record: an agent, tool or index your account has not installed yet, a secret it has not stored, or a test case that has not passed. A gate on a step that no run of the loop can call is refused too, and the refusal names the capability or the tool that would let it fire. Each problem it names is marked on its line as well as listed under the editor. The editor changes only the text you type, so your comments stay.
Try the draft
The loop’s page on Loops shows a draft that was never published in words, as it shows a published version: what a run in it is told, and every tool, collection, output and cost it would get once published, with the document below.
A draft never serves a user. Only My conversations can start a run in one: start a new conversation and pick the loop and the version, draft included. The run shows on All runs like any other, so you can read every turn, every tool call and every record it wrote. A record whose fields the platform filled from what the person gave in a form shows as a link to its collection instead, because the run never holds the person’s values.
Publish
Press Publish… on the loop’s page (Publish the change… once the loop is published). The card says in plain words what the loop is told and may do; the record itself is under Show the full definition. If the loop has test questions, the card starts them itself when they have not run on this text, says that each costs a few cents, and Publish waits until every one passes, saying why while it waits.
When the change is to a published loop, the card leads instead with What changes against what runs now, from the moment it opens, while the test questions run and after one fails: each key the change adds, removes or changes, and a mark on a change to what a run is told or may do. Everything else is under Show the whole definition. If the change is saved again while the card is open, the card says so and Publish waits: press Cancel, then Publish the change… again.
Publishing does three things:
- The version is fixed. A published version is never written again.
- The loop gets its public id (
pl_…) on its first publish. Your page, your server and your keys name the loop by this id, and it stays the same for every later version. - New runs start on the new version. Runs already in flight finish on the version they started under.
Publish also refuses a record that cannot work as written. For example, it refuses:
- a record whose agents cannot do the work the record declares,
- a
crawlsource when no agent that a run starts listsrecords_query, or anuploadsource when none listsread_file, because no run could read it, - a crawl into a collection the loop does not declare,
- a tool that needs approval when no gate says who approves it.
Each refusal names the agent, the tool or the field, and the fix.
Some things a record may get wrong are flagged instead of refused, because only the words can show them. Saving the draft and the publish review both list them, and neither press waits on them:
- an entry that names a tool no run of the loop can call, such as
web_fetchwhen the loop does not holdread_web. A run then has no such tool and writes the call as text. If the entry means not to use the tool, nothing needs to change. - indexes the loop searches, beside an entry that never says to search them. A run treats its entry as true, so a price written there wins over the price the index holds.
- an end message that promises the visitor an email, such as “we’ll email you to confirm”, when
the loop has no tool or webhook that could send it. An
emailoutput sends only to the one address it names, never to the visitor. If a person sends that email, nothing needs to change. LoopAssistant’s card shows this one too. - an entry that mentions emailing or notifying your staff, such as “then email the shop to notify
staff” or “an email is sent to the shop on each saved request”, when an
emailoutput already emails them. A run cannot send email, and a run told about the email tells the visitor it went, even while it is held for an address that is not confirmed. Take every mention of it out of the entry and say what the run tells the visitor, such as that their request is saved. LoopAssistant’s card shows this one too. - an end message that says an email went or your staff were told, such as “we’ve emailed the
shop”, in a loop with an
emailoutput. That email is sent after the run and is held until its address is confirmed. LoopAssistant’s card shows this one too. - an entry that tells the run to ask for an approval, or describes the wait for one, such as “ask
the operator to approve saving this request” or “that call will pause for the operator’s
approval”, when
gates:already holds that step. The platform asks the approver and holds the step by itself, so a run told this asks the person in the chat instead. Say in the entry what the run does once the step ran, and what it says if it was refused. LoopAssistant’s card shows this one too. - a test case with an
agentturn that says an approval happened, such as “Operator approves saving the request”. A transcript answers no approval card: answer it under the case’sapprove, and take that turn out. LoopAssistant’s card shows this one too. - a collection field for when a record was saved, such as
created_at,submitted_at,saved_atortimestamp, that nobindfills. A run cannot know the time, so it writes a guess. Every record already keeps the time it was saved (created_ts) and the time it last changed (updated_ts), and the Collections screen shows them. Remove the field. A time the visitor gives, such as anappointment_time, is not flagged. LoopAssistant’s card shows this one too. - a permission under
capabilitiesthat no tool of the loop’s agents needs, such assend_externalwhen no tool sends anything. Every run holds it and nothing uses it. Remove it unless a step you know of needs it. LoopAssistant’s card shows this one too. While the loop names an agent your account does not have, this one is not shown: that agent’s tools are not known yet.
A name under tools that publish would refuse is flagged when you save the draft, so you learn
it before you publish. The draft still saves, because you may install a tool after you name it:
- a built-in tool, such as
request_inputs. Remove it fromtools; a run holds it whencapabilitieslists what it needs. - a capability, such as
write_records. Remove it fromtoolsand list it undercapabilities. - a name no tool in your account has yet. Install the tool, or declare it inline, before you publish.
An agent under agents that your account does not have is flagged the same way, first, with the
agents you can choose from. Install it, or name one of those, before you publish.
Change a published loop
On the loop’s page, type what you want to change under What do you want to change?, such as “A tune-up is now $65”, and press Ask LoopAssistant. LoopAssistant opens in the Assistant panel, in a tab named for the change, with your words already sent. It proposes the change for your approval there; then Publish the change… on the loop’s page publishes it. While a change waits to publish, or on a loop that was never published, what you ask adds to that change, and the box says so; Publish the change… and Discard the change… stay beside it.
To change the record yourself, press Change it yourself: the editor opens on the published record as the next change. Save it, try it, and publish it like the first. Discard the change… removes the waiting change and nothing else. On a loop that visitors reach, Try it as a visitor opens the chat at the top of its page.
A collection the loop declares can gain fields from one version to the next, and records written before simply lack the new field. Saving the draft refuses an edit that removes a field the loop declared before (in its published version or its saved draft), or changes a field’s type or key. The refusal names the fields: keep them, or declare a new collection. A field the loop never declared (you added it on the collection, or a pipeline or another loop did) stays, and leaving it out refuses nothing.
Archive a loop
An owner of the account can press Archive this loop. An archived loop serves nobody. Runs already in flight finish, and every published version stays readable. Reopen this loop makes it serve again.