folio export
folio export datapackage <SHEET> [--out <path>] [--stdout]folio export claude-skills <SHEET> [--out <dir>]datapackage
folio export datapackage <SHEET> [--out <path>] [--stdout]Generates a Frictionless v1 Data Package descriptor
(datapackage.json) that describes the sheet’s contract and points at
records.jsonl. External readers — frictionless validate,
datacontract-cli, dbt-style data-contract tooling — can pick the file up
without bespoke glue.
Default
$ folio export datapackage ./customerswrote datapackage.json (4 fields)
$ ls customers/contract.yaml datapackage.json derivations/ provenance.jsonl records.jsonl scripts/By default the descriptor is written to <SHEET>/datapackage.json.
Pipe to stdout
folio export datapackage ./customers --stdout > /tmp/customers.dp.jsonUseful when you want to commit the descriptor outside the sheet, or pipe
to frictionless validate directly.
What’s in the descriptor
{ "name": "example-customers", "title": "customers", "version": "1.0.0", "description": "...", "resources": [ { "name": "items", "path": "records.jsonl", "format": "jsonl", "profile": "tabular-data-resource", "schema": { "primaryKey": "id", "fields": [ {"name": "id", "type": "string", "constraints": {"required": true}}, {"name": "country_code", "type": "string", "folioDerived": true}, ... ] } } ]}| Folio field | Frictionless field |
|---|---|
id | top-level name |
name | top-level title |
version | top-level version |
description | top-level description (if set) |
schema[0].name | resources[0].name |
properties[].logicalType | fields[].type (mapped) |
properties[].required: true | fields[].constraints.required: true |
properties[].x-derived: true | fields[].folioDerived: true (custom extension key) |
logicalType mapping (§14.2 of the design overview):
| Folio | Frictionless |
|---|---|
string | string |
integer | integer |
number | number |
boolean | boolean |
date | date |
timestamp | datetime |
array | array |
object | object |
What’s not in the descriptor
- The contract’s
derivations/are not surfaced (Frictionless has no matching concept). x-editable-bypatterns are not surfaced (also Folio-specific).- Provenance is not surfaced (it’s not part of the data — it’s about the data).
The descriptor is therefore a lossy projection. It’s enough to make a Frictionless-aware tool read the rows; it isn’t enough to reconstruct the sheet from scratch.
Validate the export
pip install frictionlessfolio export datapackage ./customersfrictionless validate ./customers/datapackage.jsonfrictionless is not a Folio dependency — install it explicitly when you
need it.
claude-skills
folio export claude-skills <SHEET> [--out <dir>]Emits one Claude Code-compatible SKILL.md directory per entry in
<SHEET>/skills/. Default output dir is .claude/skills/ (relative
to the current working directory). The Claude frontmatter
(name, description) is mapped 1:1; Folio-specific metadata
(audience, tools, allowed_actors, arguments) drops to a
“Constraints” section in the body.
$ folio export claude-skills ./examples/onboarding --out /tmp/claudewrote 1 SKILL.md file(s) under /tmp/claude/ /tmp/claude/example-onboarding__advance-onboarding/SKILL.mdThe output is derived, read-only: re-run the export whenever
you change a skill. The sheet’s skills/ directory remains the
source of truth.
This sub-command pairs with the
folio-agent-skills
npm package: the npm pack ships Folio’s product-level skills, while
folio export claude-skills projects a sheet’s domain skills into
the same Claude Code shape.
Future formats
folio export is namespaced by format (datapackage, claude-skills,
<whatever>). The
design doc §14.2
mentions OpenAPI surfaces and dbt models as future candidates; neither is
implemented.