portaljs-migrate
Skill2.4k starsChanged 12 days agoMITView on GitHub
Migrate (harvest) datasets between open-data platforms. Reads CKAN, a DCAT-US /data.json catalog (DKAN, ArcGIS Hub, data.gov), a DCAT / DCAT-AP RDF feed (JSON-LD, Turtle, or RDF/XML), Socrata, OpenDataSoft, or an ArcGIS FeatureServer, and writes them to a static PortalJS catalog or pushes them into a CKAN instance over its API. Use when moving datasets from an external open-data platform into a PortalJS portal, or bridging one CKAN instance to another.
- Reads credentials
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 1 is distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 60
Read the source into canonical dataset entries, per the source's field table in the reference doc, applying the metadata hygiene rules …
- Very specific: line 68
Write datasets.json (upsert or --replace), or push packages/resources into CKAN over its action API.
- Very specific: line 70
Verify — npm run build (static) or re-query package_search (CKAN).
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
PortalJS — Migrate
Overview
Harvest datasets from an external open-data platform into a PortalJS portal, or
push them into a CKAN instance. Every source reads into one canonical shape —
{ slug, namespace, name, description, resources[] } — then writes to the target
from that shape, so adding a source covers every target automatically.
Supported sources: CKAN, a DCAT-US /data.json catalog (DKAN, ArcGIS Hub,
data.gov), a DCAT / DCAT-AP RDF feed, Socrata, OpenDataSoft, or an ArcGIS
FeatureServer/MapServer. Supported targets: a static PortalJS catalog
(datasets.json, resources linked by URL or downloaded into Cloudflare R2) or a
CKAN instance over its write API.
This is the copy-into-the-portal path, the inverse of /portaljs-connect-ckan
(which reads the source live at build time): a one-time, re-runnable snapshot so
the portal stands alone and needs no backend.
Prerequisites
- An existing PortalJS portal for the static target:
datasets.json,package.json, andpages/[owner]/[slug].tsxmust exist (theportaljs-catalogtemplate). - Node 18+ and npm, with portal dependencies installed (
npm install). - Network access to the source platform's API or feed URL.
- For a CKAN target: a write API key in
CKAN_API_KEY— never hardcoded. - For
downloadcopy mode:git-lfsand a PortalJS Arc account (or a self-hosted Giftless endpoint) to push resource files to R2. - For
dcat-rdfsources:lib/metadata/dcat-harvest.tsanddcat-profiles.ts(copy fromexamples/portaljs-catalog/lib/metadata/if missing), run vianpx tsx.
Instructions
Full step-by-step workflow:
.claude/commands/portaljs-migrate.md.
- Gather input — source type, source URL, target (
static/ckan), portal directory, copy mode (link/download), filters. Interview instead of erroring. - Validate the target — confirm the static catalog files exist, or that the CKAN URL and API key authenticate.
- Detect the source type from the URL (or
--source) and verify reachability. - Read the source into canonical dataset entries, per the source's field table in
the reference doc, applying the metadata hygiene rules (license sentinel — never
fabricate CC-BY; description sanitizer + fallback chain; source dates preserved
with
migratedAtseparate;cleanTitledisplay-name cleanup with slugs from the raw title;categoryfrom a meaningful theme). - For a static target, resolve resource paths by copy mode:
linkkeeps source URLs;downloadcopies files into the repo under Git LFS, pushed to R2. - Print a dry-run preview; stop if
--dry-runwas passed. - Write
datasets.json(upsert or--replace), or push packages/resources into CKAN over its action API. - Verify —
npm run build(static) or re-querypackage_search(CKAN). - Report datasets migrated, namespaces touched, and next steps.
Output
Static target: an updated datasets.json (upserted on (namespace, slug)),
optionally with resource files in Git LFS served from Cloudflare R2, plus a
passing npm run build. CKAN target: created/updated packages and resources;
per-dataset failures are logged and skipped, not fatal.
Error Handling
| Symptom | Cause | Fix |
"not a portaljs-catalog template" | datasets.json missing | Confirm the portal directory, or run /portaljs-new-portal |
| CKAN target rejects every write (403) | Key missing, expired, or lacks org permission | Set a valid CKAN_API_KEY; stop rather than partially migrating |
| Source URL matches no known format | Auto-detection failed | Pass --source explicitly (ckan, dcat, dcat-rdf, socrata, ods, arcgis) |
| DCAT-RDF fetch returns HTML, not a feed | URL is a portal page, not the feed | Follow its <link rel="alternate"> href, or use the direct feed URL |
| Build fails after write | Malformed entry (missing slug/namespace/name) | Inspect /tmp/portaljs-migrate-build.log, fix, rebuild |
download mode push fails | git-lfs missing, or no Arc/Giftless token | Install git-lfs; mint a token via the Arc API or self-hosted Giftless |
| Duplicate datasets after re-running | --replace used unintentionally, or slug collisions | Omit --replace to upsert; keep slugs unique per namespace |
Examples
Example 1 — CKAN to static catalog, link mode
/portaljs-migrate --source ckan --source-url https://demo.dev.datopian.com \
--target static --portal-dir . --copy-mode linkUpserts all packages from the CKAN demo instance into datasets.json, referencing
source resource URLs directly.
Example 2 — data.gov DCAT-US catalog, downloaded into R2
/portaljs-migrate --source dcat --source-url https://catalog.data.gov/data.json \
--target static --copy-mode download --org-filter epa-govHarvests one publisher and copies every resource file into the repo under Git LFS, served from Cloudflare R2.
Example 3 — DCAT-AP RDF feed from a national portal
/portaljs-migrate --source dcat-rdf \
--source-url https://data.europa.eu/api/hub/search/catalog.jsonld \
--target static --dry-runFetches the JSON-LD feed through the RDF harvester and previews the canonical datasets without writing anything.
Example 4 — CKAN to CKAN (platform-to-platform)
/portaljs-migrate --source ckan --source-url https://old-portal.example.org \
--target ckan --target-url https://new-portal.example.org --owner-org researchPushes every package from the old CKAN instance into the new one, filed under
research.
Resources
- Command source:
.claude/commands/portaljs-migrate.md - Field mappings and troubleshooting:
references/reference.md - Related skills:
/portaljs-connect-ckan,/portaljs-add-dcat,/portaljs-check-data-quality,/portaljs-define-schema - CKAN Action API reference: https://docs.ckan.org/en/latest/api/
Trending
Steady: 0 new projects took it in the last 4 weeks, none the 4 weeks before.thin data
Who's talking about datopian/portaljs
- A Hacker News story“Show HN: PortalJS – AI-native, open-source framework for data portals”Hacker News · Jul 15, 2026 · 10 points
- fuma-nama/fumadocs“[feat] support obsidian style wikilinks, backlinks, embeds, graph view”GitHub · Mar 17, 2025 · 1 reactions
- sudosubin/agents.nix“claude-code-marketplaces.github.datopian.portaljs: init at 0-unstable-2026-10-27”GitHub · Oct 28, 2026
- sudosubin/agents.nix“agent-skills.github.datopian.portaljs: 0-unstable-2026-10-15 → 0-unstable-2026-10-20”GitHub · Oct 20, 2026
- sudosubin/agents.nix“agent-skills.github.datopian.portaljs: 0-unstable-2026-08-20 → 0-unstable-2026-10-15”GitHub · Oct 20, 2026
The biggest 5 of 38 mentions linking to the repository that our crawl found. Each line is their own headline.
See all 38
Talked about on GitHub and Hacker News (38 times).
On GitHub · 37
- Mar 17, 2025[feat] support obsidian style wikilinks, backlinks, embeds, graph view — fuma-nama/fumadocs1 reaction · 1 comment
- Oct 28, 2026claude-code-marketplaces.github.datopian.portaljs: init at 0-unstable-2026-10-27 — sudosubin/agents.nix0 reactions
- Oct 20, 2026agent-skills.github.datopian.portaljs: 0-unstable-2026-10-15 → 0-unstable-2026-10-20 — sudosubin/agents.nix0 reactions
- Oct 20, 2026agent-skills.github.datopian.portaljs: 0-unstable-2026-08-20 → 0-unstable-2026-10-15 — sudosubin/agents.nix0 reactions
- Oct 3, 2026agent-skills.github.datopian.portaljs: 1.4.0-unstable-2026-08-20 → 0-unstable-2026-08-20 — sudosubin/agents.nix0 reactions
32 more on GitHub
- Sep 30, 2026docs: fix typos and a stale CKAN example link — olitreadwell/portaljs0 reactions
- Sep 26, 2026agent-skills.github.datopian.portaljs: init at 1.4.0-unstable-2026-08-20 — sudosubin/agents.nix0 reactions
- Sep 26, 2026[Candidate] datopian/portaljs/skills/portaljs-add-dataset - portaljs-add-dataset — ProSkillsMD/proskills0 reactions · 2 comments
- Sep 26, 2026[Candidate] datopian/portaljs/skills/portaljs-add-chart - portaljs-add-chart — ProSkillsMD/proskills0 reactions · 2 comments
- Sep 26, 2026[Candidate] datopian/portaljs/skills/arcgis-to-portaljs - arcgis-to-portaljs — ProSkillsMD/proskills0 reactions · 1 comment
- Aug 12, 2026fix(ckan): make Pagination page buttons readable by screen readers — olitreadwell/portaljs0 reactions
- Aug 12, 2026fix(ckan-api-client-js): restore validation error fallback message — olitreadwell/portaljs0 reactions
- Aug 12, 2026fix(create-portaljs): make the scaffold template source repo-aware — olitreadwell/portaljs0 reactions
- Jul 8, 2026Add charts to the homepage — datopian/portaljs-research0 reactions · 2 comments
- Jul 7, 2026Add PortalJS plugin (datopian/portaljs) — tmcpa/claudedirectory0 reactions · 1 comment
- Jun 25, 2026Improve ui/ux — datopian/portaljs-research0 reactions · 2 comments
- Mar 24, 2026content: migrate two legacy Flowershow tutorials from portaljs.com — flowershow/flowershow0 reactions · 2 comments
- Dec 12, 2025Consolidate datahubio repos into datasets org — datasets/collective0 reactions
- Nov 21, 2025Added scope organization param into MCP URL to allow specific organizations — datopian/portaljs-mcp-server0 reactions · 2 comments
- Oct 29, 2025[BUG Fix] Pagination and table — datopian/portaljs-frontend-starter0 reactions · 2 comments
- Oct 19, 2025[BUG FIX] Frontend table preview — datopian/portaljs-frontend-starter0 reactions · 2 comments
- Oct 19, 2025[Bug Fix] Table Preview Frontend issues — datopian/portal-lcc0 reactions · 2 comments
- Oct 9, 2025preview data table tool — datopian/portaljs-mcp-server0 reactions · 1 comment
- Oct 7, 2025[IMPLEMENTING] Auth for portalJS key — datopian/portaljs-mcp-server0 reactions · 2 comments
- Sep 18, 2025Dataverse Harvester Implementation — datopian/harvesterjs0 reactions · 1 comment
- Jul 6, 2025Move all flowershow stuff from portaljs and add redirects — flowershow/flowershow0 reactions · 1 comment
- May 9, 2025Enable Iframe previews — datopian/portaljs-frontend-starter0 reactions · 2 comments
- Dec 28, 2023Transfer here "create a simple catalog of anything using markdown" — flowershow/wayofmarkdown0 reactions · 8 comments
- Dec 14, 2023Migrate content from portaljs.org/guide to this site — flowershow/wayofmarkdown0 reactions · 6 comments
- Oct 23, 2023[DO-NOT_MERGE] Improvement suggestions — flowershow/flowershow0 reactions · 1 comment
- Sep 20, 2023When I have a remote content e.g. https://github.com/datasets/awesome-data I want to load and render that (statically) so that i can author content in another repo but render it here — Valecia2023/caring.net0 reactions
- Jun 12, 2023Setup auto-publishing to npm — flowershow/markdowndb0 reactions
- May 26, 2023Turn this repo into core template and move core lib to portaljs repo — flowershow/flowershow0 reactions · 2 comments
- May 17, 202317 consolidate gitignore and expand its entries — hackforla/accessthedata-ckan0 reactions
- May 16, 2023[EPIC] Editor guide: how to contribute content and datasets — flowershow/wayofmarkdown0 reactions · 2 comments
- Apr 28, 2023[epic] MarkdownDB site (landing page) and "launch" — flowershow/markdowndb0 reactions · 6 comments
- Oct 30, 2022Analytics other than Google Analytics (and switch to pliny model) — flowershow/flowershow0 reactions · 2 comments
On Hacker News · 1
- Jul 15, 2026Show HN: PortalJS – AI-native, open-source framework for data portals10 points · 1 comment
In this repository16 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- site/CLAUDE.mdCLAUDE.md
- arcgis-to-portaljsSkill
- portaljs-add-chartSkill
- portaljs-add-datasetSkill
- portaljs-add-dcatSkill
- portaljs-add-geoSkill
- portaljs-add-mapSkill
- portaljs-add-resourceSkill
- portaljs-architectSkill
- portaljs-check-data-qualitySkill
- portaljs-connect-ckanSkill
- portaljs-define-schemaSkill
- portaljs-deploySkill
- portaljs-new-portalSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

