Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Running Procedures

How procedures execute, park on waits, and resume — in both interactive and autonomous modes.

Execution Rules

When executing a procedure, the AI is an operator, not a collaborator. It follows the document exactly.

  1. Execute the current step exactly as written. Nothing more.
  2. Do not skip steps. Even if a step seems unnecessary.
  3. Do not add steps. If something isn't in the document, don't do it.
  4. Do not reorder steps. Follow transitions () as written.
  5. Do not improvise. If it says "post in #general", post in #general.
  6. Use exact references. {input.channel} means the channel from input.
  7. Wait means wait. If the step says **Wait**: 48h, stop. Do not proceed early.
  8. Log everything. After each step, append a log entry to the run page.
  9. If something fails, stop. Report the error. Do not retry unless the procedure says to.
  10. If something is ambiguous, ask. Do not guess.
  11. Respect the actor's permissions. Only access resources the current actor has tokens for.

Execution Modes

Interactive Mode

The user's AI executes steps while the user is present. The AI has the user's provider tokens and can ask for clarification. When it hits a wait step, it parks and tells the user what's being waited on.

Autonomous Mode

Gateway's internal AI executes steps without a user present. This happens when a scheduled sweep detects a wait condition is met (deadline passed, approval received). The AI is sandboxed — it uses the workspace bot token for Slack and the run creator's tokens for other providers.

A procedure might start interactively (user kicks it off), park on a wait, then resume autonomously (the system handles the timeout).

Execution Sequence

The AI never sees the full procedure source during execution. It works one step at a time, stopping after each:

1.  Call get_procedure(pageId) → see required input, step names, no instructions
2.  Collect all required input from the user
3.  Call start_run(procedureId, pageId, input, firstStep) → creates run in D1
4.  Call get_run(runId) → see current step instructions ONLY
5.  Execute the current step exactly as written
6.  Call log_step(runId, step, entry) → record what was done
7.  STOP. Report what was done and the result to the user.
8.  If wait → call park_run, stop. Turn is over until user asks to resume.
9.  If → done ✓ → call complete_run, stop.
10. When user says "continue" → call advance_step(runId, nextStep), go to step 4.

The AI stops after each step and waits for the user before continuing. After parking, it does NOT auto-resume — the user must explicitly ask to resume.

Parking a Wait

When a step has **Wait** or **Wait until**:

  • Set run status to waiting
  • Record wait_until (ISO timestamp when the wait expires)
  • Record wait_context (e.g., Slack message reference for approval polling)
  • Log the wait in the run page
  • Stop execution — do NOT proceed to the next step

Resuming

When a wait resolves, execution resumes with context about what triggered the resume:

TriggerContext
timeoutDeadline expired — follow **On timeout** handler
event: approvedApproval received — follow **On event** \approved`` handler
event: rejectedRejection received — follow **On event** \rejected`` handler

Run Log Format

After each step, a log entry is written to the D1 run_log table:

### route_approval — 2026-03-15 09:30
Posted approval request in #finance-approvals for $2,400 Denver conference trip.
Approver: COO (amount > $1,000).
Result: waiting for approval (48h timeout)

For autonomous execution, entries are prefixed with [auto]:

### process_reimbursement — 2026-03-17 10:00 [auto]
Approval received from @sarah. Updated expense status to "Approved".
Posted reimbursement request in #finance.
Trigger: event:approved by @sarah
Result: waiting for finance to confirm (5d timeout)

Run States

StatusMeaning
runningActively executing steps
waitingParked on a wait condition
completedReached → done ✓
failedA step failed and couldn't recover
cancelledManually stopped by a user or admin
needs_migrationProcedure had a major version bump while run was waiting
token_expiredA provider token failed during autonomous execution

Storage

During Execution (D1)

In-flight runs live in D1 behind code-enforced ACL. No Notion page exists during execution — admins and users query run data via the LLM.

TableWhat it stores
runsRun state, procedure snapshot, wait metadata
run_submissionsData collected during steps
run_logExecution log entries
run_accessCreator + dynamically assigned users

After Completion (Notion Export)

On any terminal status (completed, failed, cancelled), data exports to a Notion database under the procedure page:

Procedures (database)
├── expense-report (page)
│   ├── [procedure document]
│   └── Completed Runs (auto-created Notion DB)
│       ├── Run #1 — completed — $150 team lunch
│       └── Run #2 — cancelled — partial data

Admins can also manually trigger export at any time via procedure.export(runId).

Access Control

Runs are ACL-gated. Who sees what:

WhoWhat they see
AdminAll runs for procedures they admin. Full data.
CreatorTheir own runs. Full data.
AssignedRuns they're assigned to. Data from their step onward.
Everyone elseNothing. The run doesn't exist to them.

Dynamic assignment happens via **Assign** in procedure steps — when the LLM executes that step, it grants the assigned user access to the run.

Version Migration

Runs snapshot the procedure version at start. If the procedure is updated while a run is parked:

Version changeWhat happens
Minor (e.g. 1.01.1)LLM adapts on next resume — new step language applies going forward
Major (e.g. 1.12.0)Run status moves to needs_migration — admin must review or the LLM auto-migrates on resume

The LLM decides whether an edit is major or minor based on the nature of the change (structural vs cosmetic).

What the AI Must NOT Do

  • Call get_procedure_source during execution (that's for authoring only)
  • Read ahead to future steps or the full procedure document
  • Summarize steps instead of executing them
  • Combine multiple steps into one action
  • Skip notification steps ("they probably already know")
  • Change approval thresholds or routing logic
  • Continue past a wait step
  • Modify the procedure document during execution
  • Execute steps out of order
  • Access resources beyond the actor's token scope
  • Read procedure internals on behalf of non-admin users