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

Keep a signed lab notebook

A tamper-evident notebook that records which conclusions an AI model helped with, from which data files, and that an inspector can verify in the browser.

Measured515 of 520Insider edits caught from the export alone, personal keys (synthetic)
On production24 smedian on production (2026-09-26); slower when the service is busy
List price~$0.10 per 100 AI analysesmeasured, at list price

Built on: Signed record

Keep a signed notebook

Live

The Hartwell Lab is fictional. Run its enzyme-kinetics notebook step by step: entries with instrument files attached by hash, an AI analysis with its receipt, an amendment that keeps the original, a witness and an approval signed with each person's own key, and a trusted timestamp. Then export it and check it.

Entries appear here as they are recorded: each with its hash, the files it holds by SHA-256, and the signatures on it.

AI analyses are marked, with the data the model saw and its receipt. Amendments point at the original, which stays.

What the export shows: who recorded what and when, every amendment and why, which entries a model wrote (with its receipt and the exact data it saw), and each e-signature with its meaning, none of it changed after signing. What it cannot show: that the science is right, or that a lab's procedures meet 21 CFR Part 11. The notebook supports Part 11 audit-trail requirements; compliance also needs validation, procedures and controls at the lab.

Watch a recorded run first

Watch: a lab notebook with an AI analysis, an amendment and a countersign

Replay · not live

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 the analysis model; the notebook, signatures and verification 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 signed lab notebook 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
signed-lab-notebook

Use the hosted API

# Decosa signed lab notebook: use the hosted API

You are wiring Decosa's signed lab notebook into our lab's tools (an instrument script, our ELN or a data pipeline).
It keeps numbered entries on an append-only hash chain, instrument files by SHA-256, amendments that point at the
original and give a reason, e-signatures with meaning, a log of AI analyses (exact prompt, data hashes, model, signed
receipt, output) and RFC 3161 timestamps, and exports a signed record an inspector can check in their browser. 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`.
- Hosted is for synthetic, public or published data. Unpublished results belong on a self-hosted box.
- It supports 21 CFR Part 11 audit-trail requirements; it does not make us compliant (validation and SOPs are ours).

## Auth
1. Preferred: an API key (`dk_…`) from "Get an API key" on the tool page, in the 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": "signed-lab-notebook"}` returns `{"token", "expires_at", "budget"}`.
   A notebook is visible only to the key or token that made it; hosted notebooks expire after 14 days.

## The flow
1. `POST /notebook/books` `{"title", "lab"?, "project"?, "description"?, "owner": {"name", "role"?, "pubkey"?}}` → `{notebook_id, ...}`.
2. Members who write or sign: `POST /notebook/books/{id}/members` `{"name", "role"?, "pubkey"?}`. A `pubkey` (raw Ed25519,
   64 hex) means that person must sign with their own key; without one, signatures are recorded as "account".
3. Entries: `POST /notebook/books/{id}/entries` `{"title", "text", "author", "attachments": [{"name", "sha256", "bytes", "kind": "instrument", "instrument": {"name", "serial"?, "run_id"?}}]}`.
   Hash files locally; never send them. Entries are numbered 1, 2, 3.
4. Corrections: `POST /notebook/books/{id}/amend` `{"amends": <entry number>, "text", "reason", "author"}`. The original stays.
5. AI analysis: `POST /notebook/books/{id}/analysis` `{"question", "requested_by", "of": [entry numbers], "data": [{"name", "text"}]}`.
   Each data file's SHA-256 must equal an attachment already recorded (409 otherwise). One receipted model call:
   `{entry, text, receipt, usage}`; `"stream": true` gives SSE `ready`, `receipt`, `analysis`, `budget`, `done`.
6. Sign: `POST /notebook/books/{id}/sign` `{"n", "meaning": "authored" | "witnessed" | "reviewed" | "approved", "signer", "signature"?: {"sig", "signed_ms"}}`.
   With an enrolled key, sign `"decosa.notebook-signature.v1\n" + canonical JSON of {v, notebook, target_seq, target_hash, meaning, signer, statement_sha256, signed_ms}`
   (see `GET /notebook/info`; `target_seq` and `target_hash` come from the entry, `statement_sha256` is the SHA-256 of the meaning's statement).
7. Timestamp: `POST /notebook/books/{id}/timestamp` `{}` (RFC 3161, at most one a minute per notebook).
8. Export: `GET /notebook/books/{id}/export` (signed JSON) and `GET /notebook/books/{id}/audit.csv`.

## Example (Python, `pip install httpx`)
```python
import hashlib, httpx, os, pathlib
API = "https://api.decosa.ai"
c = httpx.Client(base_url=API, headers={"Authorization": f"Bearer {os.environ['DECOSA_API_KEY']}"}, timeout=180)
nb = c.post("/notebook/books", json={"title": "Kinetics notebook", "owner": {"name": "Dr. Ada Lin"}}).raise_for_status().json()
N = nb["notebook_id"]
data = pathlib.Path("rates.csv").read_bytes()
c.post(f"/notebook/books/{N}/entries", json={"title": "Plate run", "text": "Initial rates attached.", "author": "Dr. Ada Lin",
       "attachments": [{"name": "rates.csv", "sha256": hashlib.sha256(data).hexdigest(), "bytes": len(data), "kind": "instrument",
                        "instrument": {"name": "Plate reader"}}]}).raise_for_status()
a = c.post(f"/notebook/books/{N}/analysis", json={"question": "Summarise and flag outliers.", "requested_by": "Dr. Ada Lin",
           "of": [1], "data": [{"name": "rates.csv", "text": data.decode()}]}).raise_for_status().json()
print(a["receipt"]["status"], a["text"][:200])
rec = c.get(f"/notebook/books/{N}/export").raise_for_status().json()
print(httpx.post(f"{API}/notebook/verify", json={"record": rec}).json()["summary"])
```

## Verify
- `POST https://api.decosa.ai/notebook/verify` `{"record", "earlier"?}` (no token): hashes, signatures, AI receipts, TSA tokens and
  the notebook rules; with `earlier`, whether nothing before it was rewritten.
- The site's verify page (`/notebook/verify`) runs the same checks in the browser, with no upload.

## Honest limits
- AI analyses are recorded and receipted, not checked for correctness; a person must review them.
- Our server signs exports. Keep your own copy of each export and use personal keys for signers: those catch an
  operator who rebuilds a notebook.

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 signed lab notebook: run it yourself (containers)

You are setting up Decosa's signed lab notebook on this machine, so unpublished results and invention records stay
here. The notebook (decosa-api) needs no GPU. Qwen3.8-27B is only needed for AI analyses. The only outbound call is the
RFC 3161 timestamp request (a 32-byte digest to the Time-Stamp Authority), and it can be turned off.

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.

Hardware: any Linux x86_64 machine for the notebook; 1x RTX 5090 32 GB or larger for Qwen3.8-27B (NVFP4). 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/signed-lab-notebook.zip (6 KB, 7 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 signed-lab-notebook` (the api image carries the same bundle under /app/rehearsal/signed-lab-notebook/;
   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 signed-lab-notebook --bundle signed-lab-notebook.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 AI analysis flags the planted outlier well F7", "the analysis records the SHA-256 of the rates file it read", "the amendment points at the original run entry, which stays in the record"). 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.

## Rules you must keep
- Bind every port to 127.0.0.1. Expose nothing without my approval.
- The box's signing key is created on first start in the data volume (`attest/ed25519.pem`, 0600). Back it up with the
  notebooks (`/data/notebook/*.jsonl`); never print it.
- Set `DECOSA_NOTEBOOK_TTL_S` to our retention (the default is 14 days, for demos).
- Part 11: this supports audit-trail and signature-manifestation requirements; validation, SOPs and access control are ours.

## Steps
1. Docker (and the NVIDIA Container Toolkit if you run the model): if `docker compose version` fails, install it from
   the official Docker instructions.
2. Fetch the compose file: `mkdir -p ~/decosa && cd ~/decosa && curl -fsSL "${DECOSA_COMPOSE_URL}" -o compose.yaml`. Read it.
   Keep the `api` service; keep `llm` only for AI analyses. The api's data goes in a named volume, not a host folder.
3. In `.env`: `DECOSA_LLM_ROUTE=direct`, `DECOSA_LLM_URL=http://llm:8000/v1`, `DECOSA_LLM_MODEL=qwen3.8-27b` (with `llm`),
   `DECOSA_ADMIN_SECRET` (a long random string, file mode 0600), `DECOSA_NOTEBOOK_TTL_S`, and `DECOSA_NOTEBOOK_TSA_URL`
   (`https://freetsa.org/tsr` by default, our own TSA, or `off`).
4. Start: `docker compose pull && docker compose up -d`. Wait for `curl -fsS http://localhost:<PORT>/notebook/info`.
5. Mint a key: `POST /v1/keys` with the admin secret and `{"label": "lab", "verticals": ["signed-lab-notebook"]}`.
6. Smoke test with a token from `POST /demo/session {"vertical": "signed-lab-notebook"}`: take the `enzyme-kinetics`
   sample from `GET /notebook/samples`, create a notebook, add the members, an entry with `rates.csv` attached by its
   SHA-256, an analysis of it (with `llm`; expect receipt status `attested`), an amendment with a reason, a witness
   signature, and a timestamp. Then `GET .../export` and `POST /notebook/verify {"record": ...}`: expect `ok: true`.
7. Change one digit in the analysis entry's data and verify again: it must fail at that entry.
8. Report back: health, the signing key id, the verify summary and the time each step took.

Off by default. Leave it off unless I ask.

No NVIDIA GPU? This tool also runs entirely on an Apple Silicon Mac (MLX, 32 GB of unified memory or more): use https://decosa.ai/prompts/signed-lab-notebook-mac.md instead.
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 (32 of 96 GB).

  • Apple M5 Max, 64 GBstandard tierRuns

    The standard tier fits (32 of 64 GB).

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":"signed-lab-notebook"}'

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 signed-lab-notebook

Download the mock-data bundle (6 KB, 7 checks)expected.json

A fictional lab records a protocol and a plate-reader run with its rates file attached by SHA-256, asks the model to analyse the data (receipted), amends the run to exclude the planted outlier well F7 with a reason, and collects witness, review and approval signatures and an RFC 3161 timestamp. The exported record must verify, and a copy with one entry changed must not. The timestamp comes from FreeTSA, a free third-party authority: if it is down that step is skipped and nothing checks it.

What the rehearsal checks
  • the AI analysis flags the planted outlier well F7
  • the analysis records the SHA-256 of the rates file it read
  • the amendment points at the original run entry, which stays in the record
  • the exported record verifies
  • the record holds 1 amendment and 3 e-signatures
  • a copy with the amendment reason changed no longer verifies
  • every model call has a signed receipt

Licence: Synthetic: the lab, people, instrument and data are invented for Decosa; the rates come from a Michaelis-Menten curve (Vmax 118, Km 0.42 mM) with small noise and one deliberate outlier. Part of decosa-api, AGPL-3.0-or-later.

Prompt for your coding agent

# Decosa signed lab notebook: run it yourself (containers)

You are setting up Decosa's signed lab notebook on this machine, so unpublished results and invention records stay
here. The notebook (decosa-api) needs no GPU. Qwen3.8-27B is only needed for AI analyses. The only outbound call is the
RFC 3161 timestamp request (a 32-byte digest to the Time-Stamp Authority), and it can be turned off.

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.

Hardware: any Linux x86_64 machine for the notebook; 1x RTX 5090 32 GB or larger for Qwen3.8-27B (NVFP4). 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/signed-lab-notebook.zip (6 KB, 7 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 signed-lab-notebook` (the api image carries the same bundle under /app/rehearsal/signed-lab-notebook/;
   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 signed-lab-notebook --bundle signed-lab-notebook.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 AI analysis flags the planted outlier well F7", "the analysis records the SHA-256 of the rates file it read", "the amendment points at the original run entry, which stays in the record"). 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.

## Rules you must keep
- Bind every port to 127.0.0.1. Expose nothing without my approval.
- The box's signing key is created on first start in the data volume (`attest/ed25519.pem`, 0600). Back it up with the
  notebooks (`/data/notebook/*.jsonl`); never print it.
- Set `DECOSA_NOTEBOOK_TTL_S` to our retention (the default is 14 days, for demos).
- Part 11: this supports audit-trail and signature-manifestation requirements; validation, SOPs and access control are ours.

## Steps
1. Docker (and the NVIDIA Container Toolkit if you run the model): if `docker compose version` fails, install it from
   the official Docker instructions.
2. Fetch the compose file: `mkdir -p ~/decosa && cd ~/decosa && curl -fsSL "${DECOSA_COMPOSE_URL}" -o compose.yaml`. Read it.
   Keep the `api` service; keep `llm` only for AI analyses. The api's data goes in a named volume, not a host folder.
3. In `.env`: `DECOSA_LLM_ROUTE=direct`, `DECOSA_LLM_URL=http://llm:8000/v1`, `DECOSA_LLM_MODEL=qwen3.8-27b` (with `llm`),
   `DECOSA_ADMIN_SECRET` (a long random string, file mode 0600), `DECOSA_NOTEBOOK_TTL_S`, and `DECOSA_NOTEBOOK_TSA_URL`
   (`https://freetsa.org/tsr` by default, our own TSA, or `off`).
4. Start: `docker compose pull && docker compose up -d`. Wait for `curl -fsS http://localhost:<PORT>/notebook/info`.
5. Mint a key: `POST /v1/keys` with the admin secret and `{"label": "lab", "verticals": ["signed-lab-notebook"]}`.
6. Smoke test with a token from `POST /demo/session {"vertical": "signed-lab-notebook"}`: take the `enzyme-kinetics`
   sample from `GET /notebook/samples`, create a notebook, add the members, an entry with `rates.csv` attached by its
   SHA-256, an analysis of it (with `llm`; expect receipt status `attested`), an amendment with a reason, a witness
   signature, and a timestamp. Then `GET .../export` and `POST /notebook/verify {"record": ...}`: expect `ok: true`.
7. Change one digit in the analysis entry's data and verify again: it must fail at that entry.
8. Report back: health, the signing key id, the verify summary and the time each step took.

Off by default. Leave it off unless I ask.

No NVIDIA GPU? This tool also runs entirely on an Apple Silicon Mac (MLX, 32 GB of unified memory or more): use https://decosa.ai/prompts/signed-lab-notebook-mac.md instead.

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

RunsSigned lab notebook on GeForce RTX 5090: use the Standard · Qwen3.8-27B writes receipted AI analyses (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:

  • 1× RTX 5090 32 GB (fits): Qwen3.8-27B NVFP4 needs about 20 GB of weights plus KV cache. Estimate: same model stack as the other Qwen verticals, not run here for this one.

Standard · Qwen3.8-27B writes receipted AI analyses (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
  • Notebook: decosa-api notebook module (decosa_api/verticals/notebook). CPU. Runs on CPU (vram_gb 0 in stack.json).
  • Writes the AI analysis note from the selected...: 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 Signed lab notebook, 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 Signed lab notebook on my hardware

Fetch https://decosa.ai/prompts/signed-lab-notebook-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=signed-lab-notebook)

Target machine: GeForce RTX 5090 (32 GB of GPU memory; CUDA, FP8 and NVFP4).
Quality tier: Standard · Qwen3.8-27B writes receipted AI analyses (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):
- Notebook: decosa-api notebook module (decosa_api/verticals/notebook), CPU
- Writes the AI analysis note from the selected...: 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/signed-lab-notebook-assemble.md

Or on a Mac Studio

No NVIDIA GPU needed: every model this tool uses runs natively on Apple Silicon through MLX. Any M-series Mac with 32 GB of unified memory or more. Measured speeds and what runs where

From a checkout of decosa-api, one command sets up the models and the API: scripts/mac/setup.sh

Mac prompt for your coding agent

# Decosa Signed lab notebook: run it on this Mac (Apple Silicon, no NVIDIA GPU)

You are setting up the Decosa Signed lab notebook on this Mac, natively on Apple Silicon. The models run on the Mac's GPU
through MLX and decosa-api runs from a git checkout with `uv`. Docker is not used for the models, because Docker on
macOS cannot reach the GPU. Nothing is sent to Decosa's hosted API.

Every model this tool needs runs on the Mac. It needs 32 GB of unified memory or more.

Ask me before any command that needs sudo or installs software with Homebrew, and show me the command first. Never stop
or kill a process this setup did not start; if a port is taken, pick another one.

## 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/signed-lab-notebook.zip (6 KB, 7 checks, synthetic or openly licensed: see `licence` in expected.json),
   show me what is in it, and run the rehearsal against the local API:
   `.venv/bin/python scripts/rehearse.py signed-lab-notebook` in the decosa-api checkout (the key comes from ~/.decosa-mac/api.key).
   It sends the mock inputs to the local API and prints PASS or FAIL for each expected property (for example: "the AI analysis flags the planted outlier well F7", "the analysis records the SHA-256 of the rates file it read", "the amendment points at the original run entry, which stays in the record"). 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.

## What runs where

| Part | On an NVIDIA GPU | On this Mac | Status |
|---|---|---|---|
| Notebook: hash chain, members, amendments, e-signature rules, RFC 3161 client, export, audit CSV and verification (no model; CPU) | Python on CPU | The same Python module, run with uv | Runs, measured |
| Writes the AI analysis note from the selected entries and attached data files | NVFP4 on vLLM 0.29 (Blackwell) | MLX 4-bit (EigenLabs/Qwen3.8-27B-4bit) on mlx_lm.server 0.31.3; oMLX 0.6.1 with MTP as an option | Runs, measured |

## Steps
1. Check the machine: `uname -m` must print `arm64` (an M-series chip; Intel Macs cannot run MLX), and
   `sysctl -n hw.memsize` should be at least 32 GB for this tool. Check about 30 GB of free disk with
   `df -h ~`. Show me the chip (`sysctl -n machdep.cpu.brand_string`) and the memory.
2. Tools: `uv --version`. If it is missing, ask me, then `brew install uv`.
3. Code: `git clone <decosa-api source: on request at https://decosa.ai/contact?topic=self-host> ~/decosa-api` (access required) and `cd ~/decosa-api`.
   Check that `scripts/mac/setup.sh` exists; if it does not, the checkout is too old: stop and tell me.
4. Start everything with one command: `scripts/mac/setup.sh`. It creates `.venv` (decosa-api)
   and `.venv-mac` (MLX, mlx-lm, mlx-audio), downloads the weights with the Hugging Face CLI (about 16 GB for the
   language model), starts the model servers and decosa-api on 127.0.0.1, and mints a local API key
   into `~/.decosa-mac/api.key` (mode 0600). The first run takes a while because of the downloads; later runs reuse them.
   If a download fails with 401 or 403, ask me for a Hugging Face token and set `HF_TOKEN`.
5. Check health: `scripts/mac/setup.sh status` shows each server, and `curl -fsS http://127.0.0.1:8445/healthz` must
   report `"llm": true`. `curl -fsS http://127.0.0.1:8445/attest/signing-key` shows this Mac's public key:
   show it to me, because it is what others pin to check the receipts and records this Mac signs.
6. Smoke test: `.venv/bin/python scripts/mac/bench_usecases.py signed-lab-notebook`. It runs the tool's own sample end to end
   against the local API with the local key and prints `ok`, the wall time, the model calls and the receipts.
   `ok=True` is the pass condition. If it fails, read `~/.decosa-mac/logs/*.log` and tell me what you found.
7. Point the app at it: the API is `http://127.0.0.1:8445` with `Authorization: Bearer $(cat ~/.decosa-mac/api.key)`,
   the same routes as the hosted API. To stop everything: `scripts/mac/setup.sh stop`.
8. Report back: the chip and memory, the public key, the smoke-test result and its time, and the output of
   `scripts/mac/setup.sh status`.

## Good to know
- Receipts: every model call is signed with this Mac's own Ed25519 key and names the exact MLX weights
  (`qwen3.8-27b-mlx-4bit` with a hash of the downloaded files). There is no gateway countersignature on a
  self-hosted Mac.
- The weights are a 4-bit MLX build of the same open models, not the NVFP4 build the hosted route and the published
  evals use. Expect small differences in wording and scores.
- Faster drafting: `scripts/mac/setup.sh stop && scripts/mac/setup.sh --engine omlx` serves the
  model with oMLX and multi-token prediction (about 2x faster for a single long answer, no faster for many parallel
  calls; typed judgments then use sampling because oMLX returns no log-probabilities).
- Measured speeds for a Mac Studio M3 Ultra and the memory each tool needs: https://decosa.ai/mac. Full details:
  `docs/self-host-mac.md` in the checkout.

The proof

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

Verified end to end

Hosted: pass (pre-release server) on 26 Sep 2026 · QA sweep · p50 24 s · ~$0.001 per run · 1 receipt

Loading the nightly status…

Self-host: verified 26 Sep 2026 · Fresh clone of the branch into a clean directory on our server, image built from docker/api/Dockerfile, api started with compose (named volume, python healthcheck), then the assemble prompt's smoke steps 1-9; torn down afterwards.

Measured cost to run: about $0.10 per 100 AI analyses (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.

Ran against the already-running Qwen3.8-27B vLLM on 127.0.0.1:8114 instead of the compose llm service; model-server startup not re-verified. Analysis receipt attested, FreeTSA token in 159 ms, export verified, altered export rejected. Host networking and port 8438 because other services held the default ports.

Known limits (6)
  • Hosted check ran on the pre-release server (decosa-api the pre-release branch on our server, gateway route): console flow with personal keys, own entry with a file, AI analysis, self-witness refused, timestamp rate limit, export, audit CSV, tamper buttons, verify page, Watch replay, Build example as written, 390 px layout. Production runs it once merged and deployed.
  • The server signs exports with its own key: an operator could rebuild a notebook that has only account signatures and no surviving TSA token. Personal keys and export copies kept by others catch that.
  • Signer identity is the name the key-holder sends unless the signer enrolled a personal key; no SSO or two-component sign-in (21 CFR 11.200) yet.
  • AI analyses are receipted, not graded; the number check only points at numbers not in the data.
  • FreeTSA is a free service with no SLA; TSA certificate revocation is not checked (the issuer is pinned).
  • POST /notebook/verify takes 8 MB by default; larger exports are checked in the browser (a 17 MB, 10,000-entry export took 4.7 s).

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 the analysis model; the notebook, signatures and verification 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 signed lab notebook 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 tamper-evident lab notebook that shows which conclusions an AI model helped with, and lets an inspector check it without trusting you.

Every entry, amendment and e-signature goes on an append-only hash chain. Instrument files are hashed in the browser, so only their SHA-256 is recorded; a correction is a new entry that points at the original and gives a reason. Witnesses and approvers sign one exact version with their own Ed25519 key, with a meaning (authored, witnessed, reviewed, approved). When a scientist asks the open model to analyse data, the exact prompt, the hash of every data file it saw (which must match a file already attached), the model and its signed receipt go on the record. RFC 3161 timestamps from an independent authority bound when each part existed. The export is a signed record plus an audit-trail CSV, and a verify page checks it in the inspector's browser. It is for academic labs, biotech and CROs that use AI on their data and need to show what it did; it is a signing and provenance layer with a small notebook, not a full ELN.

Deployment
Hosted or self-host
Regulatory
Checked 26 Sep 2026. 21 CFR Part 11 sets when FDA treats electronic records and signatures as equivalent to paper for records other FDA rules require (the predicate rules). The notebook supports the audit-trail requirement of 11.10(e) (secure, computer-generated, time-stamped records of who created or changed what, without obscuring earlier entries), the signature manifestation of 11.50 (printed name, date and time, and meaning) and the signature/record linking of 11.70. Compliance also needs the lab's validation, written procedures, training, access control and signature controls under 11.100 to 11.300 (for example two distinct identification components for non-biometric signatures); software alone does not make anyone compliant. FDA's guidance Part 11, Electronic Records; Electronic Signatures: Scope and Application (August 2003) narrowed enforcement (validation, audit trails, record retention and copying) while the predicate rules still apply; the final guidance Electronic Systems, Electronic Records, and Electronic Signatures in Clinical Investigations: Questions and Answers (October 2024, docket FDA-2017-D-1105) covers clinical investigations. The trusted timestamps follow RFC 3161; their weight depends on the Time-Stamp Authority (FreeTSA, the default, is free with no SLA; an eIDAS-qualified or commercial TSA can be configured). AI analyses are recorded and receipted, not validated: a person must still check them. Model licence: Apache-2.0 (Qwen3.8-27B). Not legal or regulatory advice.
Architecture
Text description

Scientists write entries in the browser; files are hashed there and only their SHA-256 is sent. Each entry, amendment and e-signature is appended to a hash chain in decosa-api. Signers sign with their own Ed25519 keys kept in the browser. For an AI analysis, the question, the selected entries and the attached data go to Qwen3.8-27B through our gateway, which returns a signed receipt covering the output; the prompt, the data hashes, the receipt and the output go on the chain. An independent RFC 3161 Time-Stamp Authority signs the chain head. The server signs exports; outputs are the signed export, an audit-trail CSV and a verify page that checks everything in the browser. In self-host mode the notebook and the model run on your machine; only timestamp requests leave it.

Architecture

At a glance

What you send
Entry text, file hashes (files are hashed in your browser), members and their public keys, signatures, and the data text for an AI analysis (up to 60,000 characters).
What you get
A signed export (JSON) with every entry, amendment, AI analysis, e-signature and RFC 3161 token; an audit-trail CSV; a verify page an inspector runs in their browser.
Typical cost
One model call per AI analysis: a fraction of a cent at the gateway list price. Entries, signatures, timestamps and exports are CPU.
Retention (hosted)
Demo notebooks expire after 14 days. Self-host keeps notebooks as append-only files in your data volume for as long as you set.
What leaves the box (self-host)
Only the timestamp request: a 32-byte digest of the chain head, sent to the TSA. On the hosted route the entries and analysis data reach our server and the gateway.
Part 11
Supports the audit-trail, signature-manifestation and signature/record-linking requirements. Validation, SOPs, SSO and two-component sign-in are yours to provide.
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.

  • Lite

    notebook, signatures and timestamps on CPU (self-host)

    Everything except AI analyses: entries, amendments, personal e-signatures, RFC 3161 timestamps, the signed export and the verify page. Analyses you run elsewhere can be recorded as ordinary entries, without a receipt.

    Models
    • decosa-api notebook module (decosa_api/verticals/notebook)
    Hardware
    Any CPU
    Quality evidence
    • Genuine exports verified300 / 300docs/evals/signed-lab-notebook.md
    • Alterations caught, file edited without keys (13 kinds in 5 groups, 3 configurations)1,400 / 1,400docs/evals/signed-lab-notebook.md
    • Alterations caught, insider with the server key, personal keys + TSA515 / 520 on the export alone; 520 / 520 with an earlier exportdocs/evals/signed-lab-notebook.md
    • Verify a 10,000-entry notebook (17,107 chain entries)2.6 s Python; 4.7 s browser code (Node)docs/evals/signed-lab-notebook.md
    Latency
    measured: entries, signatures and exports take milliseconds; a timestamp adds one round trip to the TSA
    Verification
    No proof yetSelf-host onlyNo model call, so no receipts: the export is signed by your box, and personal keys and TSA tokens are the outside signatures.
  • In the hosted demo

    Standard

    Qwen3.8-27B writes receipted AI analyses (hosted demo)

    Adds the AI-analysis log: the model writes a note from the selected entries and attached data, with a signed receipt, the exact prompt and the data hashes on the record. This is what the hosted API runs.

    Models
    • decosa-api notebook module (decosa_api/verticals/notebook)
    • Qwen3.8-27B (NVFP4)
    Hardware
    1× RTX PRO 6000 96 GB (measured) or 1× RTX 5090 32 GB (estimate)
    Quality evidence
    • AI analyses with a signed receipt covering the stored output5 / 5 end-to-end runs (smoke, recorder, self-host, two console analyses)scripts/smoke/signed-lab-notebook.py; docs/evals/signed-lab-notebook.md
    • Insider edit of an AI output with a gateway receipt (real export)caught: the gateway receipt covers a different outputdocs/evals/signed-lab-notebook.md
    • Sample analysis: outlier named, numbers checkednamed well F7 in the run recorded; 7 of 13 numbers in the data, 4 rounded, 2 flagged (one run, not an accuracy measure)docs/evals/signed-lab-notebook.md
    • Tamper detection and 10k performanceas the lite tier (same code)docs/evals/signed-lab-notebook.md
    Latency
    measured on a shared, busy GPU: one analysis in under half a minute; the rest of the notebook is milliseconds
    Verification
    Proof: strongEach AI analysis carries a gateway-signed receipt embedded in the signed export.
Components

Every model in the stack

Models in this stack. Each row has a button that shows its licence, engine, verification and evidence.
ModelDetails
Notebook: hash chain, members, amendments, e-signature rules, RFC 3161 client, export, audit CSV and verification (no model; CPU)decosa-api notebook module (decosa_api/verticals/notebook)
0 GBProof: partial
Writes the AI analysis note from the selected entries and attached data filesQwen3.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

  • FreeTSA (freetsa.org), RFC 3161 Time-Stamp Authority (opens in a new tab)Free public service; no written terms of service or SLA

    Signs the chain head and Merkle root with an ECDSA P-384 certificate issued by the FreeTSA root, which is pinned in the API and the site (PEM sha256 2151b611…e044438, fetched 25 Sep 2026). Chosen as the cheapest honest outside anchor; DigiCert and Sectigo's public TSAs also answered, and any RFC 3161 TSA can be set with DECOSA_NOTEBOOK_TSA_URL.

  • Verify page (/notebook/verify) and POST /notebook/verifyApache-2.0

    Checks an export in the inspector's browser: hashes, links, the server signature, personal e-signatures, AI analyses against the data they cite and their receipts, and RFC 3161 tokens; optionally that a later export still contains an earlier one unchanged.

  • GET /notebook/books/<id>/audit.csvApache-2.0

    Who, what, when and why for every chain entry, with hashes, for an inspector's spreadsheet.

  • scripts/notebook_eval.py and docs/evals/signed-lab-notebook.mdApache-2.0

    Genuine exports, 13 alterations by an outsider and by an insider holding the server key, and a 10,000-entry notebook (decosa-api).

Services

  • decosa-api (notebook routes):8445
    ${DECOSA_REGISTRY}/decosa-api:<tag>

    POST /notebook/books, /members, /entries, /amend, /analysis (SSE or JSON), /sign, /timestamp; GET /notebook/books/<id>, /export, /audit.csv; POST /notebook/verify; GET /notebook/info, /notebook/samples.

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

    Qwen3.8-27B NVFP4 behind our gateway (hosted) or called directly (self-host). Not needed on the lite tier.

Hardware

  • Any CPU, no GPU Fits

    Lite tier: notebook, signatures, timestamps, export and verification. A 10,000-entry notebook verifies in 2.6 s on one core.

  • 1× RTX 5090 32 GB Fits

    Qwen3.8-27B NVFP4 needs about 20 GB of weights plus KV cache. Estimate: same model stack as the other Qwen verticals, not run here for this one.

  • 1× RTX PRO 6000 Blackwell 96 GB Fits

    Measured on our server: the hosted demo ran on this card, shared with other services.

Latency per lane

  • AI analysis of the sample (about 1,080 prompt and 480 generated tokens), hosted gateway route22.2 s

    Measuredmeasured on our server 2026-09-26: 22.2 s in the smoke run while the shared gateway was busy with other evaluation jobs

  • RFC 3161 timestamp from FreeTSA, including verification159 ms

    Measuredmeasured on our server 2026-09-26: 159 ms in the self-host run (one request)

  • whole sample notebook: 2 members, 3 entries, 1 AI analysis, 3 signatures, 1 timestamp, export23.7 s

    Measuredmeasured on our server 2026-09-26: 22.4 s (smoke) and 23.7 s (recorder), nearly all of it the model call

  • verify a 10,000-entry export (17,107 chain entries, 17 MB)4.7 s

    Measuredmeasured 2026-09-26: 2.6 s in Python on our server, 4.7 s for the site's browser code under Node 26 on a Mac

Notes

  • All 300 genuine synthetic exports verified. Every alteration by someone editing the file without keys was caught (1,400 of 1,400: edits, deletions, reordering, backdating, forged signatures), naming the entry.
  • An insider holding the server key, who repairs every hash and re-signs, was caught on the export alone in 515 of 520 cases when signers used personal keys and TSA timestamps, and in 1,400 of 1,400 when compared with an earlier export a witness kept. With account signatures only, most such rewrites pass on their own: keep export copies.
  • Python and the browser verifier agree on 219 of 219 exports.
  • The number check lists numbers in an AI analysis that are not in its data (calculated, thresholds or wrong) for the reviewer; it does not grade the analysis.
  • What it cannot show: that the science is right, that a named person without a personal key really signed, or that the lab's procedures meet Part 11.
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.

signed-lab-notebook/assemble-prompt.md129 lines
# Assemble the Decosa signed lab notebook on this machine

You are setting up a signed lab notebook for our lab: numbered entries on an append-only hash chain, instrument files
attached by SHA-256, amendments that point at the original and give a reason, e-signatures with meaning (authored,
witnessed, reviewed, approved) made with each person's own key, an AI-analysis log where every model call carries a
receipt and the exact data it saw, RFC 3161 timestamps from an independent authority, and a signed export plus an
audit-trail CSV for an inspector. 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/signed-lab-notebook.zip (6 KB, 7 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 signed-lab-notebook` (the api image carries the same bundle under /app/rehearsal/signed-lab-notebook/;
   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 signed-lab-notebook --bundle signed-lab-notebook.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 AI analysis flags the planted outlier well F7", "the analysis records the SHA-256 of the rates file it read", "the amendment points at the original run entry, which stays in the record"). 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 only for AI analyses. It is optional: without it the notebook, signatures,
  timestamps and exports all work, and analyses answer 503.
- The notebook is decosa-api (AGPL-3.0-or-later) and needs no GPU. Files never leave the browser: only their hashes are stored.
- Unpublished results stay on this machine. Bind every port to 127.0.0.1. Logs carry ids and counts only; do not add
  request logging.
- Be accurate about Part 11: this supports the 21 CFR Part 11 audit-trail and signature-manifestation requirements.
  Compliance also needs our validation, SOPs, training and access controls; the software does not make us compliant.
- Honest limit: this box signs with its own key, so whoever runs it could rebuild a notebook. Personal signing keys,
  TSA timestamps and export copies kept by witnesses are what catch that.

## 1. Check the machine
1. For the model: `nvidia-smi` shows one GPU with at least 32 GB (Qwen3.8-27B NVFP4 needs about 20 GB of weights plus KV
   cache; an RTX 5090 32 GB or an RTX PRO 6000 96 GB). Driver 570 or newer. Blackwell cards run NVFP4; on older cards
   use `Qwen/Qwen3.8-27B-FP8`. For the notebook alone, any x86_64 Linux box.
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 for the model weights. A notebook of 10,000 entries is about 17 MB.
4. Outbound HTTPS to `freetsa.org` for timestamps (or our own TSA, or set `DECOSA_NOTEBOOK_TSA_URL=off`).

## 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 a release that contains
  `decosa_api/verticals/notebook/`, and run `docker build -f docker/api/Dockerfile -t decosa-api:local .`
- `vllm/vllm-openai:v0.29.0` for the model; weights `nvidia/Qwen3.8-27B-NVFP4`.

## 3. docker-compose.yml
Write this in `~/decosa/notebook/` (drop the `llm` service and the `depends_on` for the notebook-only setup):

```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", "--seed", "0"]
    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_ADMIN_SECRET: ${DECOSA_ADMIN_SECRET}      # for minting keys; put it in ~/decosa/notebook/.env (0600)
      DECOSA_NOTEBOOK_TTL_S: "3153600000"              # keep notebooks (100 years); the hosted demo uses 14 days
      DECOSA_NOTEBOOK_TSA_URL: https://freetsa.org/tsr  # or our TSA, or "off"
      DECOSA_RECORD_MAX_BYTES: "67108864"              # let POST /notebook/verify take large exports
    volumes: ["decosa-data:/data"]
    depends_on: { llm: { condition: service_healthy } }
    healthcheck: { test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8445/notebook/info', timeout=4)"], interval: 30s, retries: 10 }
volumes:
  decosa-data:
```

On the first start the api service creates this box's Ed25519 key in the `decosa-data` volume (`attest/`, mode 0600).
Back it up with the volume; never print it. Notebooks live in `/data/notebook/` as append-only JSONL files: include
them in our backups. Every AI analysis on the direct route gets a receipt signed with the box's key (status `attested`).

For real use, mint a key per lab or instrument script:
`curl -s -XPOST localhost:8445/v1/keys -H "authorization: Bearer $DECOSA_ADMIN_SECRET" -H 'content-type: application/json' -d '{"label": "lab", "verticals": ["signed-lab-notebook"], "daily_llm_tokens": 200000}'`.
Notebooks are visible only to the key that made them.

## 4. Smoke test
1. `curl -s localhost:8445/notebook/info | jq '{format, model, signed, tsa: .timestamp.tsa}'`.
2. Token: `T=$(curl -s -XPOST localhost:8445/demo/session -H 'content-type: application/json' -d '{"vertical":"signed-lab-notebook"}' | jq -r .token)`.
3. `curl -s localhost:8445/notebook/samples > samples.json`, then
   `N=$(jq '.[0].notebook | {title, lab, owner}' samples.json | curl -s -XPOST localhost:8445/notebook/books -H "authorization: Bearer $T" -H 'content-type: application/json' -d @- | jq -r .notebook_id)`.
4. Members: `POST /notebook/books/$N/members` with `{"name": "Dr. Maya Okafor"}` and `{"name": "Dr. Tomas Reyes"}`.
5. Entry with the sample's rates file by hash: write the file byte for byte with
   `jq -j '.[0].files["rates.csv"]' samples.json > rates.csv`, take `sha256sum rates.csv` and `stat -c %s rates.csv`, then post `{"title": "Run", "text": "Rates attached.", "author": "Dr. Maya Okafor", "attachments": [{"name": "rates.csv", "sha256": "<hash>", "bytes": <size>, "kind": "instrument", "instrument": {"name": "Plate reader"}}]}` to `/notebook/books/$N/entries`.
6. With the model: `jq -Rs '{question: "Summarise these rates and flag any outlier.", requested_by: "Dr. Maya Okafor", of: [1], data: [{name: "rates.csv", text: .}]}' rates.csv | curl -s -XPOST localhost:8445/notebook/books/$N/analysis -H "authorization: Bearer $T" -H 'content-type: application/json' -d @- | jq '{status: .receipt.status, text}'`.
   Expect status `attested` and an analysis that names well F7.
7. Amend entry 1 with a reason (`/amend`), have Dr. Tomas Reyes witness the amendment (`/sign`, `{"n": 3, "meaning": "witnessed", "signer": "Dr. Tomas Reyes"}`),
   and `POST /notebook/books/$N/timestamp` `{}` (expect `gen_time` from FreeTSA).
8. `curl -s localhost:8445/notebook/books/$N/export -H "authorization: Bearer $T" > export.json` and
   `jq '{record: .}' export.json | curl -s -XPOST localhost:8445/notebook/verify -H 'content-type: application/json' -d @- | jq '{ok, summary}'` must be ok.
   Change one digit in the rates inside the analysis entry's prompt and verify again: it must fail at that entry.
9. `GET /notebook/books/$N/audit.csv` for the inspector view. Tell me the verify summary and the analysis.

## 5. Point our tools and site at it
- Instrument scripts and our ELN call the API with the `dk_` key: entries with file hashes, analyses with the data
  text. Contract: `API_CONTRACT.md`, section "Signed lab notebook".
- Personal keys: each signer enrols an Ed25519 public key as a member (`pubkey`) and signs the statement in
  `/notebook/info`; the site's console does this in the browser.
- The Decosa site's console and `/notebook/verify` work against this box with `NEXT_PUBLIC_DECOSA_API=http://127.0.0.1:8445`.
  The verify page runs entirely in the browser, so an inspector can check an export without reaching this box.

Off by default. Joining serves other people's requests on this GPU; never do it on a box that holds unpublished 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…

4 laws, rules and guidance pages cited; 4 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 tamper-evident lab notebook that shows which conclusions an AI model helped with, and lets an inspector check it without trusting you.
Who it's for
Teams in science and research and compliance and trust.
Where it runs
Hosted for synthetic or public data; self-host for unpublished results
Key numbers
  • 300 / 300 Genuine synthetic exports that verify (synthetic, n = 300)
  • 1,400 / 1,400 Outsider alterations caught (editing the export without keys) (synthetic, n = 1400)
  • 515 of 520 Insider alterations caught, personal keys + TSA, export alone (synthetic, n = 520)
All results, datasets and caveats
Models
Qwen3.8-27B (AI analyses)
Where
Hosted for synthetic or public data; self-host for unpublished results
Checks
Receipt per AI analysis; signed hash chain, personal e-signatures, RFC 3161 timestamps
Output
Signed record or verdict · Structured data
Data
Confidential business data
Hardware
1× 96 GB GPU
Licence
Permissive (Apache-2.0, MIT)
Built from
Signed record

Questions people ask

Does this make my lab Part 11 compliant?

No. It supports the audit-trail (11.10(e)), signature-manifestation (11.50) and signature/record-linking (11.70) requirements. Validation, written procedures, training, access control and two-component sign-in are yours to provide; software alone does not make anyone compliant.

How is an AI analysis recorded?

The exact prompt, the hash of every data file the model saw (which must match a file already attached), the model and its signed receipt go on the record. The analysis is receipted, not graded: a person must still check it.

Can someone change an entry without it showing?

On synthetic notebooks all 1,400 alterations by someone editing the export without keys were caught, naming the entry. An insider holding the server key was caught on the export alone in 515 of 520 cases when signers used personal keys and TSA timestamps; with account signatures only, keep export copies.

Do my instrument files leave the lab?

Files are hashed in your browser, so only their SHA-256 is recorded. Self-hosted, only a 32-byte digest of the chain head goes to the Time-Stamp Authority.

Is it a replacement for a full ELN?

No. It is a signing and provenance layer with a small notebook and an API; it has no templates, inventory, registry or validated GxP package.

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

Ask about Signed lab notebook

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.