Folio quickstart
Create a working Folio sheet (a directory containing contract.yaml
and records.jsonl) from a description of what data the user wants
to collect. Hand it back so other Folio skills (derivations,
materialize) can build on it.
When this skill applies
- The user asks to "make a Folio sheet" / "set up Folio" / "build a
data contract".
- The user has a CSV / JSON file and wants a typed, AI-friendly
container for it.
- The user is starting a new entity collection (customers, research
notes, support tickets, etc.) and wants the sheet to be the system
of record.
This skill does not apply when the user already has a sheet and
wants to add a derivation, run materialize, or query — see the other
add-derivation-* and debug-* skills.
Prerequisites
Procedure
Pick the slug. Ask the user for a stable slug (kebab- or
snake_case ASCII). Use it as both the directory name and the
contract id. Example: customers, research-notes,
onboarding-queue.
Identify the primary key. A Folio sheet must have exactly
one primaryKey: true property. Composite keys are not allowed.
When the data has no obvious key, generate one (<slug>_<NNN>).
Identify required fields. Anything the row cannot exist
without. Mark them required: true.
Pick logicalType per field. The eight valid values are:
string, integer, number, boolean, date, timestamp,
array, object. Default to string when unsure.
Write contract.yaml at the sheet root. Skeleton:
apiVersion: v3.0.0
kind: DataContract
id: customers
name: customers
version: 1.0.0
description: A customer master.
schema:
- name: items
physicalType: jsonl
properties:
- name: id
logicalType: string
primaryKey: true
required: true
- name: company_name
logicalType: string
required: true
- name: country
logicalType: string
Write records.jsonl with one JSON object per line, no
enclosing array. Every record must include the primary key.
Skeleton:
{"id": "cust_001", "company_name": "Acme", "country": "Japan"}
{"id": "cust_002", "company_name": "DataFlow", "country": "United States"}
Validate. Always run folio validate <sheet> before handing
the sheet back. Fix every error.
Verify
folio validate <sheet>
folio list <sheet> --limit 3
Both should exit 0 and the second should print the records you
just wrote.
What to do next
- For a derived field that an LLM fills, use the
add-derivation-ai
skill.
- For a 1:1 join to another sheet, use
add-derivation-cross-sheet.
- For per-field write-permissions, set
x-editable-by (an array of
fnmatch patterns matched against the actor on every write).
- For external consumers, ship the sheet as a tarball — caches and
per-sheet venvs live outside the directory and don't need to be
bundled.
Common mistakes (don't make them)
- Two
primaryKey: true properties. folio validate rejects.
Pick one.
logicalType outside the eight allowed values (e.g. text,
int, datetime). Map to the closest from the list.
- Forgetting
apiVersion: v3.0.0 or kind: DataContract. Both
are required and pinned.
- Putting the cache or venv inside the sheet. Folio's cache
lives at
<user-cache>/folio/<id>/cache/ by design — do not
commit .folio-cache/ directories.
1---2name: folio-quickstart3description: Bootstrap a new Folio sheet from scratch — the contract.yaml schema, records.jsonl format, and the first materialize loop. Invoke when the user wants to start a Folio sheet, asks "how do I create a Folio data set", or has only data and needs a typed Folio container for it.4---56# Folio quickstart78Create a working Folio sheet (a directory containing `contract.yaml`9and `records.jsonl`) from a description of what data the user wants10to collect. Hand it back so other Folio skills (derivations,11materialize) can build on it.1213## When this skill applies1415- The user asks to "make a Folio sheet" / "set up Folio" / "build a16 data contract".17- The user has a CSV / JSON file and wants a typed, AI-friendly18 container for it.19- The user is starting a new entity collection (customers, research20 notes, support tickets, etc.) and wants the sheet to be the system21 of record.2223This skill does **not** apply when the user already has a sheet and24wants to add a derivation, run materialize, or query — see the other25`add-derivation-*` and `debug-*` skills.2627## Prerequisites2829- `folio` Python CLI is installed:30 ```31 pipx install folio-kit # or: uv tool install folio-kit32 ```33 (PyPI distribution name is `folio-kit`; the binary on disk is `folio`.)34 Verify with `folio --help`. If the user is on macOS Apple Silicon35 and `folio --help` errors with ENOENT, they may need to add36 `~/.local/bin` to PATH.3738## Procedure39401. **Pick the slug.** Ask the user for a stable slug (kebab- or41 snake_case ASCII). Use it as both the directory name and the42 contract `id`. Example: `customers`, `research-notes`,43 `onboarding-queue`.44452. **Identify the primary key.** A Folio sheet must have *exactly46 one* `primaryKey: true` property. Composite keys are not allowed.47 When the data has no obvious key, generate one (`<slug>_<NNN>`).48493. **Identify required fields.** Anything the row cannot exist50 without. Mark them `required: true`.51524. **Pick `logicalType` per field.** The eight valid values are:53 `string`, `integer`, `number`, `boolean`, `date`, `timestamp`,54 `array`, `object`. Default to `string` when unsure.55565. **Write `contract.yaml`** at the sheet root. Skeleton:5758 ```yaml59 apiVersion: v3.0.060 kind: DataContract61 id: customers62 name: customers63 version: 1.0.064 description: A customer master.65 schema:66 - name: items67 physicalType: jsonl68 properties:69 - name: id70 logicalType: string71 primaryKey: true72 required: true73 - name: company_name74 logicalType: string75 required: true76 - name: country77 logicalType: string78 ```79806. **Write `records.jsonl`** with one JSON object per line, no81 enclosing array. Every record must include the primary key.82 Skeleton:8384 ```jsonl85 {"id": "cust_001", "company_name": "Acme", "country": "Japan"}86 {"id": "cust_002", "company_name": "DataFlow", "country": "United States"}87 ```88897. **Validate.** Always run `folio validate <sheet>` before handing90 the sheet back. Fix every error.9192## Verify9394```bash95folio validate <sheet>96folio list <sheet> --limit 397```9899Both should exit 0 and the second should print the records you100just wrote.101102## What to do next103104- For a derived field that an LLM fills, use the `add-derivation-ai`105 skill.106- For a 1:1 join to another sheet, use `add-derivation-cross-sheet`.107- For per-field write-permissions, set `x-editable-by` (an array of108 `fnmatch` patterns matched against the actor on every write).109- For external consumers, ship the sheet as a tarball — caches and110 per-sheet venvs live outside the directory and don't need to be111 bundled.112113## Common mistakes (don't make them)114115- **Two `primaryKey: true` properties.** `folio validate` rejects.116 Pick one.117- **`logicalType` outside the eight allowed values** (e.g. `text`,118 `int`, `datetime`). Map to the closest from the list.119- **Forgetting `apiVersion: v3.0.0`** or `kind: DataContract`. Both120 are required and pinned.121- **Putting the cache or venv inside the sheet.** Folio's cache122 lives at `<user-cache>/folio/<id>/cache/` by design — do not123 commit `.folio-cache/` directories.