Files on disk
Red Clippy keeps two things outside the process: a SQLite database and a storage directory. Everything else is in the binary.
The database
The database is red-clippy.db in the working directory by default, or
wherever database_url points.
SQLite runs in WAL mode, so you will see three files:
red-clippy.db
red-clippy.db-wal
red-clippy.db-shm
All three belong together. Copying only the .db while the server is running
gives you a database missing the most recent writes.
The storage directory
The storage directory is ./red-clippy-storage by default, or wherever
storage_root points. It is created at startup if missing.
red-clippy-storage/
org_northwind/
pentest_PT-2026-Q3-NORTHWIND/
findings/
2/
9a9344b81c8e1bfb44740ab09b23d933
aa26c30965cbc9533cf47261680b8c4e
data/
notes/checkout-flow.md
scans/northwind-perimeter.xml
scans/subfinder-northwind.txt
screenshots/evidence.png
Each engagement has two buckets, and they name files differently.
findings/<finding_id>/ holds evidence attachments. Names are
server-generated random hex, so the original filename never touches disk and a
storage key lifted from an old database dump cannot be replayed against a
running server. The real filename, MIME type and caption live in the database.
data/ is the operator file area, the one behind the Files tab. It keeps
the names you gave things, so the Files tab is a faithful view of what is on
disk. Every path segment is validated, and nothing user-supplied can resolve
outside the engagement’s own data/ root.
Asset file areas are a slice of the same data/ tree, so a file written
through an asset’s Files tab is visible from the engagement’s Files tab too.
Backing up
With the server stopped, copy the database file (all three parts) and the storage directory. That is the whole state.
With the server running, use SQLite’s own backup so you get a consistent snapshot:
sqlite3 red-clippy.db ".backup 'backup/red-clippy.db'"
cp -a red-clippy-storage backup/
Deletion behaviour
Deleting a record and deleting its files are deliberately separate actions.
Deleting an organization in the panel removes every database row inside it and
leaves the files under org_<slug>/ alone. Deleting an asset removes its
observations and check results but keeps findings tagged against it.
In both cases a destructive action removes the index, not the artefacts. If you want the files gone, remove the directory yourself.
Path derivation
org_<slug> and pentest_<code> are derived from the slug and the code, which
is why both are immutable after creation. Both are re-validated every time a
path is built, so even a tampered database row cannot produce a path that
escapes the storage root.
This means one engagement’s artefacts are one directory. Archiving an
engagement is tar czf. Handing over a client’s files is copying
org_<slug>/.