← The Karsa Manual

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:

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.

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.