Documentation
User Guide & API Reference
A real-time control plane where machine jobs, AI agent actions and human approvals share one event grammar, one policy engine and one view of process health.
Every capability described here is implemented and exercised. Capabilities that are not yet available are listed in Section 12 rather than described as though they work. A claim you can check is a claim that holds when you check it.
1. Platform overview
Traffic Lights orchestrates business processes in which humans, AI agents and machine systems are first-class participants. Each participant emits and receives the same standardised events, operates under the same versioned policies, and appears in the same audit record.
The platform separates two things most tools combine:
- Execution — what runs next. Handled by rules over the process graph.
- Decision — what should be done about an outcome. Handled by versioned policies: retry, escalate, notify.
Traffic Lights does not replace your execution engines. It sequences them, decides what happens when they produce an outcome, and records who decided what.
What the platform provides
| Capability | Description |
|---|---|
| Process orchestration | Author a process as tasks, flows, actions and policies. Flows carry conditions, so a process can branch on the content of an event. |
| Human-in-the-loop | A process pauses at a human task, an approver decides, and the process resumes. Approve, reject and delegate are all first-class. |
| Agent participation | AI agents propose actions and are recorded as agents — distinct from both people and machines — in every audit view. |
| Independent corroboration | A task can compare a proposed value against an independent record and refuse when they disagree, without a person in the loop. |
| Policy-driven decisioning | Versioned, effective-dated policies decide retry, escalation and notification. Changing a policy does not require a deployment. |
| Real-time health | Every process and run carries a derived Red / Yellow / Green state with full lineage to the event that produced it. |
| Audit by default | Every event, decision and approval is recorded with an actor, a timestamp and an outcome. The record is append-only. |
2. Core concepts
| Term | Definition |
|---|---|
| Process | A definition: a set of tasks, the flows connecting them, the actions they dispatch, and the policies that govern them. Versioned and effective-dated. |
| Task | An atomic unit of work. A task is machine-executed, human-decided, or agent-proposed. |
| Flow | A directed edge between tasks. Carries an optional condition that gates whether the downstream task dispatches. |
| Action | What a task actually does when dispatched. A task may fan out to several actions. |
| Policy | A versioned rule governing what happens in response to an outcome — retry, escalate, or notify. |
| Run | One execution of a process. Identified by a run ID that correlates every event, decision and record end to end. |
| Event | A standardised message emitted by a task, an agent, an external system, or the platform itself. |
| Traffic state | Derived health: Green (healthy), Yellow (attention needed), Red (critical). |
| Principal | An identity that acts: a person, a service, or an agent. Resolved and displayed differently for each. |
2.1 Execution types
A task declares what kind of participant executes it. This determines how the platform dispatches it and how it appears in the audit record.
| Type | Executed by | Behaviour |
|---|---|---|
| Machine | A system | Dispatched to an action; completion is reported back as an event. |
| Human sign-off | A person | The run pauses. An approver approves, rejects or delegates. |
| Agent proposal | An AI agent | The agent proposes an outcome. The proposal is recorded as a proposal, attributed to the agent, and is subject to the same policies as any other outcome. |
| Corroboration | A checker | Compares a claimed value against an independent record and returns confirmed or rejected. The comparison is made by the checker; the platform records the verdict and branches on it. |
| No-op | — | A marker step. Records that a stage was reached without dispatching work. |
Why corroboration is separate. A corroboration is not a task someone performs. It is an independent comparison whose verdict the process branches on — so an agent's confident proposal can be refused by a check that never asked the agent. The audit record shows both the proposal and the refusal.
3. Authentication
Every route is authenticated. Two methods are supported.
| Method | Header | Use |
|---|---|---|
| Bearer token | Authorization: Bearer <token> | Interactive callers. A person signed in through the application, or a service acting with a user's identity. |
| API key | X-API-Key: <keyId>.<secret> | Machine callers. The secret half is returned once when the key is minted and never again. |
Bearer wins. A route consults the API key only when no Authorization header is present. An empty or placeholder Authorization header silently disables the key. Machine callers must send no Authorization header at all.
3.1 API key scopes
A key carries one or more scopes. Scopes are exact and are not hierarchical.
| Scope | Grants |
|---|---|
read | Read routes. |
audit:write | The approval-history write route, and nothing else. |
principal:resolve | Resolving a set of identifiers you already hold into display names and delivery addresses. Cannot list, cannot search, refuses empty or wildcard requests. |
ingest | Reserved for event submission. No endpoint accepts it yet — see Section 12. |
Scopes are not a disjunction. A key holding audit:write is refused by every read route. A key minted with an unrecognised scope is dropped at resolution and returns 401 — indistinguishable from an invalid key.
4. REST API
Base URL: https://api.<environment>.traffic-lights.io. All business routes are under /api/v1.
4.1 Health
| Method | Path | Auth | Response |
|---|---|---|---|
| GET | /health | None | 200 {"status":"ok"} |
4.2 Processes
| Method | Path | Notes |
|---|---|---|
| GET | /api/v1/processes | List process definitions for your tenant. |
| POST | /api/v1/processes | Create a process definition. Versioned on write. |
| GET | /api/v1/processes/{id}/runs | Run history for a process. |
| GET | /api/v1/processes/{id}/status | Current derived health and per-task state. |
| GET | /api/v1/processes/{id}/policies | Policies attached to a process. |
Tasks, flows and actions are created and read under /api/v1/tasks, /api/v1/flows, /api/v1/actions and are always scoped to a parent process.
4.3 Policies
| Method | Path | Notes |
|---|---|---|
| GET | /api/v1/policies | List all policy types available to your tenant. |
| POST | /api/v1/policies | Create a policy. Effective-dated on write. Changing a policy does not require a deployment. |
| GET | /api/v1/policies/{id} | Read a specific policy version. |
Two policy types do nothing. Delegate and branch policies are accepted, stored and returned by the API, but nothing acts on them. Use retry, escalate, notify and halt. See Known limitations.
4.4 Approvals
| Method | Path | Notes |
|---|---|---|
| GET | /api/v1/approvals | List pending approvals for the authenticated caller. |
| GET | /api/v1/approvals/{id} | Read a specific approval with full context. |
| POST | /api/v1/approvals/{id}/approve | Settle as approved. Run resumes. |
| POST | /api/v1/approvals/{id}/reject | Settle as rejected. Accepts optional reason field. Run does not continue past the rejected task. |
| POST | /api/v1/approvals/{id}/delegate | Pass authority to a named delegate. Hop recorded in the decision chain. |
4.5 Approval history
| Method | Path | Notes |
|---|---|---|
| POST | /api/v1/approval-history | Write an approval history record. Requires audit:write scope. Append-only. |
| GET | /api/v1/approval-history/{runId} | Read the complete decision chain for a run. |
4.6 Principal resolution
| Method | Path | Notes |
|---|---|---|
| POST | /api/v1/principals/resolve | Given identifiers you already hold, returns display name, identity kind and delivery address. Requires principal:resolve scope. |
Deliberately narrow. This route converts an identifier you possess into an address. It cannot discover one you do not have — there is no listing form, no search by name or email, and an empty or wildcard request is refused.
4.7 Error behaviour
- A first request to an idle service may take several seconds. Retry once.
- Validation failures return
422with a structureddetailarray — one entry per field, naming the field path, the rejected value and a machine-readable error type. All violations are reported, not just the first.
5. Events
Every participant communicates through the same event shape. An event carries an envelope, which says what kind of event it is, and a detail, which carries the facts.
{
"source": "sai.tl.router",
"detail-type": "FLOW_COMPLETE",
"detail": {
"runID": "MEC-20260827T042400Z",
"taskID": "20001202",
"status": "SUCCESS",
"severity": "INFO",
"message": "Flow complete"
}
}
| Field | Level | Description |
|---|---|---|
source | envelope | Where the event came from. |
detail-type | envelope | The event category. |
runID | detail | The correlation identifier, end to end. The most important field in the system. |
taskID | detail | Which task the event concerns. |
status | detail | STARTED | SUCCESS | FAILED |
severity | detail | ERROR | WARN | SUCCESS | INFO | DEBUG |
message | detail | Human-readable description. |
timestamp | detail | Stamped automatically. |
Severity is not decoration. Notification delivery filters on severity before choosing a channel. An event that omits severity defaults to INFO, which is below the default threshold and is suppressed. An emitter that builds its detail from scratch must set severity explicitly.
5.1 Conditions on flows
A flow may carry a single comparison that gates whether its downstream task dispatches: a path into the event, an operator, and a value.
detail.status == FAILED
Conditions fail open. An expression the parser cannot read is treated as true, with a warning. A malformed gate is indistinguishable from a satisfied one and the branch runs. Keep conditions to a single comparison.
6. Approvals, delegation and expiry
A human task pauses the run and creates a pending approval addressed to a principal. Four outcomes are possible.
| Outcome | Meaning |
|---|---|
| Approve | The run resumes and the next task dispatches. |
| Reject | The decision is recorded with an optional reason. The run does not continue past the rejected task. |
| Delegate | Authority passes to a named delegate. The pending approval is repointed and the hop is recorded in the decision chain. |
| Expire | No person decided within the window. The platform settles the approval as expired and the task reads as blocked. The audit record shows expiry, not rejection — the absence of a decision is not a decision. |
6.1 The decision chain
Every approval carries a chain showing who did what, in order, with timestamps. A delegated approval shows the delegator, the delegate, and who ultimately decided. The chain names people, services and agents distinctly — a delegation to a colleague and an action by a service are never displayed the same way.
Delegation depth. The chain displays how many delegations have occurred and how many are permitted. The permitted count is currently a display value; the platform does not yet refuse a delegation that exceeds it.
6.2 Identity in the audit record
Every actor in a decision chain is resolved to one of five kinds.
| Kind | Meaning |
|---|---|
| Person | Resolved to a named member of your tenant. |
| Service | A platform component acting under its own identity. |
| Agent | An AI agent, shown by the label it was assigned. Agent labels are displayed exactly as written and are never looked up as people. |
| Unknown | The identifier was looked up and no matching member was found. |
| Unresolvable | The directory could not be read at all. |
Why the last two are separate. "We looked and found nobody" and "we could not look" are different facts. Collapsing them would let a directory outage read as a missing person.
7. Notifications
Notifications are delivered when a policy asks for one, when an approval is requested, and when an approval breaches its deadline.
| Aspect | Behaviour |
|---|---|
| Channels | Email and Microsoft Teams are implemented. Other channels are not. |
| Recipient | For an approval request, the assignee is resolved to a delivery address at send time. There is no fallback address — if the recipient cannot be resolved, the platform refuses to send and records why. |
| Severity threshold | A per-tenant threshold suppresses events below it. Notifications a tenant explicitly asked for — an authored policy or an approval request — are delivered regardless of the threshold. |
| Deduplication | Repeated notifications for the same task and the same state within a short window are suppressed. Different runs of the same process are always distinguished. |
| Per-tenant config | Channel credentials and delivery settings are held per tenant. A tenant with no configuration is refused rather than defaulted to another tenant's channel. |
8. Agents and the MCP surface
Traffic Lights exposes its API as a tool surface for LLM-driven agents, so an agent can read processes, examine runs, author drafts and settle approvals through the same authenticated routes a person uses.
- An agent acts as the caller whose credential it holds. It cannot name a tenant — that parameter does not exist on any tool — and every write is stamped with the tenant from the credential.
- Agent actions appear in the audit record as agent actions, distinguishable from both people and services.
- Process drafts can be created, previewed and finalised, so an agent can propose a process definition for review before it becomes live.
Agents propose; policies decide. An agent's proposal is an outcome like any other. It is subject to corroboration, to approval, and to the same policies. Nothing an agent proposes bypasses a gate a human would have faced.
9. Multi-tenancy
Every record is scoped to a tenant, and the tenant is always taken from the caller's credential — never from the request body. A request that names a different tenant does not reach another tenant's data.
- Process definitions, runs, approvals and audit history are all tenant-scoped.
- Two tenants may use the same process names without collision.
- Directory reads return only your tenant's members. Platform staff are withheld from tenant directories.
9.1 Roles
| Role | May |
|---|---|
| Administrator | Author and modify process definitions, policies and users. Settle approvals. |
| Process owner | Settle approvals. Read everything in the tenant. |
| Approver | Settle approvals. Read everything in the tenant. |
| Viewer | Read only. |
Shared authority. Any holder of an approving role may settle an approval, not only the named assignee. Today the approvals list shows each user the approvals addressed to them specifically — so an approval a colleague could settle may not appear in their list. This is being addressed.
10. Retry and escalation
A failed task can be retried under a retry policy, and a task that breaches its deadline can escalate under an escalation policy. Both are authored as policies rather than configured in code, so they can be changed without a deployment.
| Concept | Behaviour |
|---|---|
| Retry policy | Governs how many attempts a failed task receives and with what delay. |
| Circuit breaker | Refuses further retries after repeated failures within a window, then allows a single probe attempt before closing. |
| Escalation policy | Fires when an approval passes its deadline. Names who to escalate to and through which channel. |
Retry is not a governance decision. A policy reacts to an outcome a task produced. A mechanical retry reacts to no outcome at all — the attempt did not land, and nothing decided anything. Where retries exhaust is where a governance response begins.
11. Known limitations
Each of these is current, measured, and visible to you through the API. They are listed so this guide does not assert capability the product does not have.
| Limitation | Detail |
|---|---|
| Two policy types do nothing | Delegate and branch policies are accepted, stored and returned by the API, and nothing acts on them. Halt policies are enforced. Use retry, escalate, notify and halt. |
| A run has no deadline | A task has a deadline and an approval has a deadline. The run itself does not. A run that stops making progress stays open until somebody notices. |
| An abandoned run reads as running | A run whose work has stopped is shown as in flight, not as stalled. One run read as healthy for thirteen days. |
| Approval windows not honoured | An approval policy may name its own window in seconds. That value is not carried into the store the engine reads, so every approval falls back to the deadline of the task it sits on. |
| Escalation resolves to the sweep | Escalation is evaluated by a periodic sweep that runs every thirty minutes, so an approval that names a five-minute window escalates on a thirty-minute boundary. |
| Conditions fail open | An unparseable flow condition is treated as true and the branch runs. |
| Branches cannot rejoin | Mutually exclusive branches cannot converge on a shared downstream task. A conditional split needs a complete path on each side. |
| A false condition ends its branch | A skipped step does not continue past itself. There is no "skip this step and carry on". |
| Delegation is unbounded | The permitted-hops value is displayed and not enforced. |
| Approvals listed by assignee only | A role-holder who is not the named assignee can settle an approval that does not appear in their list. |
| Task lists show identifiers | The process definition view shows raw identifiers rather than names. Run detail and the approvals list resolve names correctly. |
| Self-approval not prevented | The platform does not record who requested a run, so it cannot refuse an approval by the requester. |
| Retry has not executed | Implemented; no retry has run in a live system. |
12. Not yet available
These are planned and are not built. They are named here so that nothing in this guide reads as though they exist.
| Capability | Status |
|---|---|
| Event submission over REST | External systems cannot yet submit events over the API. A scope is reserved for it and no endpoint accepts it. |
| One-tap approval from email | Approval notifications link into the application, where you sign in and decide. Deciding directly from the email without signing in is not yet available. |
| Segregation-of-duties controls | Preventing a requester from approving their own request requires the platform to record the requester, which it does not yet do. |
| Structured input on an approval | An approver may approve, reject or delegate. A decision cannot yet capture structured input — acknowledgements, required fields, or anything the process author wants recorded alongside the decision. |
| Attaching an outcome to a run | A defect, complaint or incident discovered later cannot yet be attached to the run that produced it. |
| Fan-in on the process graph | Two branches cannot converge on a shared downstream task, so a conditional split needs a complete path on each side. |
A claim you can check is a claim that must hold when you check it. Everything in Sections 11 and 12 is verifiable from the API by anyone with a key — which is why it is here rather than omitted.