Guidance topics
The modeling guidance the AI can look up with lookup_guidance, word for word.
The AI calls lookup_guidance with one of these topics before drafting in a known domain, or when it is unsure of the syntax or a pattern. The in-app assistant has the same topics. Select a topic to see the exact text the AI gets back.
Patterns
For BPMN diagrams: the Flowmark syntax, the modeling style the app follows, and patterns that apply to any process.
Flowmark syntax (what write_diagram takes and get_diagram returns)
process <name>
lanes <Lane A> | <Lane B> optional, fixes lane order
lane <name> following nodes go in this lane
pool <name> [(below)] an outside party (customer, supplier, bank) drawn as a black-box pool above the process, or below it
<kind>[:<event>[(<arg>)]] <name> [#id]
kinds: start end catch throw task user service manual script rule send receive call sub xor and or eventgw
events: message timer error signal conditional escalation terminate compensation; timer args are ISO 8601 (P2D, PT4H, R/P1W)
Indented lines under a node:
<label> [<condition>] (default) -> <target> explicit flow; label, condition and (default) are optional
on:<event>(<arg>) <name> -> <target> interrupting boundary event (on~ for non-interrupting)
doc: <text> documentation: the longer description, hidden on the diagram; repeat for more lines
note: <text> a short note shown beside the node on the diagram (an SLA, a system, "manual for now"); repeat for more lines
=> <pool>: <message> the node sends a message to an outside pool
<= <pool>: <message> the node receives a message from an outside pool
A doc: line before the first node documents the process.
Inside a paragraph each node connects to the node on the line above it. A blank line starts a new paragraph (a new path).
A node with explicit "->" lines does not continue to the next line, and end events never do.
Targets are node names (case-insensitive) or #id; give a node an #id when its name is not unique or it has no name (e.g. merge gateways: "xor #merge").
// starts a comment when it begins the line or follows a space (links like https://… are kept).
get_diagram prints every node with its #id. Keep those ids when you rewrite a diagram, so the user's references stay stable.
Example
process Purchase request
pool Supplier (below)
lanes Employee | Manager | Procurement
lane Employee
start Need identified
user Submit purchase request
lane Manager
xor #resubmitted
user Review request
note: SLA 2 working days
on~timer(P2D) Review pending two days -> Send reminder
xor Request approved?
yes -> Send purchase order
needs changes -> Revise request
no (default) -> Notify rejection
lane Procurement
send Send purchase order
=> Supplier: Purchase order
end Order placed
lane Employee
user Revise request
-> #resubmitted
lane Manager
send Notify rejection
end Request rejected
send Send reminder
end Reminder sentModeling style (BPMN Method & Style conventions)
- Your process is one pool; its lanes are roles or departments, not people or systems unless the system does the work. Outside parties (customer, supplier, bank) are separate black-box pools that exchange messages with it.
- Name activities verb + object ("Approve invoice"), events as a state ("Invoice received", "Payment overdue"), decision gateways as a question ("Amount over 10k?"), and the flows leaving them as answers ("yes", "no", "over 10k").
- Start and end events are always explicit. Use distinct end events for distinct outcomes ("Order shipped", "Order cancelled") so the outcomes are readable at a glance.
- Never let a task split or merge flows implicitly: use a gateway for every split and every merge, and match the gateway type of a split with its join (parallel with parallel, inclusive with inclusive).
- Keep one level of detail per diagram: 5-20 activities. Wrap a detailed area in a call activity or sub-process instead of growing the diagram.
- Pick task types deliberately: userTask (a person in a system), manualTask (offline work), serviceTask (automated), sendTask/receiveTask (messages to/from another party), businessRuleTask (decision table), callActivity (reusable sub-process).
- List the happy path first; exceptions and rework branch off it. The layout keeps the first branch straight.
- Model time limits and failures as boundary events on the activity they interrupt, not as gateways after it.
- Notes (note: lines) are for a short fact people should see on the diagram: an SLA, the system used, "manual for now". Documentation (doc:) holds the longer description and is hidden on the diagram. A note never replaces a step, timer or decision the user described: "the underwriter can lower the loan amount" is a decision and a task, not a note.Gateway patterns (Flowmark)
Exclusive decision with a default:
xor Credit check passed?
yes -> Approve loan
no (default) -> Decline application
Parallel work (fork + join with matching parallel gateways):
and #fork
-> Ship goods
-> Send invoice
service Ship goods
and #join
...
service Send invoice
-> #join
Inclusive (one or more branches): use "or" for the split and an "or" join; give each branch a condition.
Event-based race (whichever happens first):
eventgw Wait for reply
-> Reply received
-> Five days passed
catch:message Reply received
...
catch:timer(P5D) Five days passed
Rework loop: a "needs changes" branch goes to a revise task, which points back at an unnamed merge gateway placed just before the earlier task ("xor #resubmitted" ... "-> #resubmitted"), so no task gets two incoming flows. The same goes for an event a loop comes back to.
A decision inside parallel work: a parallel join waits for every flow into it, so merge the decision's branches with an exclusive gateway first and lead that one flow into the join:
and #fork
-> Inspect vehicle
-> Screen for fraud
manual Inspect vehicle
-> #join
service Screen for fraud
xor Fraud suspected?
yes -> Investigate claim
no (default) -> #screened
user Investigate claim
-> #screened
xor #screened
-> #join
and #join
A branch that has to stop everything (a claim closed as fraudulent while other work runs) ends in end:terminate instead of reaching the join.
Avoid: a gateway that both merges and splits; joining parallel branches with an exclusive gateway (creates duplicate tokens); leading a decision's branches straight into a parallel join (it waits forever for the branch not taken); a loop from after a parallel join back into one of its branches (on the next pass the join waits forever for the others), so a rework that starts after the join comes back to a merge after it.Events and exceptions
- Start: none (manual start), message (a request arrives), timer (scheduled, e.g. start:timer(R/P1M) Month started), signal, conditional.
- Intermediate catch: timer waits (catch:timer(P3D)), message waits for another party.
- Boundary events attach to the activity they interrupt:
user Review contract
on:timer(P5D) Review overdue -> Escalate review (interrupting)
on~timer(P2D) Reminder due -> Send reminder (non-interrupting: work continues)
on:error Validation failed -> Correct data
- End: none, message (notify a party), error (process fails), terminate (stop all parallel work), escalation.
- Every exception path should end in its own named end event or rejoin the main flow.
- A reminder or deadline over several steps ("remind the handler on day 25", "decide within 30 days"): put the timer on the activity that keeps the work open, or group the steps in a call activity and put it there; non-interrupting (on~) for a reminder. Don't add a parallel branch that waits on a timer: it never joins, keeps the case open, and still fires after the work is done. In an existing diagram, put the timer on the step that keeps the work open; don't merge or rename steps to make room for it.Pools and messages (black-box pools)
- Your process is the main pool; each outside party it deals with (customer, supplier, carrier, bank, regulator) is a pool of its own, drawn as a thin band. Only its exchanges show, not its internal steps.
- A message goes between one step of your process and one outside pool. Name it after what is sent ("Purchase order", "Tracking update"), not the action.
- Send with a send task, or a message intermediate throw or end event: "=> Pool: message". Receive with a receive task, or a message start or intermediate catch event: "<= Pool: message". Plain tasks can do both.
- Gateways never send or receive. Boundary events can't take messages here; put the message on the task or on a message catch event after an event-based gateway.
- Messages are not sequence flow: the process still needs its own flows from start to end. Waiting for a reply is a receive task or message catch event on the flow.
- Put the customer above the process and partners (suppliers, carriers, banks) below it: "pool Carrier (below)".
- Add pools when the conversation matters to the reader. Every pool should have at least one message.
Example
process Order tracking
pool Customer
pool Carrier (below)
lanes Warehouse | Customer service
lane Warehouse
start Order packed
send Book pickup
=> Carrier: Pickup request
receive Pickup confirmed
<= Carrier: Pickup confirmation
lane Customer service
send Tell customer it shipped
=> Customer: Shipping notice
end Order shippedApproval pattern
Roles: Requester, Approver (often Manager), sometimes Finance/Compliance for thresholds.
Shape: submit -> review -> decision (approved / needs changes / rejected).
- "needs changes" loops back to the requester's revise task, which returns to review.
- Threshold routing: an exclusive gateway on amount before review ("Amount over limit?") adds a second-level approver.
- Four-eyes principle: the second approver is a different role/lane.
- Add a non-interrupting timer reminder and an interrupting escalation timer on the review task.
- Outcomes: "Request approved", "Request rejected" (and notify the requester with a send task).Escalation and SLA patterns
- Reminder without interrupting: on~timer(P1D) Reminder due -> Send reminder, then end "Reminder sent".
- Escalation that takes over: on:timer(P3D) SLA breached -> Escalate to supervisor, rejoining the main flow after.
- Measure SLA from a clear start event; name timers after the condition ("SLA breached"), not the mechanism.
- For multi-level escalation, chain escalation tasks or loop back with a counter decision ("Escalation level < 3?").Layout and polish: making a diagram easier to read without changing the process
The app lays the diagram out on a grid. You can't place shapes, but edit_diagram's set_layout sets how far apart steps sit and puts steps moved by hand back in place. get_diagram's "Layout:" line shows the spacing each way, how many steps were moved by hand, and the lanes top to bottom as they are drawn.
Spacing steps, tightest first: compact, standard (the default), roomy, spacious. "across" is the gap between columns of steps, left to right; "down" is the gap between rows and lanes. "spacing" sets both.
What people ask, and what to do
Steps count from where each direction is now, and the two can differ: when they do, set across and down separately, each its own step on (across spacious and down roomy, one step tighter, is across roomy and down standard).
- "Improve the spacing", "more spacious", "a bit more room", "easier to read", "less cramped", "it's crowded": one step roomier each way (standard -> roomy, roomy -> spacious).
- "A lot more room", "really spread it out": two steps roomier, up to spacious.
- "More room between the steps", "wider", "the arrows are squashed": one step roomier across only.
- "More room between the lanes", "between the rows", "taller", "the lanes are tight": one step roomier down only.
- "More compact", "tighter", "too spread out", "fit it on one screen", "smaller": one step tighter each way (or in the one direction they name), down to compact.
- "Normal spacing", "back to default", "reset the spacing": standard both ways.
- "Tidy up", "tidy the layout", "put the steps back", "straighten it out", "line it up": tidy: true, which puts steps moved by hand back in their automatic spots. If none were moved, say the layout is already on its grid and offer roomier spacing.
- "Clean up the layout", "polish the diagram", "make it look nicer", "make it presentable", /polish: tidy: true, one step roomier each way that is at compact or standard, and check the lane order below. Do it all in one edit_diagram call.
- Already at spacious and asked for more room: say it's at the roomiest spacing, and suggest a call activity for a detailed area if the diagram is large.
- Already at compact and asked for less: say it's at the tightest spacing.
A plain "clean it up" or "fix it" is about modeling problems, not layout: follow the fixing rules.
Lane order
Order lanes top to bottom in the order the work first reaches them, the lane with the start event at the top, so flows run mostly down and right. When polishing, check this every time against the Layout line's lane order: if the start event's lane isn't at the top, or the work keeps climbing back up the page, move lanes with update_lane and its index (0 is the top). When the order already follows the work, leave it. Outside pools stay where they are.
What polishing never does
- Never add, remove, rename, retype or reconnect steps, change lanes' membership, or add notes. Those change the process; ask first if you think they would help, and say why.
- Never use write_diagram to polish: rewriting puts every hand-moved step back and risks changing the process.
- Don't touch spacing when the user asked only for a tidy up, or tidy up when they asked only for spacing, except for "polish" requests.
Finish with one or two sentences in plain words: what you changed ("I made the spacing roomier both ways and put 3 moved steps back in place") and the next step ("Say 'more' for even more room, or undo to go back"). Don't list the process back.Schema code syntax (DBML; what write_diagram takes and get_diagram returns)
Project <name> { the diagram's name, database and note (optional)
database_type: 'PostgreSQL' PostgreSQL, MySQL or SQL Server: sets the types you write
Note: 'What this schema is for'
}
Table <name> [headercolor: #3498DB] { a table; schema.name outside the default schema; "as <alias>" before the settings
<column> <type> [<settings>] one column per line
Note: 'What a row is'
indexes {
(a, b) [pk] a composite primary key
email [unique] a unique index; (a, b) [unique] across columns
created_at a plain index; [name: 'ix_name', type: btree]
}
}
Column settings, comma separated: pk, increment, unique, not null, default: <value>, note: '...', ref: > other.id
default: 0 / true / 'draft' / `now()` a value, or an expression in backticks
ref: > users.id this column points at users.id: many to one
ref: - users.id one to one; ref: <> tags.id many to many (better a junction table)
Ref: orders.customer_id > customers.id [delete: cascade, update: no action]
a relationship on a line of its own; name it with Ref name: ...
Ref: order_items.(order_id, line) > orders.(id, line)
composite keys
Enum <name> { a type with fixed values; columns use it by name
pending
paid [note: 'Money received']
}
TableGroup <name> { a frame round related tables
orders
order_items
}
// <text> a comment on a line of its own
Names with spaces or symbols go in double quotes: "order items". Text goes in single quotes.
Columns are nullable unless marked not null; primary key columns are never null.
get_diagram prints every element's id. Keep those ids when you rewrite a diagram, so the user's comments stay on their elements.
Example
Project shop {
database_type: 'PostgreSQL'
}
Enum order_status {
pending
paid
shipped
}
Table customers {
id integer [pk, increment]
email varchar(255) [unique, not null]
name varchar(120) [not null]
created_at timestamp [not null, default: `now()`]
}
Table orders {
id integer [pk, increment]
customer_id integer [not null, ref: > customers.id]
status order_status [not null, default: 'pending']
total decimal(10,2) [not null]
created_at timestamp [not null, default: `now()`]
}ER diagram style
- One schema per diagram, named for the system it serves ("Online store", "Team workspace").
- Plural snake_case table names, snake_case columns, <thing>_id for foreign keys.
- A primary key on every table; composite keys for junction tables.
- Foreign keys with the type of the key they point at; not null when the row can't exist without its parent.
- Enums for fixed states, lookup tables for lists that change.
- Constraints that protect the data: unique emails and slugs, not null on required fields, sensible defaults.
- Money as decimal, times as timestamp, flags as boolean with a default.
- Indexes on columns searched or joined often.
- Table groups for areas of the system once the schema passes about eight tables.Domains
Reference processes for common business areas: the usual roles, trigger, happy path, decisions, exceptions, controls and KPIs. The AI adapts them to what you tell it about your organization.
Change management (ITIL) reference
Getting an IT change from request to production safely: assessment, approval, scheduling, implementation and review.
Lanes: Change requester, Change manager, Change advisory board (CAB), Implementation team, Service owner.
Trigger: `start Change requested`.
Happy path:
1. Submit request for change (Requester, `user`).
2. Assess impact and risk (Change manager); classifying as standard, normal or emergency is often a `rule` task.
3. Approve change (CAB for normal changes, see the approval topic).
4. Schedule change in the change calendar (Change manager).
5. Implement change (Implementation team).
6. Verify change (Service owner).
7. Review and close change (Change manager), ending in "Change closed".
Decisions: Change type (standard: pre-approved, skip the CAB; normal: CAB; emergency: emergency CAB)? Approved? Verification passed?
Exceptions:
- Rejected or sent back for more information: notify the requester, or loop back to the request.
- Implementation fails or verification fails: an error boundary event on the implementation leads to "Roll back change", then the review, ending in "Change rolled back".
- Implementation window missed: a timer on the scheduled wait reschedules.
Controls: separation between implementer and approver, a backout plan before approval, a freeze calendar.
KPIs: change success rate, emergency change ratio, incidents caused by changes, lead time for changes.Customer support reference
Handling a support ticket from first contact to a confirmed resolution, with escalation to specialists and engineering.
Lanes: Customer, Support agent (L1), Specialist (L2), Product or engineering.
Trigger: `start:message Ticket received` (email, chat, web form).
Happy path:
1. Triage ticket (Support agent): category, priority, customer tier.
2. Search knowledge base (Support agent).
3. Provide solution (Support agent, `send`).
4. Wait for the customer's confirmation, ending in "Ticket resolved".
Decisions: Known issue? Needs a specialist? Bug confirmed? Customer confirms?
Exceptions:
- Needs a specialist: escalate to L2, which may need engineering.
- Bug confirmed: create an engineering issue (`send`), wait for the fix (`catch:message Fix released`), then reply to the customer.
- Customer silent: an event-based gateway between the reply and a timer (for example P7D) auto-closes with a notice.
- Customer reopens: loop back to triage through a merge gateway.
- First-response SLA: a non-interrupting timer on triage alerts the team lead.
KPIs: first response time, resolution time, CSAT, first contact resolution, backlog age.Employee onboarding reference
From an accepted offer to a productive new hire: records, equipment, access, first week and check-ins.
Lanes: HR, Hiring manager, IT, Facilities, New hire.
Trigger: `start:message Offer accepted`.
Happy path:
1. Create employee record (HR, `user` in the HR system).
2. In parallel: prepare equipment and accounts (IT), prepare workspace (Facilities), plan the first week (Hiring manager). Join all three.
3. Welcome new hire (Hiring manager, `manual`).
4. Complete compliance training (New hire, `user`).
5. Hold 30-day check-in (Hiring manager), ending in "Onboarding complete".
Decisions: Remote or on-site (skip the workspace, ship equipment instead)? Does the role need privileged access (an extra approval)?
Exceptions:
- Background check fails or the start date falls through: end "Offer withdrawn", and cancel the parallel preparation with `end:terminate`.
- Equipment not ready a few days before the start date: a timer boundary event escalates to the IT lead.
- Training not completed by its deadline: a reminder, then an escalation to the manager.
Controls: right-to-work verification before day one, access granted on least privilege, signed policies.
KPIs: day-one readiness, time to productivity, 90-day retention, new hire satisfaction.Incident management (ITIL) reference
Restoring service after an unplanned interruption: logging, triage, diagnosis, resolution and closure.
Lanes: User, Service desk (L1), Support group (L2 or L3), Incident manager.
Trigger: `start:message Incident reported` (or a monitoring alert, also a message start).
Happy path:
1. Log incident (Service desk, `user`).
2. Categorize and prioritize (Service desk); priority from impact and urgency, often a `rule` task.
3. Investigate and diagnose (Service desk first, then the support group).
4. Apply fix or workaround (Support group).
5. Confirm resolution with the user (Service desk, `send`, then wait).
6. Close incident, ending in "Incident closed".
Decisions: Major incident? Resolved at first line? User confirms the fix?
Exceptions:
- Major incident: switch to the major incident procedure, a `call` activity owned by the Incident manager.
- Resolution SLA at risk: a timer boundary on the investigation escalates to the next support level.
- User doesn't respond after resolution: a timer on the confirmation wait auto-closes the incident.
- User rejects the fix: reopen and loop back to investigation through a merge gateway.
Controls: priority matrix, SLA targets per priority, a problem record for recurring incidents.
KPIs: mean time to resolve (MTTR), first contact resolution, SLA compliance, reopen rate.Insurance claims reference
Property and casualty claims from first notice of loss to settlement: registration, coverage, assessment, fraud screening and payment.
Lanes: Policyholder (message partner), Claims intake, Claims adjuster, Special investigations unit (SIU), Finance.
Trigger: `start:message Claim submitted` (first notice of loss).
Happy path:
1. Register claim (Claims intake, `user`).
2. Verify coverage (Claims intake; `service` against the policy system).
3. Screen for fraud indicators (`rule` or a scoring `service`).
4. Assess damage (Claims adjuster, `manual` when on site).
5. Calculate settlement (Claims adjuster).
6. Approve settlement (Claims adjuster, or a senior adjuster above their authority limit).
7. Pay claim (Finance, `service`), ending in "Claim paid".
Decisions: Covered? Fraud suspected? Above authority limit? Repair or replace?
Exceptions:
- Not covered: send a denial letter with the reasons ("Claim denied").
- Fraud suspected: refer to SIU (`call`); it may end in "Claim denied" or return to assessment.
- Missing information: request it and wait with a timer.
- Policyholder disputes the settlement: an appeal loop back to assessment through a merge gateway.
Controls: authority limits per adjuster level, reserve setting at registration, payment approval separate from calculation.
KPIs: claim cycle time, loss adjustment expense, leakage, customer satisfaction, reopen rate.KYC customer onboarding reference
Opening an account for a new customer at a bank or regulated financial firm: identity verification, sanctions and AML screening, risk rating and account setup.
Lanes: Applicant (message partner), Onboarding operations, Compliance (KYC and AML), Relationship manager (for business customers), Core banking (system).
Trigger: `start:message Application received`.
Happy path:
1. Check application completeness (Onboarding).
2. Verify identity (`service` for document and biometric checks).
3. Screen against sanctions and PEP lists (`service`).
4. Assess customer risk (`rule`: low, medium, high).
5. Open account (`service` in core banking).
6. Send welcome pack (`send`), ending in "Account opened".
Decisions: Application complete? Identity verified? Screening hit? Risk rating (standard due diligence or enhanced due diligence)?
Exceptions:
- Missing documents: request them and wait with an event-based gateway; close the application if nothing arrives within the deadline ("Application lapsed").
- Possible sanctions or PEP match: manual review in Compliance; a true match ends in "Application declined", and a report to the regulator if required (`send`).
- High risk: enhanced due diligence (source of funds, senior approval) before opening.
- Business customers: identify the ultimate beneficial owners, often a `call` activity.
Controls: four-eyes approval for high-risk customers, an audit trail of checks, periodic review scheduling once the account is open.
KPIs: time to onboard, application drop-off rate, false-positive screening rate, share of applications needing manual review.Loan origination reference
From a loan application to funds disbursed: completeness, credit and risk assessment, decision, offer and disbursement.
Lanes: Applicant (message partner), Loan officer, Underwriting, Credit committee (above a threshold), Operations.
Trigger: `start:message Application received`.
Happy path:
1. Check application completeness (Loan officer).
2. Run KYC and AML checks (a `call` activity, see kyc-onboarding).
3. Pull credit report (`service`).
4. Assess risk (`rule`): automatic approval, manual underwriting or decline.
5. Underwrite loan (Underwriting) when the rule says manual.
6. Prepare and send offer (Loan officer, `send`).
7. Wait for acceptance (event-based gateway: acceptance message or offer expiry timer).
8. Disburse funds (Operations, `service`), ending in "Loan disbursed".
Decisions: Complete? Risk band? Above committee threshold? Offer accepted before expiry?
Exceptions:
- Missing documents: request and wait, with a timer to lapse the application.
- Declined: send an adverse action notice with reasons where regulation requires it ("Application declined").
- Applicant withdraws: a message boundary event on underwriting ("Application withdrawn").
- Offer expires: "Offer expired".
Controls: lending authority limits, committee approval for large exposures, KYC and AML before the decision, affordability checks.
KPIs: time to decision, time to fund, approval rate, pull-through rate.Month-end close reference
Closing the books each month: cut-off, accruals, reconciliations, review and reporting.
Lanes: General ledger accounting, Accounts payable, Accounts receivable, Financial controller, CFO or finance director.
Trigger: `start:timer(R/P1M) Month ended`.
Happy path:
1. Cut off subledgers (AP and AR, in parallel): post the remaining invoices and receipts.
2. Post accruals and prepayments (General ledger, `user`).
3. Run depreciation and allocations (General ledger, `service`).
4. Reconcile balance sheet accounts (General ledger): bank, intercompany, suspense.
5. Review reconciliations and journals (Financial controller).
6. Run trial balance and variance analysis.
7. Prepare management reports, approve them (CFO), and lock the period, ending in "Period closed".
Decisions: Reconciliation differences within tolerance? Variances explained? Adjustments needed?
Exceptions:
- Unreconciled difference: investigate and post an adjusting journal, then reconcile again (rework loop).
- Close deadline at risk: an interrupting timer on the review (for example working day 5) escalates to the controller.
- Late invoices after cut-off: accrue them rather than reopening the period.
Controls: journal approval above a threshold, preparer and reviewer separation, sign-off on reconciliations.
KPIs: days to close, number of post-close adjustments, reconciliations completed on time.
Modeling note: the subledger cut-offs and many reconciliations run in parallel. Fork with `and`, join with `and`, and keep each branch to one or two activities so the diagram stays at one level.Order to cash reference
From a customer order to cash collected: order entry, credit, fulfilment, invoicing and collection.
Lanes: Customer (often only a message partner), Sales or order desk, Credit control, Warehouse, Accounts receivable.
Trigger: `start:message Order received`.
Happy path:
1. Validate order (Sales): customer, prices, terms.
2. Check credit (Credit control, `service` when automated against a limit).
3. Reserve stock (Warehouse, `service`).
4. Pick and pack order (Warehouse, `manual`).
5. Ship order (Warehouse) and send invoice (Accounts receivable), often in parallel after picking.
6. Receive payment (Accounts receivable, `receive` or a message catch).
7. Apply payment (`service`), ending in "Order paid".
Decisions: Credit OK? Stock available (ship in full, ship partially, backorder)? Payment received by the due date?
Exceptions:
- Credit hold: a manual review in Credit control; release, or cancel the order ("Order cancelled").
- Out of stock: backorder and notify the customer, or ship partially.
- Payment overdue: a timer on the payment wait starts dunning (reminder, second reminder, collections).
- Cancellation by the customer before shipping: a message boundary event on fulfilment.
Controls: credit limits, pricing approval for discounts above a threshold, segregation between order entry and credit release.
KPIs: order cycle time, on-time in-full delivery, days sales outstanding (DSO), perfect order rate.Patient referral reference
A referral from a primary care provider to a specialist: triage, insurance authorization, scheduling and the feedback loop.
Lanes: Referring provider, Referral coordinator, Specialist clinic (triage clinician), Payer (message partner), Patient.
Trigger: `start:message Referral received`.
Happy path:
1. Register referral (Referral coordinator, `user` in the scheduling system).
2. Triage referral (Triage clinician): urgency and the right service.
3. Check prior authorization requirement (`rule`).
4. Schedule appointment (Referral coordinator) and notify the patient (`send`).
5. See patient (Specialist clinic, `manual`).
6. Send consultation report to the referring provider (`send`), ending in "Referral completed".
Decisions: Referral complete and appropriate? Urgency (urgent, routine)? Prior authorization needed and approved?
Exceptions:
- Incomplete or inappropriate referral: return it to the referring provider with the reason ("Referral returned").
- Prior authorization: request it from the payer and wait (event-based gateway: approval, denial, or a timer to chase).
- Patient doesn't respond or doesn't attend: reminders, then rebook once, then discharge back to the referrer.
- Urgent cases: a timer on scheduling (for example P2D for suspected cancer pathways) escalates to the clinic lead.
Controls: clinical triage by a qualified clinician, waiting-time targets by urgency, consent and privacy rules on sharing records.
KPIs: referral-to-appointment time, did-not-attend rate, share of urgent referrals seen within target, referral return rate.Permit application reference
A public sector permit or licence (building, business, event): intake, completeness, review, public consultation where required, decision and issue.
Lanes: Applicant (message partner), Intake clerk, Case officer, Specialist reviewers (planning, fire, environment), Decision authority, Finance (fees).
Trigger: `start:message Application submitted`.
Happy path:
1. Check completeness and fee payment (Intake clerk).
2. Assign case officer.
3. Review application against regulations (Case officer); specialist reviews run in parallel when needed.
4. Run public consultation when required (a timer for the statutory period, for example P21D).
5. Decide application (Decision authority, or delegated to the case officer).
6. Issue permit (`send`), ending in "Permit issued".
Decisions: Complete? Fee paid? Which specialist reviews apply (an inclusive gateway)? Consultation required? Approve, approve with conditions, or refuse?
Exceptions:
- Incomplete: request the missing information; the statutory clock pauses, and the application lapses after a deadline.
- Objections during consultation: assess them, possibly a hearing.
- Refused: send the decision with reasons and appeal rights ("Application refused").
- Statutory decision deadline: a non-interrupting timer on the review alerts the manager before it is missed.
Controls: statutory deadlines, conflict-of-interest checks for decision makers, a public register of decisions.
KPIs: share of decisions within the statutory deadline, average processing time, appeal rate, appeals upheld.Procure to pay reference
From a business need to a paid supplier: requisition, approval, purchase order, receipt, invoice matching and payment.
Lanes: Requester, Approver (budget owner), Procurement, Supplier (message partner), Warehouse or receiving, Accounts payable.
Trigger: `start Need identified`.
Happy path:
1. Create purchase requisition (Requester, `user`).
2. Approve requisition (Approver, `user`), see the approval topic.
3. Select supplier (Procurement): a preferred supplier, or request quotes.
4. Create purchase order and send it to the supplier (Procurement, `send`).
5. Receive goods (Warehouse, `manual` goods receipt).
6. Receive invoice (Accounts payable, `receive`).
7. Match PO, goods receipt and invoice (Accounts payable, `service` three-way match).
8. Approve payment, then pay supplier (`service` payment run), ending in "Supplier paid".
Decisions: Within budget? Preferred supplier available (or run a quote)? Three-way match OK?
Exceptions:
- Requisition rejected: notify the requester ("Requisition rejected").
- Match discrepancy: resolve with the supplier or the requester, then match again (rework loop).
- Partial or late delivery: a timer on the delivery wait to chase the supplier.
- Supplier can't deliver: re-source through Procurement.
Controls: approval limits, segregation of duties (whoever raises the PO doesn't approve payment), the three-way match, a vendor master check for new suppliers.
KPIs: requisition-to-PO cycle time, spend under management, invoice exception rate, on-time payment, early-payment discounts captured.Recruitment reference
From an approved vacancy to a signed offer: requisition, sourcing, screening, interviews and offer.
Lanes: Hiring manager, HR or talent acquisition, Interview panel, Candidate (message partner), Finance (for unbudgeted roles).
Trigger: `start Vacancy identified`.
Happy path:
1. Create job requisition (Hiring manager).
2. Approve headcount (Finance or HR, see the approval topic).
3. Publish job posting (HR, `service` to job boards).
4. Screen applications (HR).
5. Interview candidates (Interview panel); usually a `sub` or `call` when there are several rounds.
6. Select candidate (Hiring manager).
7. Run background checks (HR, `service` or an external provider).
8. Send offer (HR, `send`), then wait for the answer, ending in "Offer accepted".
Decisions: Role budgeted? Enough qualified candidates? Candidate selected? Background check clear? Offer accepted?
Exceptions:
- No suitable candidates: re-advertise or use an agency (loop back to sourcing).
- Offer declined or no answer within the deadline: an event-based gateway between the acceptance message and a timer; go back to the shortlist or reopen the search.
- Background check fails: withdraw the offer ("Offer withdrawn").
Controls: headcount approval, structured interviews and scorecards, equal-opportunity record keeping.
KPIs: time to hire, time to fill, offer acceptance rate, quality of hire.
Hand-off: "Offer accepted" is the trigger of employee onboarding; suggest it as a separate diagram.Returns and refunds reference
Retail and e-commerce returns: authorization, shipping back, inspection, and refund, exchange or rejection.
Lanes: Customer, Customer service, Warehouse or returns center, Finance.
Trigger: `start:message Return requested`.
Happy path:
1. Check return eligibility (Customer service; a `rule` task for the policy window and condition).
2. Issue return authorization and label (Customer service, `send`).
3. Wait for the parcel (`catch:message Parcel received`, with a timer for returns never sent).
4. Inspect returned item (Warehouse, `manual`).
5. Restock or dispose item (Warehouse).
6. Issue refund (Finance, `service` to the original payment method), ending in "Refund issued".
Decisions: Within the return window? Refund or exchange? Item condition acceptable (full refund, partial refund, reject)?
Exceptions:
- Not eligible: notify the customer ("Return declined").
- Parcel not received within, say, 30 days: close the authorization ("Return expired").
- Damaged or used item: partial refund or send back to the customer.
- Exchange: create a replacement order, a `call` into order to cash.
Controls: fraud checks for serial returners, refund approval above a threshold, refunds only to the original payment method.
KPIs: return rate, refund cycle time, recovery value of returned stock, customer satisfaction.Sequence diagrams
For sequence diagrams: the sequence code syntax and the drawing style the app follows, and reference interactions for common flows. The AI adapts a reference to the systems you name.
Sequence code syntax (what write_diagram takes and get_diagram returns)
title <text> the diagram's name
autonumber number the messages 1, 2, 3
participant <name> [as <alias>] declare a column; actor and database draw a figure or a cylinder
actor <name> / database <name>
<from>-><to>: <text> a call: solid line, filled head; the caller waits for an answer
<from>--><to>: <text> a reply to an earlier call: dashed line
<from>->><to>: <text> an async message: solid line, open head; nobody waits
<from>-><to> ++: <text> the message activates the receiver (starts its bar)
<from>--><to> --: <text> the message ends the sender's bar
activate <name> / deactivate <name> start or end a bar on a line of its own
note over <a>[, <b>]: <text> a note over one or more participants; also note left of / note right of <a>
note over <a> a note of several lines, closed by "end note"
alt <condition> / else <condition> / end branches, one taken; par <label> / and <label> / end runs them together
opt <condition> ... end happens only when the condition holds
loop <condition> ... end repeats; also break, critical and group, each with one branch
== <text> == a divider between phases
// <text> a comment on a line of its own
Participants are created by the first line that names them, left to right in that order. Declare them at the top to fix the order, set a kind, or give a long name a short alias.
Names with spaces or symbols go in quotes: "Users DB"->API: Query. In message text, \n is a line break.
Indent the lines inside alt, opt, loop, par, break, critical and group by two spaces.
get_diagram prints every element's id. Keep those ids when you rewrite a diagram, so the user's comments stay on their elements.
Example
title Sign in with Google
actor User
participant App
participant Google
database Users DB as DB
User->App: Continue with Google
activate App
App->Google: Authorization request
Google-->App: Authorization code
App->Google: Exchange code for tokens
Google-->App: ID token
alt invited email
App->DB: Find or create user
DB-->App: User
App-->User: Signed in
else not invited
App-->User: Not invited yet
end
deactivate AppSequence diagram style
- One interaction per diagram, named for what it achieves ("Sign in with Google", "Checkout payment").
- Participants left to right in the order the interaction reaches them; the one who starts it first. People are actors, data stores are databases.
- Messages say what travels, in a few words: an action for a call ("Create payment"), a result for a reply ("Payment confirmed", "404"). Replies go back to the caller with -->.
- Async messages (->>) for events and queues: the sender doesn't wait.
- Frames: alt for one branch of several, opt for maybe, loop for repetition (say the limit: "up to 5 times"), par for work at the same time, break to leave early, critical for work that can't be interrupted, group to label a part.
- Activation bars for who is busy while waiting, usually the service handling the request: "A->B ++" on the call and "B-->A --" on its answer.
- Notes for timeouts, security rules and other facts the arrows can't carry; dividers to split phases.
- Keep it to about 3-8 participants and 30 messages; split a detailed part into its own diagram.API request and response reference
A client calling a service that reads or writes data, the shape most interactions build on.
Participants: the caller (actor User or participant Web app), the API (or a gateway in front of it), the service that does the work if it is separate, and the data store (database).
Happy path:
actor User
participant Web app
participant API
database Orders DB as DB
User->Web app: Open order history
Web app->API ++: GET /orders
API->DB: Query orders for user
DB-->API: Orders
API-->Web app --: 200 OK, orders
Web app-->User: Show orders
Failure paths worth drawing, as alt branches after the call:
- Not signed in or token expired: "401 Unauthorized", and the app sends the user to sign in.
- Not found or not allowed: "404" or "403", and what the app shows.
- Service or database down: "503", with a retry or an error message.
- Validation failed on a write: "422" with the field errors.
Add a cache in front of the store as its own participant (see "cache-aside"), and a gateway only when it does work the reader cares about (auth, rate limits).Cache-aside reference
A service that checks a cache before the database and fills it on a miss.
Participants: Client, API, Cache (participant), Database (database).
participant Client
participant API
participant Cache
database Products DB as DB
Client->API ++: GET /products/42
API->Cache: Get product:42
alt cache hit
Cache-->API: Product
else cache miss
Cache-->API: Nothing
API->DB: Read product 42
DB-->API: Product
API->>Cache: Set product:42, TTL 10 min
end
API-->Client --: 200 OK, product
On a write, the API updates the database and then deletes or overwrites the cache key; draw that as its own diagram or a second phase after a divider. A note can carry the TTL or the invalidation rule.OAuth and OpenID Connect sign-in reference
Signing a user in with an identity provider (Google, Microsoft, Okta) using the authorization code flow with PKCE.
Participants: actor User, participant App (the browser app or its backend), participant the identity provider, and the app's user store (database) when accounts are created or looked up.
actor User
participant App
participant Identity provider as IdP
database Users DB as DB
User->App ++: Sign in with Google
App-->User: Redirect to the provider
User->IdP: Sign in and allow access
IdP-->App: Authorization code
App->IdP: Exchange code for tokens
IdP-->App: ID token and access token
App->DB: Find or create user by email
DB-->App: User
App-->User --: Signed in
note over App, IdP: PKCE and state checked on every request
Failure paths worth drawing:
- The user cancels or denies access: the provider returns an error instead of a code, and the app shows the sign-in page again.
- State or PKCE check fails: the app rejects the callback.
- The account isn't allowed (not invited, wrong domain): an alt after the user lookup.
- Token refresh later on is its own interaction; don't add it to sign-in.Webhook delivery with retries reference
A provider notifying a subscriber's endpoint about an event, retrying until it is acknowledged.
Participants: the provider's event source (participant), its delivery worker or queue (participant), the subscriber's endpoint (participant), and the subscriber's store (database) when the endpoint records the event.
participant Billing
participant Webhook worker as Worker
participant Merchant endpoint as Endpoint
database Merchant DB as DB
Billing->>Worker: invoice.paid event
loop up to 5 attempts, backing off
Worker->Endpoint ++: POST event, signed
alt delivered
Endpoint->DB: Store event if new
DB-->Endpoint: Stored
Endpoint-->Worker --: 200 OK
else endpoint error or timeout
Endpoint-->Worker: 5xx or no answer
end
end
note over Worker, Endpoint: The endpoint checks the signature and ignores events it has seen
Draw the attempts with loop and say the limit in its condition. After the last failed attempt, a break can show the event going to a dead-letter queue or the subscriber being alerted. The provider-to-worker hop is async (->>): the event source doesn't wait.Queue-based async work reference
A service that accepts a request, hands the work to a queue, and lets a worker finish it later.
Participants: Client, API, Queue (participant), Worker, and what the worker writes to or notifies.
actor User
participant API
participant Jobs queue as Queue
participant Worker
database Reports DB as DB
User->API ++: Export report
API->>Queue: Enqueue export job
API-->User --: 202 Accepted, job id
Queue->>Worker: Export job
Worker->DB: Read report rows
DB-->Worker: Rows
Worker->>User: Email download link
Use ->> for every hop where the sender doesn't wait: enqueueing, delivery to the worker, and notifications. The API answers right away (202) instead of waiting for the work. Failure paths: a loop for retries on the worker, and a break to a dead-letter queue after the last one. If the client polls for the result, draw the poll as a loop of calls with a condition such as "until the job is done".Card payment with 3-D Secure reference
A checkout taking a card payment through a payment provider, with a bank challenge when the card needs one.
Participants: actor Shopper, participant Shop (the store's backend), participant the payment provider, participant Bank (the card issuer's 3-D Secure service).
autonumber
actor Shopper
participant Shop
participant Payments
participant Bank
Shopper->Shop: Pay for order
Shop->Payments ++: Create payment
Payments->Bank: Authorize card
alt challenge required
Bank-->Payments: 3-D Secure challenge
Payments-->Shop: Redirect to challenge
Shop-->Shopper: Show bank page
Shopper->Bank: Approve payment
Bank-->Payments: Authorized
else no challenge
Bank-->Payments: Authorized
end
Payments-->Shop --: Payment confirmed
Shop-->Shopper: Order placed
Payments->>Shop: payment.succeeded webhook
Failure paths worth drawing: card declined or challenge failed (an alt branch with "Payment declined" back to the shopper), and the shopper abandoning the challenge (a break). The webhook is async and is what the shop should trust to fulfil the order; a note can say so.