Data and storage
When you work inside a Karsa project and a task produces something — a file, a table, a memo — that output has a home. The project root is never it. This page is the rule for where data goes by shape, and the Karsa HTTP API conventions you use to put it there. If you are an agent, read this before you save anything: dropping loose files at $PROJECT_HOME is the single most common way to make work that Karsa can't see, browse, or manage.
The one rule: route data by its shape
Every artifact a task produces has a shape, and each shape has a home that makes it a first-class, browsable record instead of loose bytes on disk:
- A file — a CSV, PDF, image, dataset, export, anything you'd hand someone as a file → upload it as an asset. It lands under
karsa/<project>/artifact/file/as a record the UI can list and preview, not stray bytes the daemon can't see. - Tabular data you'd filter, sort, join, or aggregate → the project's Karsa SQL DB (
karsa/<project>/sqldb/default.db), not a stray spreadsheet on disk. To make a table browsable in the UI, put a collection over it. - Prose — a memo, notes, a writeup, a report → a markdown document in a docdb collection under
artifact/, not a loose.mdat the project root.
If you are unsure where something belongs, ask. But the project root is never the answer — a file written there is invisible to Karsa, unversioned as a record, and lost to every view the user has.
The Karsa HTTP API: conventions first
The daemon exposes a local HTTP API, and the active project is already baked into one environment variable.
- Always use
$KARSA_API_BASE. It encodes the daemon host and the active project — every call you make through it operates on this project. Build every request as${KARSA_API_BASE}/<path>. - Never hard-code
/api/...paths or a host. Don't writehttp://localhost:3100/api/...or assume a path prefix.$KARSA_API_BASEis the only base you need; hard-coding anything else will hit the wrong project or no project at all. - You're already cwd'd into the project. Your working directory is
$PROJECT_HOME, so filesystem tools act on the real project tree — but records (assets, rows, docs) are created through the API, not by writing files intoartifact/by hand.
Everything below is a specific application of these two ideas: use $KARSA_API_BASE, and let the API create the record.
Titling the chat
Once the user's intent is clear, give the conversation a short title — a undefined-undefined word noun phrase:
PATCH ${KARSA_API_BASE}/chat/<chat_id>
{ "title": "Quarterly revenue cleanup" }
Do this once, early, when intent is clear. It's how the conversation becomes findable later.
Uploading a file (assets)
A file becomes a browsable asset record with a single multipart upload — field name file:
POST ${KARSA_API_BASE}/file (multipart/form-data, field: file)
The response is the asset record. The bytes land under karsa/<project>/artifact/file/, and the file shows up in the project's Files view. Use this for any genuine file: a generated CSV, a downloaded PDF, an image, a dataset export. Don't cp it into the project tree and hope — upload it, so it's a record.
Tabular data (sqldb + collections)
Tabular data goes into the project's Karsa SQL DB, and you make it browsable by laying a collection over the table.
undefined. Write your rows into a table in the project's SQL DB (karsa/<project>/sqldb/default.db). undefined. Create a collection that exposes the table in the UI:
POST ${KARSA_API_BASE}/collection
{
"slug": "invoices",
"source": "sqlite.row",
"sqlite": { "table": "invoices" },
"name": "Invoice",
"plural": "Invoices"
}
Now the table's rows are a typed, sortable, filterable collection in the project — not a spreadsheet nobody can find. It appears in the sidebar under Artifacts by default; pass "ui": { "group": "operate" } to place it elsewhere. This is also the path to "expand to the cloud later": data in the Karsa SQL DB is data on the seam Karsa controls (see Building a Karsa app).
Prose (docdb docs)
A memo, notes, a writeup, a report — anything document-shaped — goes into a docdb collection as a markdown document (YAML frontmatter for typed fields, a markdown body), under artifact/. Create the document through the API against ${KARSA_API_BASE} so it becomes a real resource in a collection, cross-linkable by id and rendered in the UI — not a loose .md at the project root that no view will ever surface.
Where to go next
When the task grows from organizing data into building software on top of it, read Building a Karsa app — the app, like the data, belongs inside the project, on the Karsa SDK. And if you ever feel the pull to write a file to the project root or reach for an outside database, read Anti-patterns first.