Incidents
For: tenant admins and governance reviewers.
Create an incident to record an agent's unwanted action and your organisation's response. The record links the jobs and audit entries that show what happened, the kill switch used, the owner, deadlines and actions taken. The audit trail records every change with its actor and reason, so the record can support a response to an authority under a deadline.
Open one
oz0 incident open --title "Upload to a paste site" --severity high \
--regime gdpr --regime nis2 --aware-at 2026-10-12T08:30:00Z \
--owner team:security --job job-9eae… --reason "egress denial on a support agent's job"
| Field | What it is |
|---|---|
| Title | One line, at most 200 characters. Keep personal data out of it; notes are for details |
| Severity | One of your tenant's severities (low, medium, high, critical unless you set others) |
| Regimes | The regimes you say apply; add or remove them later with oz0 incident clock |
| Aware | When you became aware of it (default now). --aware-at takes RFC 3339 or how long ago, such as 2h |
| Classified | When it was classified, for regimes that count from classification (--classified-at) |
| Owner | person:<account> or team:<name> of the tenant: who is reminded besides the tenant's admins |
In the console, Govern, Incidents lists those opened in the period you pick (the last 30 days unless you pick another, so an older incident that is still open shows with a longer period), filtered by state, with their next deadline, and opens each record, which you can print from the browser.
Clocks
Each regime that applies has stages, and each stage a deadline: its span after what it counts from. The record shows each one with the time left:
oz0 incident show inc-01a1300e-53f3-7dbc-bf41-c7f700105376
REGIME STAGE COUNTS FROM DEADLINE STATE
gdpr (to be confirmed) notification (72h) awareness 2026-10-15 10:30 70h 12m left
nis2 (to be confirmed) early_warning (24h) awareness 2026-10-13 10:30 22h 12m left
dora (to be confirmed) initial (4h) classification - waiting for classification
The built-in regimes, as data your tenant can change:
| Regime | Stages | Counts from |
|---|---|---|
gdpr (GDPR Art. 33) | notification 72 hours | awareness |
nis2 (NIS2 Art. 23) | early_warning 24 hours, notification 72 hours, final_report 1 month | awareness |
dora (DORA Art. 19) | initial 4 hours, intermediate 72 hours, final_report 1 month | classification |
ai_act_73 (AI Act Art. 73) | report 15 days | awareness |
Every one is marked to be confirmed. A month is a calendar month in UTC. A stage may also count from when an earlier stage of its regime was marked notified ("from": "stage:notification"), if that is how your lawyers read it.
A clock is waiting while what it counts from is unknown, running, due soon in the last quarter of its window, missed after its deadline, and marked (or marked late) once someone marks the stage:
oz0 incident notify inc-01a1… gdpr notification --reference "IMY-2026-17" --reason "sent through the authority's form"
oz0 incident notify inc-01a1… gdpr notification --undo --reason "entered by mistake"
Your own regimes
oz0 incident regimes # what applies now
oz0 incident regimes --json > regimes.json
oz0 incident regimes --file regimes.json --reason "per our DPO, case 2026/41"
oz0 incident regimes --defaults --reason "back to the built-in ones"
{
"regimes": [
{"name": "gdpr", "label": "GDPR Art. 33", "basis": "awareness", "stages": [{"name": "notification", "after": "72h"}]},
{"name": "sector", "label": "Our sector's rule", "basis": "classification",
"stages": [{"name": "first", "after": "24h"}, {"name": "final", "after": "1mo", "from": "stage:first"}]}
],
"severities": ["low", "medium", "high", "critical"],
"remind_before": ["24h", "4h", "1h"],
"classify_within": "24h"
}
Spans are a whole number and m, h, d or mo, from one minute to twelve months; at most 16 regimes of 8 stages each. Your regimes are a governance setting (incident_regimes): removing a regime or a stage, giving a stage longer, counting from a later moment, dropping a reminder, or dropping or lengthening classify_within loosens it, so it takes a reason and, with four eyes on, a second admin. An open incident keeps the regimes it was given; editing the defaults never moves its deadlines.
A regime that counts from classification, such as dora, waits until someone records when the incident was classified (oz0 incident clock inc-01a1… --classified-at now --reason "..."). So that a forgotten classification does not stay silent, classify_within (24 hours by default; leave it out to turn the warning off) is how long an open incident may wait unclassified after awareness before oz0 doctor warns in its incident classification row. It is a prompt your tenant sets, not a legal deadline: whether such a regime also has a limit counted from awareness is a question for your lawyers (to be confirmed).
Reminders
Before each deadline of a stage not yet marked, the incident's owner (the person, or the team's members) and the tenant's admins are reminded by email, at each of the tenant's remind_before points that falls inside the stage's window (24 hours, 4 hours and 1 hour before, by default) and once more when the deadline passes. Only the latest point that is due is sent, so an incident recorded late gets one reminder, not a burst. Notification rules that name the event incident.deadline reach their webhooks and chat channels too.
Reminders go out through the email relay and webhooks your operators and admins already configured; nothing new leaves the cluster. A reminder carries the incident's ID, title, severity, the regime and stage, the deadline and the time left; no figure about people. Each one is in the audit trail as incident.reminder with how many deliveries it made.
oz0 doctor fails its incident_deadline_missed row while a deadline has passed unmarked, warns in incident deadlines while one is near, and warns in incident classification about an incident left unclassified (above). These rows are computed from the open incidents each time; nothing needs to be resolved by hand.
Links
oz0 incident link inc-01a1… job job-9eae… # the job is tagged incident:<id>
oz0 incident link inc-01a1… egress --job job-9eae… # every egress denial of the job
oz0 incident link inc-01a1… egress seq:166 # one, by its audit entry
oz0 incident link inc-01a1… kill kill-01a1000c-299b-… # a kill switch
oz0 incident link inc-01a1… receipt rcpt-01a1… # a kill or revocation receipt
oz0 incident link inc-01a1… audit --since 2026-10-12T08:00:00Z --until 2026-10-12T10:00:00Z
oz0 incident link inc-01a1… audit --from-seq 120 --to-seq 180
oz0 incident link inc-01a1… finding f-7c1d… # an eval finding
oz0 incident link inc-01a1… incident inc-01a0… # a related incident
oz0 incident unlink inc-01a1… job job-9eae… --reason "wrong job"
Each item is checked in the incident's tenant when you link it and keeps its own time and a one-line summary for the timeline. An audit range holds at most 50,000 entries; egress denials by job or time at most 100 at once; an incident at most 500 links. Every link and unlink takes a reason. oz0 job search tag:incident:<id> finds the linked jobs.
Notes
oz0 incident note inc-01a1… "Customer informed by phone at 10:05."
oz0 incident note inc-01a1… --file notes.txt
Notes are free text, at most 8 KiB each and 200 per incident. They are content: only people with the content permission read them, in the record and in the export. A note's audit entry names its ID and length, never its text.
The timeline export
oz0 incident export inc-01a1… --out timeline.json --html timeline.html
oz0 incident verify timeline.json --key 1d06721c68a4f066… # the fingerprint oz0 audit key prints
A timeline exported without the content permission holds blinded entries, which only its signature covers, so incident verify fails on it without --key unless --unpinned says that showing the file is whole is enough.
timeline.json (format oz0-incident-timeline/1) holds the record, its clocks at the export, every link with its time and summary, the notes (with the content permission), a timeline of everything in time order (the incident's own audit entries, which carry their seq, keep their chain's order: one whose writer's clock had stepped back shows its own time and still follows the entry before it), and the audit entries of its linked ranges, its own entries and each linked item's entries, as whole pieces of the tenant's hash chain.
A checkpoint signed with the audit key names each piece's first link and last entry, the chain's head, and the SHA-256 of the rest of the document.
oz0 incident verify checks all of it without the cluster: the signature (pinned with --key), that nothing in the document changed, and every entry's hashes and links.
Without the content permission an entry's private part is left out and its hash kept, so the export still verifies.
timeline.html is one printable page made from the same document; print it from your browser. It is a rendering, not the evidence: hand over the JSON with it. There is no regulator template in it; the export is the input to whatever form your authority asks for. Each export is in the audit trail as incident.export.
The incident's records travel with the tenant's other tables in the tenant export (oz0 tenant export); their notes only with --content.
Who may
The tenant's admins open, change, link, mark, close and export incidents, and so do operator certificates, which act as cluster admins on every admin API. Once roles are data, reading takes incidents.read (the auditor and the privacy officer have it) and changing incidents.manage (the privacy officer has it); changing the regimes takes governance.write. Nodes, apps' API keys, scoped keys and other tenants' people are refused.
Audit actions
| Action | What it records |
|---|---|
incident.open | the title's length, severity, regimes, moments, owner and reason; the title itself in the entry's private part |
incident.update | what changed (severity, owner, awareness, classification, regimes; a new title as for incident.open) and why |
incident.link, incident.unlink | the kind and references, and why |
incident.notified | a stage marked (when, reference) or taken back, and why |
incident.note | a note's ID and length |
incident.close, incident.reopen | why |
incident.reminder | a reminder sent by the edge: the stage, its deadline, the phase and how many deliveries |
incident.export | a timeline exported, and whether with content |
tenant.incident_regimes | the tenant's regimes changed |
Works-council mode
Usage and cost figures about people only for teams of five or more, a person's own figures to that person, and tenant totals otherwise. On by default.
Inventory
Every agent and tool with its owner team and person, purpose, risk class, models and their regions, the data it handles, where its data goes, its DPIA and FRIA fields, a report export, and retired items.