# Playbook import files

Drop playbook `.json` files here, then load them into a **running** Synapse-Cortex
instance from **Admin → Playbooks → Import from File** — no container restart, no
rebuild. The browser reads the file and uploads it to the running API, so this
works identically whether Cortex runs in Docker or locally.

## File format

A file may hold **one** playbook object, **an array** of them, or a
`{ "playbooks": [ ... ] }` wrapper — the importer accepts all three. Each
playbook has exactly these fields (the same shape the **Export** button on a
playbook row produces, so an exported file re-imports as-is):

| Field | Type | Notes |
|---|---|---|
| `name` | string | Unique within the tenant. A name clash on import is **skipped** (never overwrites an existing playbook). |
| `enabled` | boolean | Whether the AI investigator may select it. |
| `graph_json` | object | `{ "nodes": [...], "edges": [...] }` — validated server-side on import (no Start node / unreachable command / cycle → reported as an error, that item is not created). |
| `allowed_target_os` | string[] | e.g. `["linux"]`. Empty = any OS. |
| `required_approval_level` | string | `"human_in_the_loop"` (default) or `"auto_approve"` (only importable by a global admin on a deployment with `ALLOW_AUTO_APPROVE=true`, otherwise reported as an error). |
| `forbidden_commands` | string[] | Tenant-specific blocked substrings, checked in addition to the non-overridable baseline. |
| `acknowledged_dangerous_commands` | string[] | Optional. Review-eligible baseline categories (currently only `"host_power"` → reboot/shutdown/halt/poweroff) this playbook may run **behind mandatory human review** instead of being auto-blocked. **Only importable by a `global_admin`** — otherwise reported as an error. An acknowledged run is never auto-approved. Catastrophic patterns (`rm -rf`, `mkfs`, `dd of=/dev/…`) can never be acknowledged. |

### Graph nodes

- **Start** — exactly one, `{"id": "start", "type": "start", "data": {}}`.
- **Command** — `{"id": "...", "type": "command", "data": {"label": "...", "command": "..."}}`.
  Commands may use the ticket placeholders `{{username}}`, `{{ip_address}}`,
  and `{{password}}`, resolved per-ticket at run time.
- **Condition** — `{"id": "...", "type": "condition", "data": {"label": "...", "expression": "..."}}`,
  with two outgoing edges whose `sourceHandle` is `"true"` / `"false"`.
  Execution always follows the `true` branch (the expression is documentation).

Edges: `{"id": "...", "source": "<node id>", "target": "<node id>", "sourceHandle": null }`.

## Import behaviour

- **Name clash** → skipped and reported (an existing playbook is never clobbered;
  rename in the file, or delete the existing one first, to re-import).
- **Invalid graph** or a disallowed `auto_approve` → that item is reported as an
  error and not created; the rest of the file still imports.
- Everything valid and new → created immediately in the running database.

## What's in this folder

Every playbook from the app's built-in **Template Catalogue** (36 Ubuntu/Debian
+ 10 Windows + 11 Docker + 14 Proxmox + 1 General) is exported here as an
individual `.json` file, so the
whole set is importable into any instance. `check-ssh-authentication-ubuntu-debian.json`
is a good complete example to read first, and the `docker-*.json` files cover
common container operations (restart, prune, compose, log/diagnostics, plus a
"locate a container's Compose project" discovery step). Import one at a time from
**Admin → Playbooks → Import from File**, and edit any of them freely in the
visual builder after importing — a template is only ever a starting point.

**Docker & container locations:** the container-level docker playbooks address
containers by name via the daemon, so they work from any directory. The Compose
playbooks **auto-locate** the project directory at run time from the container's
own Compose labels (and the update playbook also auto-derives the service name),
so no folder is ever hand-entered — you only supply the container name, and the
AI's proposed fix runs end to end with no human pointing it at a directory.
`docker-locate-a-container-s-compose-project-files.json` remains available as a
read-only diagnostic when you want to see a container's project directory and
compose-file path yourself.

**Command runner (`run-an-ai-suggested-command-review-required.json`):** the one
playbook whose command is the `{{command}}` token, supplied at run time — the AI
proposes the exact command for the ticket, a human reviews/edits it on the
approval card, and it runs only after an explicit approval. The proposed/edited
command still passes the full guardrail engine (the non-overridable
forbidden-command baseline blocks `rm -rf`, `mkfs`, `shutdown`, etc.). It can
**only be imported/created by a `global_admin`** and can never be Auto-Approve —
importing a `.json` containing `{{command}}` as a non-global-admin is reported as
an error.

These files are generated from `frontend/src/playbook/templates.ts` (the single
source of truth), so they stay identical to what the in-app catalogue shows.
