Skip to content
decosa
LabsHostedSelf-hostSelf-host first for real data

Draft breach notices and deadlines

A timeline, a deadline per regime (8-K, NIS2, DORA and more), and each notice checked sentence by sentence against the incident log.

Held-out test20 / 20Planted errors in notices caught (held-out test)
On production23 smedian on production (2026-09-26); slower when the service is busy
List price~$0.60 per 100 incidentsmeasured, at list price

Built on: Signed record, Grounding, Numeric grounding

Loading the tool…

Use it your way

Use it from your codeThe hosted API with your key, and prompts to paste into a coding agent
Self-host · your GPUs · recommended

Run it yourself, on request

  • The same open models and app, on 1× RTX PRO 6000 (96 GB) or 1× RTX 5090 (32 GB) for Qwen3.8-27B; the clocks, the time and number checks and the record run on CPU.
  • Data never leaves your machines, and there are no Decosa charges.
  • One prompt for Claude Code or Codex assembles the whole stack.
  • Early access: the container images are not public yet and the source needs access; the prompt says how to ask.
Hosted · by Decosa

Get an API key

  • Call the incident notification pack API from your own code in minutes.
  • Every model answer carries a signed receipt.
  • Synthetic, public or test data only: real confidential data belongs on your own hardware.

Build with it

Paste one of these into Claude Code, Codex or another coding agent. The first wires your project to the hosted API with your DECOSA_API_KEY. The second pulls our containers and runs the same stack on your own GPU, with no Decosa charges.

Base URL
https://api.decosa.ai
Auth
Authorization: Bearer $DECOSA_API_KEY (or a demo session token)
Tool id
incident-notification-pack

Use the hosted API

# Decosa incident notification pack: use the hosted API (synthetic incidents only)

You are wiring Decosa's incident notification pack into this project. From an incident log (time with a zone, source,
text, tags), the entity fields, the regimes counsel is considering (SEC 8-K Item 1.05, EU NIS2 Art. 23, EU DORA, EU
Cyber Resilience Act Art. 14, California Civ. Code 1798.82) and the notices to draft or check, it seals the log as a
hash-chained timeline, computes each report's deadline clock in code from the tagged entries, drafts or checks each
notice sentence by sentence against the entries it cites (times and numbers in code, other facts by a grounding judge),
lists the required elements a notice lacks and the facts two notices state differently, and returns a Markdown pack
and a report signed by the server, with a signed receipt for every model call. Use only what is listed below. If you
need something else, stop and ask me.

- Base URL: `https://api.decosa.ai`
- Health check: `GET https://api.decosa.ai/healthz`.
- **The hosted API takes synthetic incidents only.** Incident facts are privileged and may be material non-public
  information. Every request must carry `"synthetic": true`; anything else gets HTTP 400. Real incidents belong on a
  self-hosted box (see the self-host prompt). Never send real names, hosts, addresses or customer data here.
- This is a drafting and checking aid, not legal advice, not a filing and never a compliance determination. Say so
  wherever you show results; counsel decides whether a regime applies, what to file and when, and files it.

## Auth: API key (or a demo session)
1. Preferred: an API key (`dk_…`) from "Get an API key" on the tool page. Keep it in an environment variable,
   `DECOSA_API_KEY`, never in code. Send `Authorization: Bearer $DECOSA_API_KEY`.
2. Without a key: `POST https://api.decosa.ai/demo/session` with `{"vertical": "incident-notification-pack"}` returns `{"token", "expires_at", "budget"}`.
   Sessions per IP are limited; over a limit you get HTTP 429 with `Retry-After`.
3. Model calls spend the token's budget (402 when it is spent). One run at a time per demo token (409 while one is going).

## Endpoints
- `POST /incident/pack` (token). Body:
  ```json
  {"incident": {"id": "INC-1", "title": "...", "zone": "Europe/Dublin"},
   "entity": {"name": "...", "contact": "..."},
   "log": [{"time": "2026-09-14 04:05 UTC", "source": "Slack #inc", "text": "The CISO declared an incident.", "tags": ["aware"]}],
   "regimes": ["sec_8k", "nis2"],
   "notices": [{"regime": "nis2", "report": "notification", "text": "optional: your sentences ending with [E2, P.name]"}],
   "synthetic": true, "stream": false}
  ```
  The log can also be one string of lines `time | source | text | #tag`. Every time needs a zone (Z, an offset, UTC,
  CEST, ET ...); a time without one is refused. Tags `aware`, `materiality_determined`, `classified_major`, `vuln_aware`,
  `fix_available`, `breach_discovered` start the clocks; `submitted:<regime>.<report>` marks a submission. Limits: 300
  entries, 150,000 characters, 30 entity fields, 6 notices, 12,000 characters per notice. A notice without `text` is
  drafted; with `text` it is checked. Entries are cited `E1..En` in time order, entity fields `P.<name>`.
- JSON answer: `{status: needs_attention | needs_review | all_traced, counts, coverage: {notice: [{key, label, need,
  status: given | held | missing | unknown | at_filing}]}, contradictions, missing_must, late, clocks: [{title, rule,
  cite, start_entry, due, due_local, submitted_entry, status: met | late | met_if_extended | open | overdue |
  not_started | waiting, late_by, left}], pack_md, notices_plain, record, report, ...}`. Show `held` sentences with
  their reasons and the detail (for example the nearest cited time); never put a held sentence in a notice you file.
- SSE: send `Accept: text/event-stream` (or `"stream": true`): `ready`, `notice`, `receipt`, `sentence`, `review`,
  `report`, `budget`, `done`.
- `POST /incident/clock` (token): the same body; the clocks alone, no model call.
- `POST /incident/signoff` (token): `{report, reviewer: {name, role?}, decision: approved | approved_with_changes |
  changes_requested | not_approved, note?}` → `{signoff}`, a second signed record pointing at the pack.
- `POST /incident/verify` (no token): `{report, pack_md?, signoff?, log?}` → `{valid_signature, signed_by_this_server,
  pack_md_matches?, log_matches?, signoff?}`. `POST /record/verify` (no token) checks the sealed timeline `record`.
- `GET /incident/info`, `GET /incident/samples` (no token): the regimes with their rules, sources and required
  elements, the checks, the limits, and four synthetic samples.

## Errors
400 bad input (the message names the entry, field or limit, or says the incident is not marked synthetic), 401/403
token, 402 budget, 409 a run already going on this demo token, 413 body too large, 429 busy (`Retry-After`).

Run it yourself (containers)

On request. The container images and the compose file aren’t public yet. Ask for self-host access and Decosa sends the registry (DECOSA_REGISTRY) and the compose file’s URL (DECOSA_COMPOSE_URL) these steps use. They are the steps we tested end to end on a fresh machine.

# Decosa incident notification pack: run it yourself (containers)

You are setting up the Decosa incident notification pack on this machine, so incident logs never leave it. Incident
facts are privileged and may be material non-public information. From the team's incident log, the entity fields, the
regimes counsel is considering and the notices to draft or check, it seals a hash-chained timeline, computes a deadline
clock per report in code, checks every notice sentence against the entries it cites, and returns a Markdown pack and a
signed report that counsel can sign off. Nothing is sent to Decosa's hosted API. It is a drafting and checking aid:
counsel decides and files.

Status: the container images (${DECOSA_REGISTRY}/decosa-*) and the compose file are on request while self-host is in early access (not on a public registry yet): ask at https://decosa.ai/contact?topic=self-host, and Decosa sends the registry as DECOSA_REGISTRY, the compose file URL as DECOSA_COMPOSE_URL, and pull access. If a pull fails with
"not found", "denied" or "unauthorized", stop and tell me. Do not substitute other images.

Ask me before any command that needs sudo, and show me the command first.

## Step 0: set up with a coding agent, rehearse on mock data, then go private

This prompt is for a coding agent running on the machine that will host the service. We recommend Claude Code with
Claude Opus 5.5; any capable coding agent works. Work in this order:

1. Set up on mock data only. During the whole setup you (the agent) work with the synthetic sample bundle below and
   nothing else. Do not ask me for real data, and do not open, read, list or copy files that hold real data, even to
   "test with something realistic".
2. Rehearse. When the steps below are done and the service is healthy, fetch the mock-data bundle for this tool,
   https://decosa.ai/samples/incident-notification-pack.zip (5 KB, 13 checks, synthetic or openly licensed: see `licence` in expected.json),
   show me what is in it, and run the rehearsal against the local API:
   `docker compose exec api python scripts/rehearse.py incident-notification-pack` (the api image carries the same bundle under /app/rehearsal/incident-notification-pack/;
   with no key set, the script asks the local API for a short demo token). From a decosa-api checkout instead:
   `python scripts/rehearse.py incident-notification-pack --bundle incident-notification-pack.zip --base-url http://127.0.0.1:<PORT>`.
   It sends the mock inputs to the local API and prints PASS or FAIL for each expected property (for example: "the pack needs attention", "the wrong detection time is held as a time mismatch", "the held time names the logged one"). Show me
   the full output. Every check must pass. If one fails, fix the install and run it again; never edit `expected.json`
   to make a check pass.
3. Stop there. Once the rehearsal passes, tell me, and I will run my own data against the local API myself, on this
   machine.

For the person running this: a coding agent that runs in the cloud sees everything in its context, including files it
reads, command output and anything pasted into the chat. Keep real data out of the chat and out of anything the agent
can read. Switch to your own data only after the rehearsal has passed and the agent's work is done.

## Steps
1. Docker: if `docker compose version` fails, install Docker Engine and the compose plugin using Docker's official
   instructions for this distribution (docs.docker.com/engine/install). Install the NVIDIA container toolkit and check
   `docker run --rm --gpus all nvidia/cuda:12.8.0-base-ubuntu24.04 nvidia-smi`.
2. Fetch the compose file:
   `mkdir -p ~/decosa && cd ~/decosa && curl -fsSL "${DECOSA_COMPOSE_URL}" -o compose.yaml`
   Read it. Keep the `llm` service (Qwen3.8-27B on vLLM, with prefix caching on) and the `api` service. For the `api`
   service set `DECOSA_LLM_ROUTE=direct`, `DECOSA_LLM_URL=http://llm:8000/v1`, `DECOSA_LLM_MODEL=qwen3.8-27b`,
   `DECOSA_INCIDENT_SYNTHETIC_ONLY=0` (so this box accepts real incidents) and bind every port to 127.0.0.1. Never set
   the gateway route on this box: it would send incident data to the Decosa API.
3. Pull and start: `docker compose pull && docker compose up -d`. Wait for the `llm` health check (the first start
   downloads about 20 GB of weights).
4. Check: `curl -fsS http://127.0.0.1:<PORT>/incident/info` lists the regimes, the checks, the limits and
   `synthetic_only: false`; `GET /attest/signing-key` shows this box's public key. Show me the key: it is what a
   reviewer pins to verify my packs.
5. Smoke test: get a token with `POST /demo/session {"vertical":"incident-notification-pack"}`, fetch
   `GET /incident/samples`, and send the `ransomware-saas` sample (incident, entity, log, regimes, notices, synthetic)
   to `POST /incident/clock`: expect the NIS2 early warning `late` by 7 h 0 min. Then send it to `POST /incident/pack`:
   expect `status: "needs_attention"`, the 8-K sentence with 04:12 UTC held as `time_mismatch`, the NIS2 sentence
   saying no personal data was taken held as `contradicted`, the 8-K `impact` element missing, and contradictions on
   detection time, systems affected and whether data was taken. Then `POST /incident/verify` with the report and
   pack_md: `valid_signature`, `signed_by_this_server` and `pack_md_matches` must be true.
6. Report back: the public key, the status, the held sentences and how long the run took.

Off by default. Joining as a provider serves other people's requests on this GPU; never do it on a box that holds
incident data. If I ask for it later, follow the Provide page instead of improvising.
Run it on your own hardwareWhat it needs, and the prompt that sets it up

Run it on your own GPU

Same app, same pinned models, your hardware. Nothing goes to our servers and there are no Decosa charges.

  • CPU only, 64 GB RAMlite tierRuns with a smaller tier

    The standard tier does not fit: Qwen3.8-27B (NVFP4) needs a GPU. The lite tier fits.

  • GeForce RTX 4090standard tierRuns

    The standard tier fits with changes: Replace Qwen3.8-27B (NVFP4) with A community 4-bit build of Qwen3.8-27B (AWQ or GGUF). This build is NVIDIA NVFP4, which needs a Blackwell GPU. (Memory is an estimate.)

  • GeForce RTX 5090standard tierRuns

    The standard tier fits with changes: Qwen3.8-27B (NVFP4): run it at its smallest setting (about 28 GB instead of 57.6 GB), with a shorter context and fewer parallel sessions.

  • 2x GeForce RTX 5090standard tierRuns

    The standard tier fits with changes: Split the language model across the GPUs with tensor parallelism (vLLM --tensor-parallel-size).

  • L40Sstandard tierRuns

    The standard tier fits with changes: Replace Qwen3.8-27B (NVFP4) with Qwen3.8-27B official FP8. This build is NVIDIA NVFP4, which needs a Blackwell GPU.

  • H100 80 GB (SXM)standard tierRuns

    The standard tier fits with changes: Replace Qwen3.8-27B (NVFP4) with Qwen3.8-27B official FP8. This build is NVIDIA NVFP4, which needs a Blackwell GPU.

  • RTX PRO 6000 Blackwell 96 GBstandard tierRuns

    The standard tier fits (57.6 of 96 GB).

  • 2x RTX PRO 6000 Blackwell 96 GBstandard tierRuns

    The standard tier fits (57.6 of 192 GB).

  • Apple M3 Ultra (Mac Studio), 96 GBstandard tierRuns

    The standard tier fits with changes: Replace Qwen3.8-27B (NVFP4) with Qwen3.8-27B MLX 4-bit. MLX build for Apple Silicon.

  • Apple M5 Max, 64 GBstandard tierRuns

    The standard tier fits with changes: Replace Qwen3.8-27B (NVFP4) with Qwen3.8-27B MLX 4-bit. MLX build for Apple Silicon.

Memory per component comes from measured footprints, the tool's stack.json, or an estimate from its parameter count, and each is labelled that way below. Only an RTX PRO 6000 and an M3 Ultra Mac Studio have actually been run.

On request. The container images and the compose file aren’t public yet. Ask for self-host access and Decosa sends the registry (DECOSA_REGISTRY) and the compose file’s URL (DECOSA_COMPOSE_URL) these steps use. They are the steps we tested end to end on a fresh machine.

  1. 1

    Check the GPU, Docker and the NVIDIA Container Toolkit

    The driver must see the GPU, and Docker must be able to pass it into a container.

    nvidia-smi
    docker compose version
    docker run --rm --gpus all ubuntu nvidia-smi
  2. 2

    Fetch the compose file

    One file describes the API and the language model as services.

    mkdir -p ~/decosa && cd ~/decosa
    curl -fsSL "${DECOSA_COMPOSE_URL}" -o compose.yaml
  3. 3

    Pull and start

    The first start downloads pinned model weights, tens of gigabytes.

    docker compose pull
    docker compose up -d
  4. 4

    Check health

    Wait until the API reports ok with the language model loaded. Then point your app at the local base URL.

    curl -fsS http://localhost:<PORT>/healthz
    # {"ok": true, "llm": true, ...}
    curl -fsS -X POST http://localhost:<PORT>/demo/session \
      -H 'Content-Type: application/json' -d '{"vertical":"incident-notification-pack"}'

Set up with a coding agent, rehearse on mock data, then go private

  1. Set up with a coding agent. Paste the self-host prompt into a coding agent on the machine that will run the service. We recommend Claude Code with Claude Opus 5.5; any capable coding agent works.
  2. Rehearse on mock data. The agent runs the tool on a bundle of synthetic inputs and checks each answer against the bundle's expected.json. Every check must print PASS.
  3. Go private. Only then do you run your own data against the local API, yourself, on that machine. Never give the agent real data during setup: a coding agent that runs in the cloud sees everything in its context, so keep real data out of the chat and out of the files it reads.
Rehearsal command
docker compose exec api python scripts/rehearse.py incident-notification-pack

Download the mock-data bundle (5 KB, 13 checks)expected.json

A synthetic incident log (VPN, EDR, chat, forensics, disclosure committee), the entity fields, and two supplied notices: a Form 8-K Item 1.05 draft and a NIS2 incident notification. Planted: the 8-K gives the detection time an hour late and a stale host count, and has no sentence on the financial impact; the NIS2 notification says no personal data was exfiltrated while the log records a 38 GB upload of HR exports; the NIS2 early warning went out 31 hours after awareness. The pack must hold both sentences, name the right time, list the missing element and the contradictions between the notices, show the early-warning clock as late, and the signed report and the hash-chained timeline must verify.

What the rehearsal checks
  • the pack needs attention
  • the wrong detection time is held as a time mismatch
  • the held time names the logged one
  • the no-exfiltration claim is held
  • the 8-K lacks a sentence on the financial impact
  • the two notices give different host counts
  • the NIS2 early warning was late by 7 hours
  • the 8-K is due at 17:30 Eastern on the fourth business day
  • the signed report verifies
  • the report matches the log it was run on
  • the hash-chained timeline verifies
  • a report with its status changed no longer verifies
  • every model call has a signed receipt

Licence: Synthetic: Brightwater Payroll Cloud, its people, customers, IP addresses (RFC 5737 documentation ranges) and forensic firm are fictional (decosa_api/verticals/incident/synth.py). Part of decosa-api, AGPL-3.0-or-later.

Prompt for your coding agent

# Decosa incident notification pack: run it yourself (containers)

You are setting up the Decosa incident notification pack on this machine, so incident logs never leave it. Incident
facts are privileged and may be material non-public information. From the team's incident log, the entity fields, the
regimes counsel is considering and the notices to draft or check, it seals a hash-chained timeline, computes a deadline
clock per report in code, checks every notice sentence against the entries it cites, and returns a Markdown pack and a
signed report that counsel can sign off. Nothing is sent to Decosa's hosted API. It is a drafting and checking aid:
counsel decides and files.

Status: the container images (${DECOSA_REGISTRY}/decosa-*) and the compose file are on request while self-host is in early access (not on a public registry yet): ask at https://decosa.ai/contact?topic=self-host, and Decosa sends the registry as DECOSA_REGISTRY, the compose file URL as DECOSA_COMPOSE_URL, and pull access. If a pull fails with
"not found", "denied" or "unauthorized", stop and tell me. Do not substitute other images.

Ask me before any command that needs sudo, and show me the command first.

## Step 0: set up with a coding agent, rehearse on mock data, then go private

This prompt is for a coding agent running on the machine that will host the service. We recommend Claude Code with
Claude Opus 5.5; any capable coding agent works. Work in this order:

1. Set up on mock data only. During the whole setup you (the agent) work with the synthetic sample bundle below and
   nothing else. Do not ask me for real data, and do not open, read, list or copy files that hold real data, even to
   "test with something realistic".
2. Rehearse. When the steps below are done and the service is healthy, fetch the mock-data bundle for this tool,
   https://decosa.ai/samples/incident-notification-pack.zip (5 KB, 13 checks, synthetic or openly licensed: see `licence` in expected.json),
   show me what is in it, and run the rehearsal against the local API:
   `docker compose exec api python scripts/rehearse.py incident-notification-pack` (the api image carries the same bundle under /app/rehearsal/incident-notification-pack/;
   with no key set, the script asks the local API for a short demo token). From a decosa-api checkout instead:
   `python scripts/rehearse.py incident-notification-pack --bundle incident-notification-pack.zip --base-url http://127.0.0.1:<PORT>`.
   It sends the mock inputs to the local API and prints PASS or FAIL for each expected property (for example: "the pack needs attention", "the wrong detection time is held as a time mismatch", "the held time names the logged one"). Show me
   the full output. Every check must pass. If one fails, fix the install and run it again; never edit `expected.json`
   to make a check pass.
3. Stop there. Once the rehearsal passes, tell me, and I will run my own data against the local API myself, on this
   machine.

For the person running this: a coding agent that runs in the cloud sees everything in its context, including files it
reads, command output and anything pasted into the chat. Keep real data out of the chat and out of anything the agent
can read. Switch to your own data only after the rehearsal has passed and the agent's work is done.

## Steps
1. Docker: if `docker compose version` fails, install Docker Engine and the compose plugin using Docker's official
   instructions for this distribution (docs.docker.com/engine/install). Install the NVIDIA container toolkit and check
   `docker run --rm --gpus all nvidia/cuda:12.8.0-base-ubuntu24.04 nvidia-smi`.
2. Fetch the compose file:
   `mkdir -p ~/decosa && cd ~/decosa && curl -fsSL "${DECOSA_COMPOSE_URL}" -o compose.yaml`
   Read it. Keep the `llm` service (Qwen3.8-27B on vLLM, with prefix caching on) and the `api` service. For the `api`
   service set `DECOSA_LLM_ROUTE=direct`, `DECOSA_LLM_URL=http://llm:8000/v1`, `DECOSA_LLM_MODEL=qwen3.8-27b`,
   `DECOSA_INCIDENT_SYNTHETIC_ONLY=0` (so this box accepts real incidents) and bind every port to 127.0.0.1. Never set
   the gateway route on this box: it would send incident data to the Decosa API.
3. Pull and start: `docker compose pull && docker compose up -d`. Wait for the `llm` health check (the first start
   downloads about 20 GB of weights).
4. Check: `curl -fsS http://127.0.0.1:<PORT>/incident/info` lists the regimes, the checks, the limits and
   `synthetic_only: false`; `GET /attest/signing-key` shows this box's public key. Show me the key: it is what a
   reviewer pins to verify my packs.
5. Smoke test: get a token with `POST /demo/session {"vertical":"incident-notification-pack"}`, fetch
   `GET /incident/samples`, and send the `ransomware-saas` sample (incident, entity, log, regimes, notices, synthetic)
   to `POST /incident/clock`: expect the NIS2 early warning `late` by 7 h 0 min. Then send it to `POST /incident/pack`:
   expect `status: "needs_attention"`, the 8-K sentence with 04:12 UTC held as `time_mismatch`, the NIS2 sentence
   saying no personal data was taken held as `contradicted`, the 8-K `impact` element missing, and contradictions on
   detection time, systems affected and whether data was taken. Then `POST /incident/verify` with the report and
   pack_md: `valid_signature`, `signed_by_this_server` and `pack_md_matches` must be true.
6. Report back: the public key, the status, the held sentences and how long the run took.

Off by default. Joining as a provider serves other people's requests on this GPU; never do it on a box that holds
incident data. If I ask for it later, follow the Provide page instead of improvising.

Help me customise for my hardware

Pick your GPU or Mac, or enter its memory. You get the tier that fits, the model swaps it needs, measured speed where we have it, and a setup prompt with those choices written in.

Hardware

GeForce RTX 5090: 32 GB GDDR7, 1,792 GB/s, FP8 and NVFP4. NVIDIA product page

RunsIncident notification pack on GeForce RTX 5090: use the Standard · one GPU for the model (hosted demo) tier

The standard tier fits with changes: Qwen3.8-27B (NVFP4): run it at its smallest setting (about 28 GB instead of 57.6 GB), with a shorter context and fewer parallel sessions.

What this tool's stack says about this hardware:

  • 1x RTX 5090 32 GB (fits): Estimate: Qwen3.8-27B NVFP4 needs about 20 GB of weights plus KV cache; not run for this use case.

Standard · one GPU for the model (hosted demo): what changesuses estimates

  • Qwen3.8-27B (NVFP4): run it at its smallest setting (about 28 GB instead of 57.6 GB), with a shorter context and fewer parallel sessions.
Memory per component
  • Timeline, hash chain, deadline clocks, citati...: decosa-api incident pack (decosa_api/verticals/incident) with the numeric block (decosa_api/verticals/numeric), the dates module (decosa_api/verticals/claims/dates.py) and the grounding module (decosa_api/verticals/grounding). CPU. Runs on CPU (vram_gb 0 in stack.json).
  • Notice drafting, the grounding judge, and the...: Qwen3.8-27B (NVFP4). ~57.6 GB (at least ~28 GB), weights 21.4 GB (from stack.json). Qwen3.8-27B NVFP4: Weights 19.9 GiB (21.4 GB), measured (field stack.json). The compose file gives the server 0.60 of a 96 GB card (57.6 GB) so the rest is FP8 KV cache for several sessions. The 28 GB minimum is an estimate: weights plus a short-context KV cache, which is why several stacks list a 32 GB RTX 5090 as 'estimate'. (stack.json lists 20 GB for this component.)

Expected speed

Not measured.

Not measured on this hardware. The only measured setups are an RTX PRO 6000 Blackwell and a Mac Studio M3 Ultra.

Setup prompt for this hardware

The self-host prompt for Incident notification pack, with a hardware plan for GeForce RTX 5090 added after Step 0. Loading the full prompt; until then it points your agent at the prompt's URL.

# Set up Incident notification pack on my hardware

Fetch https://decosa.ai/prompts/incident-notification-pack-selfhost.md and follow it (including Step 0: rehearse on mock data first), with the hardware plan below applied.

## Hardware plan for this machine (from https://decosa.ai/self-host/hardware?use=incident-notification-pack)

Target machine: GeForce RTX 5090 (32 GB of GPU memory; CUDA, FP8 and NVFP4).
Quality tier: Standard · one GPU for the model (hosted demo) (standard). Fit check: runs with changes, about 28 GB of 32 GB used; some memory numbers are estimates, not measurements.

First, check the machine: run `nvidia-smi` (or `rocm-smi`, or `sysctl hw.memsize` on a Mac) and confirm the GPUs and free memory match the line above. If they do not, stop and tell me before pulling anything.

Use these components (the setup below describes the standard tier; change it to match):
- Timeline, hash chain, deadline clocks, citati...: decosa-api incident pack (decosa_api/verticals/incident) with the numeric block (decosa_api/verticals/numeric), the dates module (decosa_api/verticals/claims/dates.py) and the grounding module (decosa_api/verticals/grounding), CPU
- Notice drafting, the grounding judge, and the...: Qwen3.8-27B (NVFP4) (nvidia/Qwen3.8-27B-NVFP4), 57.6 GB. Change: Qwen3.8-27B (NVFP4): run it at its smallest setting (about 28 GB instead of 57.6 GB), with a shorter context and fewer parallel sessions.

GPU placement (set each service's device and its vLLM --gpu-memory-utilization to about the share shown):
- GPU 0: Qwen3.8-27B (NVFP4) ~28 GB (88%); about 4 GB left

During the rehearsal, watch GPU memory. If a model fails to load or runs out of memory, lower its --max-model-len and --max-num-seqs first, then its memory share, and tell me what you changed.

The stack's own component list and compose layout: https://decosa.ai/prompts/incident-notification-pack-assemble.md

The proof

How we tested itEval results and end-to-end checks, hosted and self-hosted, with dates

Verified end to end

Hosted: verified 26 Sep 2026 · measured 26 Sep 2026: · p50 23 s · ~$0.006 per run · 16 receipts

Loading the nightly status…

Self-host: verified 26 Sep 2026 · fresh clone, compose up, sample against local model servers

Measured cost to run: about $0.60 per 100 incidents (hosted, 26 Sep 2026). Self-hosting is free: the code is open and the models are open-weight. You pay only for your own hardware and power.

A fresh clone of a decosa-api pre-release build (not yet merged to main) into a clean directory, the api image built from docker/api/Dockerfile, compose api service with a named data volume, DECOSA_INCIDENT_SYNTHETIC_ONLY=0, direct route to the already-running local Qwen3.8-27B vLLM (network_mode host instead of starting a second model server). The ransomware sample without the synthetic flag: both planted sentences held, impact missing, 3 contradictions, the NIS2 early warning late, report and timeline record verified, a changed status failed, receipts attested, 3.8 s; the CRA sample with a drafted final report 4.4 s. Torn down after. Model-server startup itself not re-verified.

Known limits (5)
  • Synthetic only on the hosted demo, and every number here comes from our own synthetic incidents.
  • Coverage says a traced sentence addresses an element, not that it says enough.
  • The contradiction check can read a later time as the detection time (seen in 2 of 4 clean held-out packs).
  • Member State bank holidays, national NIS2 formats and other US states are not modelled.
  • The clocks are only as right as the tags: the team marks when it became aware, classified or determined materiality.

Eval results, nightly checks and cost per runVerify a run

How it's builtThe steps, the models and what each one checks
Self-host · your GPUs · recommended

Run it yourself, on request

  • The same open models and app, on 1× RTX PRO 6000 (96 GB) or 1× RTX 5090 (32 GB) for Qwen3.8-27B; the clocks, the time and number checks and the record run on CPU.
  • Data never leaves your machines, and there are no Decosa charges.
  • One prompt for Claude Code or Codex assembles the whole stack.
  • Early access: the container images are not public yet and the source needs access; the prompt says how to ask.
Hosted · by Decosa

Get an API key

  • Call the incident notification pack API from your own code in minutes.
  • Every model answer carries a signed receipt.
  • Synthetic, public or test data only: real confidential data belongs on your own hardware.
The open stack

A signed incident timeline, a deadline clock per regime, and every sentence of each notice checked against the log.

For a CISO and general counsel during a cyber incident. Send the incident log (tickets, chat, alerts, notes), each line with its time, source and tags for the moments that start the clocks. You get a hash-chained timeline, each regime's deadlines computed in code (SEC Form 8-K Item 1.05, NIS2, DORA, the Cyber Resilience Act, California), and each notice drafted by Qwen3.8-27B or checked as you wrote it. Every sentence must cite log entries; its times, counts and dates are checked in code and its other facts by a grounding judge that sees only what it cites. The pack lists the required elements a notice lacks, the facts two notices state differently and any missed deadline, and is signed; counsel signs off on the exact version. A drafting and checking aid: counsel decides and files.

Deployment
Self-host first
Regulatory
Checked 26 Sep 2026 against primary sources (links under Tools). SEC Form 8-K Item 1.05: file within four business days after determining the incident is material (General Instruction B.1; Release 33-11216; compliance from 18 Dec 2023, smaller reporting companies 15 Jun 2024); an undetermined incident may go under Item 8.01 (SEC Corp Fin statement, 21 May 2024); we show 17:30 Eastern because later EDGAR submissions are dated the next business day (17 CFR 232.13). NIS2 Art. 23: early warning within 24 hours of becoming aware, notification within 72 hours, final report one month after the notification (national law applies; amendments proposed 20 Jan 2026, COM(2026) 13, not adopted). DORA Art. 19 and Delegated Regulation (EU) 2025/301 Art. 5: initial notification within 4 hours of classification as major and no later than 24 hours from awareness, intermediate within 72 hours, final within one month; weekend relief to noon of the next working day except for some entity types (Member State bank holidays are not modelled). Cyber Resilience Act Art. 14 (applies from 11 Sep 2026, Art. 71(2)): actively exploited vulnerabilities and severe incidents, early warning 24 hours, notification 72 hours, final report 14 days after a fix (vulnerabilities) or one month (incidents), through ENISA's single reporting platform. California Civ. Code 1798.82 as amended by SB 446 (from 1 Jan 2026): notice within 30 calendar days of discovery, required headings and contents, AG sample within 15 days if more than 500 residents. Unverified: national NIS2 rules, whether CRA format acts were adopted, whether Regulation 1182/71 extends EU day and month periods (shown as an extended date, weekends only). Whether a regime applies, and whether an incident is material, significant, major or severe, is counsel's call; the clocks only run from the entries the team tagged. Not legal advice and never a compliance determination. Model licence: Apache-2.0 (Qwen3.8-27B).
Architecture
Text description

An incident log (tickets, chat, alerts and notes, each line with a time, a source and tags) becomes a hash-chained timeline signed by this instance. Code computes each regime's deadlines from the tagged entries (SEC 8-K, NIS2, DORA, CRA, California). Each notice is drafted by Qwen3.8-27B or supplied by the team; every sentence's citations, times and numbers are checked in code, and the grounding judge reads it against only the entries it cites. A review call per notice maps required elements and quotes key facts, which code compares across notices. Outputs: a Markdown pack, clean copies without held sentences, a signed report, and counsel's signed sign-off. Hosted, every model call gets a gateway-signed receipt and only synthetic incidents are accepted; self-hosted, nothing leaves the box.

Architecture

At a glance

Data retention
Nothing stored: the log lives in memory for the request. The signed pack holds hashes, ids, verdicts, clocks, receipt ids and the facts read from each notice (counts, yes/no fields, matched times and numbers), never the log or notice text itself; the timeline record goes back to you; logs carry counts only.
What leaves the box
Hosted: every model call goes through our gateway to the GPU serving Qwen3.8-27B, and only incidents marked synthetic are accepted. Self-hosted on the direct route: nothing leaves the box.
What it will not do
Decide whether a regime applies or whether an incident is material, significant, major or severe; file anything; or call a notice compliant. A clean result reads 'every sentence traced to the log (counsel review still required)'.
Input formats
Log lines 'time | source | text | #tag' or JSON entries, up to 300 entries and 150,000 characters; every time needs a zone. Up to 6 notices per pack, each up to 60 sentences with [E3, P.name] citations, or left blank to be drafted.
Typical run
The ransomware sample: a dozen or so model calls and a fraction of a cent at the gateway list price; a drafted DORA notice adds a few calls. Each run shows its own measured cost.
Quality tiers

Pick the tier for the quality you need

Same app at every tier. What changes is the models, the hardware they need, and whether receipts are signed. Scores are measured with the source named, or marked not measured.

  • In the hosted demo

    Lite

    clocks and timeline, no GPU

    POST /incident/clock: the timeline, log issues and every regime's deadline from the tagged entries. No drafting and no sentence checks.

    Models
    • decosa-api incident pack (decosa_api/verticals/incident) with the numeric block (decosa_api/verticals/numeric), the dates module (decosa_api/verticals/claims/dates.py) and the grounding module (decosa_api/verticals/grounding)
    Hardware
    Any CPU
    Quality evidence
    • Deadlines right, 44 hand-labelled cases (SEC, NIS2, DORA, CRA, California)44 / 44 after one bug fix; 35 / 44 first rundocs/evals/incident-notification-pack.md, part 1, 26 Sep 2026
    Latency
    no model call; milliseconds on CPU (not separately timed)
    Verification
    No proof yetNo model call, so no receipts; the clocks are deterministic code. The timeline record is signed by the instance key.
  • In the hosted demo

    Standard

    one GPU for the model (hosted demo)

    Qwen3.8-27B drafts notices, judges each sentence against what it cites, and maps required elements; clocks, times, numbers and contradictions are code. This is what the hosted demo runs, on synthetic incidents only.

    Models
    • decosa-api incident pack (decosa_api/verticals/incident) with the numeric block (decosa_api/verticals/numeric), the dates module (decosa_api/verticals/claims/dates.py) and the grounding module (decosa_api/verticals/grounding)
    • Qwen3.8-27B (NVFP4)
    Hardware
    1x RTX PRO 6000 96 GB (measured) or 1x RTX 5090 32 GB (estimate)
    Quality evidence
    • Planted problems caught in supplied notices (2 repeats)28 / 28 dev; 20 / 20 held-out testdocs/evals/incident-notification-pack.md, parts 2-6
    • Unsupported or contradicted claims held10 / 10docs/evals/incident-notification-pack.md, parts 2-6
    • Clean sentences held / flagged1 / 102 held; 14 / 102 flaggeddocs/evals/incident-notification-pack.md, part 7
    • False contradictions on clean packs0 of 6 dev packs; 2 of 4 test packs (one pattern)docs/evals/incident-notification-pack.md, part 7
    • Model-drafted sentences traced / flagged / held (5 scenarios)97 / 9 / 2 (both held were real errors)docs/evals/incident-notification-pack.md, part 8
    Latency
    measured: under a minute per sample through the shared gateway; seconds self-hosted on the direct route
    Verification
    Proof: strongEvery model call has a gateway-signed receipt; the signed pack lists the receipt ids.
Components

Every model in the stack

Models in this stack. Each row has a button that shows its licence, engine, verification and evidence.
ModelDetails
Timeline, hash chain, deadline clocks, citation, time and number checks, element coverage, cross-notice consistency, signed pack and sign-off (no model; CPU)decosa-api incident pack (decosa_api/verticals/incident) with the numeric block (decosa_api/verticals/numeric), the dates module (decosa_api/verticals/claims/dates.py) and the grounding module (decosa_api/verticals/grounding)
0 GBProof: partial
Notice drafting, the grounding judge, and the review call (element coverage and quoted facts)Qwen3.8-27B (NVFP4)nvidia/Qwen3.8-27B-NVFP4 on Hugging Face (opens in a new tab)
27.8B · 20 GBProof: strongIn the hosted demo

Around the models

Tools, services and hardware

Tools

Services

  • decosa-api:8445
    ${DECOSA_REGISTRY}/decosa-api:<tag>

    GET /incident/info, /incident/samples; POST /incident/clock, /incident/pack (SSE or JSON), /incident/signoff, /incident/verify. Keeps no log text.

  • vLLM (model):8114
    vllm/vllm-openai@sha256:c2914767605584b6d8f45686b82de173ecc99e781897aa3d0a66dacd72c51ae1

    Qwen3.8-27B NVFP4 behind our gateway (hosted) or called directly (self-host).

Hardware

  • 1x RTX PRO 6000 Blackwell 96 GB Fits

    Measured on our server: the hosted demo, the eval and the self-host check ran on this card.

  • 1x RTX 5090 32 GB Fits

    Estimate: Qwen3.8-27B NVFP4 needs about 20 GB of weights plus KV cache; not run for this tool.

  • CPU only Fits

    The lite tier (clocks and the timeline, POST /incident/clock) needs no GPU.

Latency per lane

  • check two supplied notices (15 sentences), hosted gateway route23.3 s

    Measuredmeasured on our server 2026-09-26: the ransomware sample streamed, gateway shared with other workloads; eval medians 11.8 s (dev) and 24.1 s (test)

  • one drafted notice plus one supplied notice, hosted gateway route32.5 s

    Measuredmeasured on our server 2026-09-26: the DORA sample streamed

  • same, self-hosted on the direct route3.8 s

    Measuredmeasured on our server 2026-09-26: fresh self-host sandbox, ransomware sample 3.8 s, CRA sample with a drafted report 4.4 s

  • clocks only (POST /incident/clock)n/a

    Measuredno model call; milliseconds on CPU (not separately timed)

Notes

  • All 48 problems planted into supplied notices were caught over two repeats: wrong clock times, wrong counts, claims the log contradicts or does not make, removed required elements, stale figures between notices, and late submissions (28/28 on the dev set, 20/20 on two held-out scenarios).
  • Deadlines: 44 of 44 hand-labelled cases after one bug fix; 35 of 44 on the first run (the 9 misses were one bug in reports that run from an earlier submission).
  • False alarms on clean packs: 1 of 102 sentences held, 14 flagged as partly supported, 0 required elements reported missing; the contradiction check read a later time as the detection time in one held-out scenario (2 of 4 clean test packs).
  • When the model drafted every notice (108 sentences) the checker held 2 sentences, both real errors (a time copied from the wrong entry); all 28 required elements were given.
  • Everything is synthetic and written by the agent that built the checker; not run on real incident logs.
  • Planned, not built: pull the log from Slack/Teams exports, tickets and EDR alerts, and fill national NIS2 portal formats and the DORA ITS template. This is connector work, not a bigger model, so it has no wanted tier.
Assemble it

Run this exact stack on your machine

Paste into Claude Code / Codex to assemble this stack locally. The prompt checks your GPU, pulls the pinned models, writes the compose file and runs a smoke test.

incident-notification-pack/assemble-prompt.md147 lines
# Assemble the Decosa incident notification pack on this machine

You are setting up a drafting and checking aid for a CISO and general counsel during a cyber incident. From the team's
incident log (time with a zone, source, text, tags), the entity fields, the regimes counsel is considering and the
notices to draft or check, it seals the log as a hash-chained timeline, computes each report's deadline clock in code
from the tagged entries (SEC 8-K Item 1.05, EU NIS2 Art. 23, EU DORA, EU Cyber Resilience Act Art. 14, California Civ.
Code 1798.82), drafts or checks each notice sentence by sentence against the entries it cites, lists the required
elements a notice lacks and the facts two notices state differently, and returns a Markdown pack and a JSON report
signed by this box's own key. Counsel signs off with a second signed record. Work step by step, show me each command
before you run anything with `sudo`, and stop to ask if a check fails.

## Step 0: set up with a coding agent, rehearse on mock data, then go private

This prompt is for a coding agent running on the machine that will host the service. We recommend Claude Code with
Claude Opus 5.5; any capable coding agent works. Work in this order:

1. Set up on mock data only. During the whole setup you (the agent) work with the synthetic sample bundle below and
   nothing else. Do not ask me for real data, and do not open, read, list or copy files that hold real data, even to
   "test with something realistic".
2. Rehearse. When the steps below are done and the service is healthy, fetch the mock-data bundle for this tool,
   https://decosa.ai/samples/incident-notification-pack.zip (5 KB, 13 checks, synthetic or openly licensed: see `licence` in expected.json),
   show me what is in it, and run the rehearsal against the local API:
   `docker compose exec api python scripts/rehearse.py incident-notification-pack` (the api image carries the same bundle under /app/rehearsal/incident-notification-pack/;
   with no key set, the script asks the local API for a short demo token). From a decosa-api checkout instead:
   `python scripts/rehearse.py incident-notification-pack --bundle incident-notification-pack.zip --base-url http://127.0.0.1:<PORT>`.
   It sends the mock inputs to the local API and prints PASS or FAIL for each expected property (for example: "the pack needs attention", "the wrong detection time is held as a time mismatch", "the held time names the logged one"). Show me
   the full output. Every check must pass. If one fails, fix the install and run it again; never edit `expected.json`
   to make a check pass.
3. Stop there. Once the rehearsal passes, tell me, and I will run my own data against the local API myself, on this
   machine.

For the person running this: a coding agent that runs in the cloud sees everything in its context, including files it
reads, command output and anything pasted into the chat. Keep real data out of the chat and out of anything the agent
can read. Switch to your own data only after the rehearsal has passed and the agent's work is done.

## 0. Ground rules and licences
- Model: Qwen3.8-27B (Apache-2.0), used for three jobs: drafting a notice with citations when none is given, the
  grounding judge (is the sentence backed by the entries it cites), and one element review per notice. The clocks, the
  time and number checks, the contradictions, the timeline record and the report are decosa-api (AGPL-3.0-or-later) and need
  no GPU of their own.
- Incident facts are privileged work product and may be material non-public information. The log stays on this
  machine. Bind every port to 127.0.0.1. The service keeps no log or notice text: logs carry counts only. Keep it that
  way; do not add request logging.
- Be honest about what it is: a drafting and checking aid, not legal advice and not a filing. Counsel decides whether a
  regime applies, whether the incident is significant, major, material or severe, what to file and when, and files it.
  Clocks are only as right as the tags on the log entries.

## 1. Check the machine
1. `nvidia-smi`: one GPU with at least 32 GB (Qwen3.8-27B NVFP4 needs about 20 GB of weights plus KV cache; an RTX PRO
   6000 96 GB is what we measured on; an RTX 5090 32 GB should fit but we have not run this tool on one). Driver
   570 or newer. Blackwell cards run NVFP4; on older cards use `Qwen/Qwen3.8-27B-FP8`.
2. `docker --version` and `docker compose version`. If Docker or the NVIDIA container toolkit is missing, install them
   from the official Docker and NVIDIA repositories after asking me, then run
   `docker run --rm --gpus all nvidia/cuda:12.8.0-base-ubuntu24.04 nvidia-smi`.
3. Disk: about 30 GB free.

## 2. Images and weights
- `${DECOSA_REGISTRY}/decosa-api:<tag>` (**publishing soon**). If the pull fails, build from source:
  `git clone <decosa-api source: on request at https://decosa.ai/contact?topic=self-host>` (access required), check out the newest release tag that
  contains `decosa_api/verticals/incident/` (`main` until one does), and build `docker/api/Dockerfile`.
- `vllm/vllm-openai:v0.29.0` for the model; weights `nvidia/Qwen3.8-27B-NVFP4` (revision
  `482ca0f3832238542f8f5295dde86b5f22711d80`), or `Qwen/Qwen3.8-27B-FP8` on a card without NVFP4.

## 3. docker-compose.yml
Write this in `~/decosa/incident/`:

```yaml
services:
  llm:
    image: vllm/vllm-openai:v0.29.0
    command: ["--model", "nvidia/Qwen3.8-27B-NVFP4", "--served-model-name", "qwen3.8-27b", "--max-model-len", "32768",
              "--enable-prefix-caching"]
    ports: ["127.0.0.1:8114:8000"]
    volumes: ["~/.cache/huggingface:/root/.cache/huggingface"]
    deploy: { resources: { reservations: { devices: [{ driver: nvidia, count: 1, capabilities: [gpu] }] } } }
    healthcheck: { test: ["CMD", "curl", "-fs", "http://localhost:8000/v1/models"], interval: 30s, retries: 20 }
  api:
    image: ${DECOSA_REGISTRY}/decosa-api:<tag>
    ports: ["127.0.0.1:8445:8445"]
    environment:
      DECOSA_HOST: 0.0.0.0
      DECOSA_PORT: "8445"
      DECOSA_DATA_DIR: /data
      DECOSA_LLM_ROUTE: direct
      DECOSA_LLM_URL: http://llm:8000/v1
      DECOSA_LLM_MODEL: qwen3.8-27b
      DECOSA_INCIDENT_SYNTHETIC_ONLY: "0"
      # optional: packs run at once, and model calls in flight per pack
      # DECOSA_INCIDENT_MAX_CONCURRENT: "3"
      # DECOSA_INCIDENT_WORKERS: "6"
      DECOSA_BUDGET_LLM_TOKENS: "60000"
    volumes: ["decosa-data:/data"]
    depends_on: { llm: { condition: service_healthy } }
    healthcheck: { test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8445/incident/info', timeout=4)"], interval: 30s, retries: 10 }
volumes:
  decosa-data:
```

`DECOSA_INCIDENT_SYNTHETIC_ONLY: "0"` lets this box take real incidents; the hosted service refuses anything not
marked `"synthetic": true`. The api keeps its state (keys, receipts, this box's signing key) in the named volume
`decosa-data`, not in a host folder: the image runs as an unprivileged user (uid 10001), and a host folder that Docker
creates is owned by root, which stops the api with `PermissionError: [Errno 13] Permission denied: '/data/keys.sqlite'`.
Then start everything: `docker compose up -d`.

Prefix caching matters: every sentence check and element review of one pack sends the same log first.

On the first start the api creates this box's Ed25519 key in the `decosa-data` volume (`/data/attest/`, mode 0600).
Back it up with `docker compose cp api:/data/attest ./attest-backup` and keep that copy private. Never print it. Every
model call on the direct route gets a receipt signed with that key (status `attested`): an attestation by me, the
operator, not a proof of computation. Never set `DECOSA_LLM_ROUTE=gateway` on this box: that sends incident data to
the hosted Decosa API.

## 4. Smoke test
1. `curl -s localhost:8445/incident/info | jq '{regimes: (.regimes | keys), limits, synthetic_only}'` shows
   `sec_8k`, `nis2`, `dora`, `cra`, `ca_breach` and `synthetic_only: false`.
2. Token: `T=$(curl -s -XPOST localhost:8445/demo/session -H 'content-type: application/json' -d '{"vertical":"incident-notification-pack"}' | jq -r .token)`.
3. `curl -s localhost:8445/incident/samples > samples.json`, then
   `jq '.[] | select(.id=="ransomware-saas") | {incident, entity, log, regimes, notices, synthetic}' samples.json > ransomware.json`.
4. Clocks alone, no model call:
   `curl -s -XPOST localhost:8445/incident/clock -H "authorization: Bearer $T" -H 'content-type: application/json' -d @ransomware.json | jq '.clocks[] | {title, status, due_local, late_by}'`.
   Expect the NIS2 early warning `late` by 7 h 0 min and the Form 8-K `open`, due 17:30 Eastern on the fourth business
   day after the materiality entry.
5. The pack: `curl -s -XPOST localhost:8445/incident/pack -H "authorization: Bearer $T" -H 'content-type: application/json' -d @ransomware.json > res.json`.
   Expect `status: "needs_attention"`: the 8-K sentence with 04:12 UTC held as `time_mismatch` (the cited entry says
   03:12 UTC), the NIS2 sentence saying no personal data was taken held as `contradicted`, the 8-K `impact` element
   missing, and contradictions between the two notices on detection time, systems affected and whether data was taken.
   Most other sentences are `checked`.
6. `jq '{report, pack_md}' res.json | curl -s -XPOST localhost:8445/incident/verify -H 'content-type: application/json' -d @-`
   must show `valid_signature`, `signed_by_this_server` and `pack_md_matches` true. Change `status` in the report and
   verify again: it must fail. `jq .record res.json | curl -s -XPOST localhost:8445/record/verify -H 'content-type: application/json' -d @-`
   must show `ok: true`.
7. Sign-off: `jq '{report, reviewer: {name: "Test Counsel", role: "General counsel"}, decision: "changes_requested"}' res.json | curl -s -XPOST localhost:8445/incident/signoff -H "authorization: Bearer $T" -H 'content-type: application/json' -d @- > so.json`,
   then verify it with `jq -s '{report: .[0].report, signoff: .[1].signoff}' res.json so.json | curl -s -XPOST localhost:8445/incident/verify -H 'content-type: application/json' -d @-`:
   `signoff.valid_signature` and `signoff.matches_report` true.
8. Stream one with `-H 'accept: text/event-stream' -N`: `ready`, then `notice`, `receipt`, `sentence` and `review`
   events, then `report`, `budget` and `done`.
9. Time it and tell me what you measure. The ransomware sample took about 33 s on our shared RTX PRO 6000 through the
   gateway; the direct route is usually faster.

## 5. Point the app at the local API
Set `NEXT_PUBLIC_DECOSA_API=http://127.0.0.1:8445` in the site's `.env.local`, or call `POST /incident/pack` from your
incident tooling and keep `pack_md`, the signed `report`, the sealed `record` and counsel's sign-off with the incident
file. `POST /incident/clock` returns the clocks alone, with no model call, whenever the log changes. Contract:
`API_CONTRACT.md`, section "Changes (incident-notification-pack, 2026-09-26)".

Off by default. Joining serves other people's requests on this GPU; never do it on a box that holds incident data. If I
ask for it, follow the provider guide at `/provide` on the site, and do not enable it without my explicit yes.
Rules and regulations it checks againstDated, linked to the primary source; not legal advice

Regulation watch

Loading the watch status…

18 laws, rules and guidance pages cited; 16 watched nightly at the primary source. A change marks this page for a human re-check; nothing is edited automatically. What we cite and how it is watched

Technical detailsModels, where it runs, labels

In short

Last reviewed

What it is
A signed incident timeline, a deadline clock per regime, and every sentence of each notice checked against the log.
Who it's for
CISOs, general counsel, breach counsel and DFIR firms preparing regulator notices during a cyber incident.
Where it runs
Self-host for real incidents (privileged, possibly material non-public); the hosted demo takes synthetic incidents only
Key numbers
  • 20 / 20 Planted problems caught, held-out scenarios (test split, n = 20)
  • 35 / 44 Deadlines right, hand-labelled cases, first run (test split, n = 44)
  • 1 / 42 Clean sentences held, held-out scenarios (test split, n = 42)
  • 23.3 s Median end-to-end run, hosted (QA sweep 2026-09-26)
All results, datasets and caveats
Models
Qwen3.8-27B drafts, reviews and judges; the clocks, times and numbers are plain code
Where
Self-host for real incidents (privileged, possibly material non-public); the hosted demo takes synthetic incidents only
Checks
Receipt per model call; every time and number checked in code against the cited entries; hash-chained timeline; signed pack and a signed counsel sign-off
Output
Notes, reports and drafts · Signed record or verdict
Data
Confidential business data
Hardware
1× 96 GB GPU
Licence
Permissive (Apache-2.0, MIT)
Runs in
Self-host

Questions people ask

Which deadlines does it compute?

SEC Form 8-K Item 1.05 (four business days after the materiality determination, shown as 17:30 Eastern), NIS2 (24 hours, 72 hours, one month), DORA (4 hours from classification, capped at 24 hours from awareness; 72 hours; one month), the Cyber Resilience Act (24 hours, 72 hours, 14 days after a fix or one month) and California 1798.82 (30 days). Each clock runs from the log entry your team tagged, in code.

How are the notices checked?

Every sentence must cite log entries. Its clock times, counts and dates are checked in code against those entries, and a grounding judge reads the other facts against only what it cites. The pack also lists required elements a notice lacks and facts two notices state differently.

How well does it work?

On our own synthetic incidents it caught 28 of 28 planted problems in the dev scenarios and 20 of 20 in two held-out ones, held 1 of 102 correct sentences, and got 44 of 44 hand-labelled deadlines right after one bug fix (35 of 44 on the first run). It has not been run on real incident logs.

Does it tell me a notice is compliant or file it for me?

No, it never calls a notice compliant and never files. Counsel decides whether a regime applies, whether an incident is material, significant, major or severe, and what to file; counsel's sign-off is recorded as a signed statement.

Can I send a real incident to the hosted demo?

No. Incident facts are privileged and may be material non-public information, so it is self-host first and the hosted demo accepts only incidents marked synthetic. Self-hosted on the direct route, nothing leaves the box.

Ask a question or leave feedbackWe read every message and publish useful answers
Questions & feedback

Ask about Incident notification pack

We read every message. Questions, comments and our answers show here once we have reviewed and approved them.

Loading questions…

This is a

Plain text. Please leave out personal, patient or client data.

Shown with your message if we publish it. Leave blank to post as “A visitor”.

Nothing appears here until we have read and approved it.