Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Define a dataset's metadata profile — infer a Frictionless Table Schema from its data, add Data Package metadata (license, sources, keywords), and write it into datasets.json so the showcase renders a typed field table. Extend or customize via the L0-L3 profile ladder. Use when a registered dataset needs field types, constraints, or catalog metadata before publishing.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-12 | ✗→✓ | ▲ Improved | 14% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 1552% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 60% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 51% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 61% | 0% |
Define a dataset's metadata profile — the authoring skill for the metadata-profile contract (lib/metadata). Where portaljs-add-dataset registers that a dataset exists, this skill describes what its data means: infer a Frictionless Table Schema (fields, types, constraints) from sampled data, add the Data Package fields a catalog surfaces (title, licenses, sources, keywords), and write them onto the dataset's entry in datasets.json. The showcase at /@<namespace>/<slug> then renders a typed field table instead of a bare preview. The model is Frictionless-native; DCAT is a serialization layer built on top later, not authored here.
The skill runs on a profile ladder — reach for higher levels only when needed:
| Level | What it is | When | | --- | --- | --- | | L0 | Default frictionless-tabular profile; declare schema + metadata. | Default. Standard tabular CSV/TSV. | | L1 | L0 plus extra descriptive package fields. | Extra metadata, standard validation is fine. | | L2 | Fully custom profile (own schema template + validate()). | A dataset type needing custom validation rules. | | L3 | Multiple registered profiles, resolved per dataset. | A portal mixing dataset types. |
The skill is interactive and never dead-ends: if input is thin it interviews in short rounds, infers defaults from the data, echoes the schema for confirmation, and accepts "use defaults" to proceed with the inferred schema as-is.
lib/metadata/types.ts,pages/[owner]/[slug].tsx); see portaljs-new-portal.
datasets.json (see portaljs-add-dataset).PORTAL_DIR/public/data/. JSON/GeoJSON datasets get package metadata only — no fields.
tsx optional, used for the schema-validation check.The canonical, full step-by-step workflow is .claude/commands/portaljs-define-schema.md — the single source of truth. Read and follow it when executing. Summary:
PORTAL_DIR, DATASET (slug or namespace/slug), and LEVEL (default L0)from input; if DATASET is missing, list the portal's slugs and ask.
datasets.json, lib/metadata/types.ts,the showcase route); proceed anyway if lib/metadata/ predates the contract.
public/data/<file> and infereach field's type, constraints (required, unique, pattern), and a primary key.
warranted.
datasets.json in place,preserving all other fields; for L2/L3, scaffold and register a custom profile module.
validate().npx next build; fix malformed JSON or an invalid FieldType beforereporting success.
datasets.json (target entry gains profile, schema, licenses,sources, keywords, version — unset fields omitted).
lib/metadata/<profile-id>.ts; lib/metadata/registry.tsupdated with a registerProfile(...) call.
npx next build succeeds./@<namespace>/<slug> renders a typed field table in place of a bare preview.| Symptom | Cause | Fix | | --- | --- | --- | | Dataset not found in datasets.json | Wrong slug or missing namespace/ prefix | List available slugs and re-prompt. | | lib/metadata/ missing | Portal predates the metadata-profile contract | Proceed anyway — schema fields are optional and ignored by older showcases. | | No fields schema produced | Dataset is JSON/GeoJSON, not tabular | Expected — capture Data Package metadata only. | | Validation reports type errors | Sampled values don't coerce to the inferred type | Relax the type or drop the offending required/pattern constraint. | | next build fails on datasets.json | Stray comma or a type outside FieldType | Fix the JSON/type and rebuild before reporting success. |
/portaljs-define-schema population-2022Infers fields (e.g. country: string, population: integer), drafts titles, asks for a license and source, and writes the schema under the default frictionless-tabular profile.
/portaljs-define-schema neighborhoods-geoGeoJSON has no tabular fields; the skill captures license, sources, and keywords onto the entry and skips schema inference.
/portaljs-define-schema co2-emissions level=L2Scaffolds lib/metadata/co2-emissions-profile.ts with a custom validate(), registers it in lib/metadata/registry.ts, and sets "profile": "co2-emissions-profile" on the entry.
.claude/commands/portaljs-define-schema.mdreferences/reference.mdportaljs-add-dataset, portaljs-add-dcat, portaljs-check-data-qualityOther measured skills in the registry, with their headline benchmark lift.