Skip to content

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

Terminal window
$ folio export datapackage ./customers
wrote 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

Terminal window
folio export datapackage ./customers --stdout > /tmp/customers.dp.json

Useful 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 fieldFrictionless field
idtop-level name
nametop-level title
versiontop-level version
descriptiontop-level description (if set)
schema[0].nameresources[0].name
properties[].logicalTypefields[].type (mapped)
properties[].required: truefields[].constraints.required: true
properties[].x-derived: truefields[].folioDerived: true (custom extension key)

logicalType mapping (§14.2 of the design overview):

FolioFrictionless
stringstring
integerinteger
numbernumber
booleanboolean
datedate
timestampdatetime
arrayarray
objectobject

What’s not in the descriptor

  • The contract’s derivations/ are not surfaced (Frictionless has no matching concept).
  • x-editable-by patterns 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

Terminal window
pip install frictionless
folio export datapackage ./customers
frictionless validate ./customers/datapackage.json

frictionless 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.

Terminal window
$ folio export claude-skills ./examples/onboarding --out /tmp/claude
wrote 1 SKILL.md file(s) under /tmp/claude/
/tmp/claude/example-onboarding__advance-onboarding/SKILL.md

The 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.