File-Backed Data
Files are still a good local-first storage layer when users benefit from direct inspection, portability, or simple recovery.
workspace/
manifest.json
notes/
2026-07-19.md
transcripts/
session-01.jsonl
attachments/
receipt-001.jpg
indexes/
search.sqlite
File Patterns
| Pattern | Use for | Watch out for |
|---|---|---|
| JSON | small configs and snapshots | whole-file rewrites and merge conflicts |
| JSONL | append-only logs, transcripts, audit events | partial lines after crash |
| Markdown | user-owned knowledge and notes | weak schema, slower structured queries |
| Attachment folders | images, PDFs, audio, large blobs | orphan files and missing metadata |
| SQLite index | derived search or metadata over files | keep rebuildable from source files |
Atomic Write Pattern
Write to a temp file in the same directory, flush it, then rename over the old file.
import { rename, writeFile } from "node:fs/promises";
export async function writeJsonAtomic(path: string, value: unknown) {
const tmp = `${path}.tmp`;
await writeFile(tmp, `${JSON.stringify(value, null, 2)}\n`, "utf8");
await rename(tmp, path);
}
This is not a full substitute for database transactions, but it avoids many torn-write failures for small files.
Manifest Rule
Use a manifest when files belong together:
{
"formatVersion": 3,
"createdAt": "2026-07-19T10:00:00Z",
"attachments": [
{ "id": "receipt-001", "path": "attachments/receipt-001.jpg", "sha256": "..." }
]
}
Validate the manifest before import. Refuse partial imports unless the product has a clear recovery mode.