Databases begin with a ceremony: someone designs the table. Columns are named, types are chosen, and only then may data arrive. Every serious record-keeping tool inherits some version of that ceremony — the import wizard, the column-mapping dialog, the "create your first table" screen — and for personal data the ceremony is precisely where the whole enterprise dies. Nobody designs a schema for their own life. People paste a list of contacts into a chat, hand over three months of bank statements, mention one more expense on a Tuesday. The data is real, repeatable, and table-shaped — and it arrives as prose.
Which leaves an assistant with a bad pair of options. Treat the prose as prose, and something quietly repeatable dissolves at the end of every turn: the same statement gets fuzzily re-parsed next month, nothing can be appended to, sorted, totalled or charted, and "what did I spend on travel?" is answered by a model squinting at text it has read four times before. Or force the ceremony — put a table designer inside a conversational product — and violate the product's entire grammar, which is that you configure things by talking about them. The way out is the thesis of this entry: the schema is inferred at the moment the data lands, and structure is offered, never imposed.
Recognise and offer
The behaviour is a courtesy before it is a mechanism. When something table-shaped appears — pasted rows, a produced list, a file that is obviously an export — the assistant offers to keep it as a tracked dataset, and materialises nothing until the user says yes. A paste answered with a silent database write would be presumptuous; one answered with only a prose summary wastes the shape the data arrived in. The offer sits exactly between, and declining it costs nothing.
On assent, the inference machinery earns its keep. Delimited text is sniffed for its separator, parsed quote-aware, and each column's type inferred from what the values actually are — dates that behave as dates, amounts that sum. Clean files structure themselves in one pass; only genuine ambiguity comes back as a question, with the detected shape and sample rows shown for a one-tap confirmation. And before any ad-hoc schema is invented, a catalogue of canonical templates is consulted for recognised kinds — "start tracking my bank statement" yields date, description, category, amount, balance, the columns a bank statement has always had, not four creatively-named inventions that will differ from next month's four. Inference handles the novel; convention handles the known; the user handles neither.
One copy of the truth, wearing a friendly face
A kept dataset is stored as a pair addressed by one base path: an NDJSON file — one JSON row per line, the append-safe source of truth and the only place rows live — and a lightweight view document carrying the typed schema. The user is not meant to meet the pair: the view is what search indexes, never the raw row file, and the next build hides the row file from every listing so a dataset reads as one thing with one name. The two-file split is a storage decision, and storage decisions are not user-facing concepts.
The shape buys the property everything downstream leans on: appends never restart. "Add one more" appends a line to the same file — no new file, no duplicate dataset, no whole-file rewrite by a model that might race itself or mangle rows it wasn't touching. All mutation flows through a small deterministic tool family — define, append, upsert, read, import — so the record operations are code, and the model's job is deciding what to record, never reconstructing a file around it. Structured questions are then answered from the rows: filter, sort, aggregate — real operations over real values, not a fresh act of reading comprehension over remembered prose.
What already belongs to someone else
One behavioural rule guards the whole design against its own enthusiasm: don't fork connector-owned data. If a connected service already owns the records — contacts in a mailbox, deals in a CRM, workouts in a fitness service — then "keep a list of my contacts" must not quietly copy them into a dataset that will begin drifting from its source the moment it is created. The assistant binds live to the owner, or, when a frozen copy is genuinely what's wanted, creates one explicitly labelled as a point-in-time snapshot. A silent fork presented as truth is the worst artifact a data feature can produce, because it is wrong in a way that compounds: every chart built on it inherits the drift, wearing the confidence of structure.
The payoff for all this discipline lands in dashboards. Before datasets, a dashboard's refresh re-ran an agent gathering turn — a model invocation per refresh: token-billed, slow, and non-deterministic, capable of producing a slightly different dashboard from the same facts. A dashboard bound to a dataset refreshes by re-reading a file and re-applying a small declarative transform — group, sum, count, top-N — instantly, deterministically, for nothing. Six structural patterns cover what personal tabular data actually turns out to be — a ledger, a status tracker, a time series, an entity list, a catalogue, a key-value snapshot — and each maps to its natural widgets, so "put a chart on this" is a transform selection, not a creative act.
What transfers
For anyone building structure into a conversational product: put the schema step after the data, not before it — infer from what landed, offer rather than impose, and reserve the questions for genuine ambiguity. Keep exactly one copy of the rows and make every view a rendering of it. Give mutation a deterministic tool surface so the model decides content while code performs operations. Key your imports so refreshing data merges rather than multiplies. And respect prior ownership — the moment your structured copy of someone else's live data starts looking like the truth, it has started being a lie.
Postscript, August 2026. Three later chapters, each extending the same spine. The view document lost its last data-bearing duty within a day of this entry's date: an edit incident left a rendered table diverged from its row file, and the view was made schema-only — tables now render dynamically from the rows everywhere they appear, the row file dropped out of the tree, folder counts and search, and reading either half renders the same live table — deleting the drift class at the root rather than patching the editor that exposed it; the second copy of anything, we keep re-learning, is a liability wearing a convenience. Relations arrived, deliberately modest: a record can reference a record in another dataset, filters can follow one hop of that reference, writes can pass through it — and integrity violations warn rather than block or cascade, because the triggers that would justify a real multi-hop record store are named in the spec and have not fired. And provenance went cellular for research data: a value can carry its source, confidence and confirmation state, so a figure gathered from desk research graduates to confirmed on a call without its row being rewritten — a table where every cell can answer "says who?", which is what a table built from the world, rather than from a form, turns out to need. Aggregation grew methods beyond summing for the same reason: four mild days should not outrank one unbearable one, and a median tells that truth where a sum buries it.