datopian/portaljs-connect-ckan
Wire a scaffolded PortalJS portal to a CKAN backend over its API. Generates a tiny server-side fetch client (no runtime dependency) and feeds the /search catalog and /@namespace/slug showcases from CKAN instead of datasets.json. Use when connecting an existing portal to a live CKAN instance instead of a static manifest.
npx skills add https://github.com/datopian/portaljs --skill portaljs-connect-ckan
Connect an existing portaljs-catalog portal to a live CKAN backend for the "decoupled /
any backend" path. The portal stops reading the static datasets.json manifest (and files
in /public/data/) and instead feeds its two data surfaces — the /search catalog and
the /@namespace/slug showcases — straight from a CKAN instance's REST API
(package_search / package_show) through a generated fetch client. Output is plain,
editable Next.js code with no runtime dependency — never @portaljs/ckan, whose bundle
wires React UI components to React 18 internals and crashes at import under the template's
React 19. Pages fetch CKAN server-side in getStaticProps/getStaticPaths, so the catalog
is pre-rendered at build time and the site can still be statically deployed. Run this right
after portaljs-new-portal to swap a freshly scaffolded portal's sample data over to CKAN.
portaljs-new-portal) with package.json, pages/,datasets.json, pages/search.tsx, and pages/[owner]/[slug].tsx present.
https://demo.dev.datopian.com.The canonical, full step-by-step workflow is
.claude/commands/portaljs-connect-ckan.md —
the single source of truth. Read and follow it when executing. Summary:
$ARGUMENTS — CKAN base URL (required), org filter (optional), groupfilter (optional), portal directory (default .). If the URL is missing, interview the
user; never dead-end with a missing-input error.
portaljs-catalog portal; if not, suggestportaljs-new-portal instead of failing silently.
package_search?rows=1, and validate each orgfilter via organization_show; on failure, explain and re-prompt rather than dead-ending.
lib/ckan.ts — a self-contained server-side fetch client wrappingpackage_search and package_show, with DMS, ORG_FILTER, GROUP_FILTER, and
MAX_DATASETS as editable constants.
pages/search.tsx to list datasets from package_search, linking each to/@namespace/slug via datasetHref; leave pages/index.tsx untouched.
pages/[owner]/[slug].tsx to pre-render one page per dataset viagetStaticPaths and fetch details with package_show, previewing tabular resources
through the existing Table component.
npx next build; fix any error before reporting success.lib/ckan.ts (fetch wrapper client — no dependency added to package.json).pages/search.tsx (catalog reads package_search); pages/[owner]/[slug].tsx(showcase reads package_show, overwritten to drop the datasets.json source).
pages/index.tsx (still the static search-first landing page).npx next build succeeds and prints the static page count./search and /@namespace/slug are served from the CKAN backend; theDMS env var can override the base URL at deploy time without editing code.
| Symptom | Cause | Fix |
| --- | --- | --- |
| Missing CKAN URL | User invoked the skill with no $ARGUMENTS | Ask for the base URL (and optional org/group filter); never error out. |
| package_search request fails or times out | URL isn't a reachable CKAN root | Tell the user, ask them to confirm the URL, and retry. |
| Org filter not found | organization_show returns success: false | List valid orgs from organization_list and ask which one was meant. |
| Catalog renders empty after connecting | Wrong org/group filter name in lib/ckan.ts | Clear or correct the filter constants and rebuild. |
| next build fails | Typo in substituted CKAN_URL or bad TypeScript edit | Print the log, fix the first error, and re-run before reporting success. |
| <Table> fails to load a resource | CKAN resource host blocks CORS | Note that the Download link still works; prefer datastore-backed resources. |
/portaljs-connect-ckan url=https://demo.dev.datopian.com
/portaljs-connect-ckan url=https://demo.dev.datopian.com org=my-org
/portaljs-connect-ckan url=https://data.example.gov group=education dir=./my-portal
.claude/commands/portaljs-connect-ckan.mdreferences/reference.mdportaljs-new-portal, portaljs-add-dataset, portaljs-deployTake datopian/portaljs-connect-ckan from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.
The instructions reference npx.
Without those the skill loads but fails at the first command.