#484 by GitHub stars
datopian/portaljs
🌀 AI-native framework for building data portals. Scaffold a full portal from a brief and load datasets in minutes with agentic skills — any backend (CKAN, GitHub, Frictionless).
History
Review weekly changes to SKILL.md before updating. Dates mark the weeks in which we observed each version; checks apply to the recorded commits.
View weekly changes
skills/arcgis-to-portaljs/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
fc7ccd651459 → fc7ccd651459
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → fc7ccd651459
No earlier version was observed for comparison.
skills/portaljs-add-chart/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
fc7ccd651459 → fc7ccd651459
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → fc7ccd651459
No earlier version was observed for comparison.
skills/portaljs-add-dataset/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
fc7ccd651459 → fc7ccd651459
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → fc7ccd651459
No earlier version was observed for comparison.
skills/portaljs-add-dcat/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
fc7ccd651459 → fc7ccd651459
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → fc7ccd651459
No earlier version was observed for comparison.
skills/portaljs-add-geo/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
fc7ccd651459 → fc7ccd651459
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → fc7ccd651459
No earlier version was observed for comparison.
skills/portaljs-add-map/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
fc7ccd651459 → fc7ccd651459
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → fc7ccd651459
No earlier version was observed for comparison.
skills/portaljs-add-resource/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
fc7ccd651459 → fc7ccd651459
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → fc7ccd651459
No earlier version was observed for comparison.
skills/portaljs-architect/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
fc7ccd651459 → fc7ccd651459
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → fc7ccd651459
No earlier version was observed for comparison.
skills/portaljs-check-data-quality/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
fc7ccd651459 → fc7ccd651459
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → fc7ccd651459
No earlier version was observed for comparison.
skills/portaljs-connect-ckan/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
fc7ccd651459 → fc7ccd651459
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → fc7ccd651459
No earlier version was observed for comparison.
skills/portaljs-define-schema/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
fc7ccd651459 → fc7ccd651459
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → fc7ccd651459
No earlier version was observed for comparison.
skills/portaljs-deploy/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
fc7ccd651459 → fc7ccd651459
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → fc7ccd651459
No earlier version was observed for comparison.
skills/portaljs-migrate/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
fc7ccd651459 → fc7ccd651459
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → fc7ccd651459
No earlier version was observed for comparison.
skills/portaljs-new-portal/SKILL.md
Week of Nov 2, 2026 · +0 / −0 lines
Before Network or broad shell → After Network or broad shell
fc7ccd651459 → fc7ccd651459
Week of Oct 26, 2026 · Line counts unavailable
Before Not checked yet → After Network or broad shell
First observation → fc7ccd651459
No earlier version was observed for comparison.
Verified commit fc7ccd651459549a962c8b7aa08f60f8849fd9a5
git clone --filter=blob:none --no-checkout https://github.com/datopian/portaljs.git .hotskills/datopian-portaljs && git -C .hotskills/datopian-portaljs checkout --detach fc7ccd651459549a962c8b7aa08f60f8849fd9a5
# Copy each selected skill directory from .hotskills/datopian-portaljs into .claude/skills/<skill-name>/git clone --filter=blob:none --no-checkout https://github.com/datopian/portaljs.git .hotskills/datopian-portaljs && git -C .hotskills/datopian-portaljs checkout --detach fc7ccd651459549a962c8b7aa08f60f8849fd9a5
# Copy each selected skill directory from .hotskills/datopian-portaljs into .agents/skills/<skill-name>/Heat
3.3- Star growth, last 7 daysAhead of 36% of tracked repositories
- Star growth, last 24 hoursAhead of 3% of tracked repositories
- Rank movement, last 7 daysAhead of 39% of tracked repositories
- Commits, last 30 daysAhead of 93% of tracked repositories
- Accounts asking about it through MCP, last 7 daysNot available
- Hot votes this weekAhead of 0% of tracked repositories
Heat never changes the order by stars, and sponsorship never touches it. How heat works
Stars over time
Individual skills in this repository
- arcgis-to-portaljs
skills/arcgis-to-portaljs - portaljs-add-chart
skills/portaljs-add-chart - portaljs-add-dataset
skills/portaljs-add-dataset - portaljs-add-dcat
skills/portaljs-add-dcat - portaljs-add-geo
skills/portaljs-add-geo - portaljs-add-map
skills/portaljs-add-map - portaljs-add-resource
skills/portaljs-add-resource - portaljs-architect
skills/portaljs-architect - portaljs-check-data-quality
skills/portaljs-check-data-quality - portaljs-connect-ckan
skills/portaljs-connect-ckan - portaljs-define-schema
skills/portaljs-define-schema - portaljs-deploy
skills/portaljs-deploy - portaljs-migrate
skills/portaljs-migrate - portaljs-new-portal
skills/portaljs-new-portal
How it works
arcgis-to-portaljs
When your agent uses it
Migrate a whole ArcGIS Hub site into a PortalJS Arc portal end-to-end. Harvests the Hub /data.json (DCAT-US) inventory, exports every FeatureService layer through the ArcGIS REST query API with resultOffset paging, converts each to the serverless dual tier (PMTiles render + GeoParquet query) with tabular items to Parquet, pushes everything to Cloudflare R2 via Git LFS, appends dual-tier datasets.json entries, and writes a source-vs-derived parity report. Use to move a City or sector ArcGIS Hub open-data portal onto PortalJS with no server-side compute.
What it loads into context
Frontmatter
346 tokensAlways available to the agent
SKILL.md
2,114 tokensWhen the skill is activated
Reference documents
1,363,723 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Overview
- Prerequisites
- Instructions
- Output
- Error Handling
- Examples
- Resources
Scripts executed separately
../../license../../scripts/csv-to-parquet.sh
Files
../../.claude-plugin/marketplace.jsonasset484 bytes../../.claude-plugin/plugin.jsonasset1,767 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/arcgis-to-portaljs.mddoc44,474 bytes../../.claude/commands/portaljs-add-chart.mddoc13,772 bytes../../.claude/commands/portaljs-add-chart.mddoc13,772 bytes../../.claude/commands/portaljs-add-chart.mddoc13,772 bytes../../.claude/commands/portaljs-add-chart.mddoc13,772 bytes../../.claude/commands/portaljs-add-dataset.mddoc17,397 bytes../../.claude/commands/portaljs-add-dataset.mddoc17,397 bytes../../.claude/commands/portaljs-add-dataset.mddoc17,397 bytes../../.claude/commands/portaljs-add-dataset.mddoc17,397 bytes../../.claude/commands/portaljs-add-dataset.mddoc17,397 bytes../../.claude/commands/portaljs-add-dataset.mddoc17,397 bytes../../.claude/commands/portaljs-add-dataset.mddoc17,397 bytes../../.claude/commands/portaljs-add-dataset.mddoc17,397 bytes../../.claude/commands/portaljs-add-dataset.mddoc17,397 bytes../../.claude/commands/portaljs-add-dataset.mddoc17,397 bytes../../.claude/commands/portaljs-add-dataset.mddoc17,397 bytes../../.claude/commands/portaljs-add-dataset.mddoc17,397 bytes../../.claude/commands/portaljs-add-dataset.mddoc17,397 bytes../../.claude/commands/portaljs-add-dataset.mddoc17,397 bytes../../.claude/commands/portaljs-add-dcat.mddoc18,001 bytes../../.claude/commands/portaljs-add-dcat.mddoc18,001 bytes../../.claude/commands/portaljs-add-dcat.mddoc18,001 bytes../../.claude/commands/portaljs-add-dcat.mddoc18,001 bytes../../.claude/commands/portaljs-add-dcat.mddoc18,001 bytes../../.claude/commands/portaljs-add-dcat.mddoc18,001 bytes../../.claude/commands/portaljs-add-dcat.mddoc18,001 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-geo.mddoc22,095 bytes../../.claude/commands/portaljs-add-map.mddoc14,032 bytes../../.claude/commands/portaljs-add-map.mddoc14,032 bytes../../.claude/commands/portaljs-add-map.mddoc14,032 bytes../../.claude/commands/portaljs-add-map.mddoc14,032 bytes../../.claude/commands/portaljs-add-map.mddoc14,032 bytes../../.claude/commands/portaljs-add-map.mddoc14,032 bytes../../.claude/commands/portaljs-add-map.mddoc14,032 bytes../../.claude/commands/portaljs-add-resource.mddoc6,309 bytes../../.claude/commands/portaljs-add-resource.mddoc6,309 bytes../../.claude/commands/portaljs-add-resource.mddoc6,309 bytes../../.claude/commands/portaljs-add-resource.mddoc6,309 bytes../../.claude/commands/portaljs-add-resource.mddoc6,309 bytes../../.claude/commands/portaljs-architect.mddoc13,194 bytes../../.claude/commands/portaljs-architect.mddoc13,194 bytes../../.claude/commands/portaljs-architect.mddoc13,194 bytes../../.claude/commands/portaljs-architect.mddoc13,194 bytes../../.claude/commands/portaljs-check-data-quality.mddoc1,292 bytes../../.claude/commands/portaljs-check-data-quality.mddoc1,292 bytes../../.claude/commands/portaljs-check-data-quality.mddoc1,292 bytes../../.claude/commands/portaljs-check-data-quality.mddoc1,292 bytes../../.claude/commands/portaljs-check-data-quality.mddoc1,292 bytes../../.claude/commands/portaljs-check-data-quality.mddoc1,292 bytes../../.claude/commands/portaljs-connect-ckan.mddoc21,868 bytes../../.claude/commands/portaljs-connect-ckan.mddoc21,868 bytes../../.claude/commands/portaljs-connect-ckan.mddoc21,868 bytes../../.claude/commands/portaljs-connect-ckan.mddoc21,868 bytes../../.claude/commands/portaljs-connect-ckan.mddoc21,868 bytes../../.claude/commands/portaljs-connect-ckan.mddoc21,868 bytes../../.claude/commands/portaljs-define-schema.mddoc11,323 bytes../../.claude/commands/portaljs-define-schema.mddoc11,323 bytes../../.claude/commands/portaljs-define-schema.mddoc11,323 bytes../../.claude/commands/portaljs-define-schema.mddoc11,323 bytes../../.claude/commands/portaljs-define-schema.mddoc11,323 bytes../../.claude/commands/portaljs-deploy.mddoc17,783 bytes../../.claude/commands/portaljs-deploy.mddoc17,783 bytes../../.claude/commands/portaljs-deploy.mddoc17,783 bytes../../.claude/commands/portaljs-deploy.mddoc17,783 bytes../../.claude/commands/portaljs-deploy.mddoc17,783 bytes../../.claude/commands/portaljs-deploy.mddoc17,783 bytes../../.claude/commands/portaljs-deploy.mddoc17,783 bytes../../.claude/commands/portaljs-deploy.mddoc17,783 bytes../../.claude/commands/portaljs-deploy.mddoc17,783 bytes../../.claude/commands/portaljs-deploy.mddoc17,783 bytes../../.claude/commands/portaljs-deploy.mddoc17,783 bytes../../.claude/commands/portaljs-deploy.mddoc17,783 bytes../../.claude/commands/portaljs-deploy.mddoc17,783 bytes../../.claude/commands/portaljs-deploy.mddoc17,783 bytes../../.claude/commands/portaljs-deploy.mddoc17,783 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-migrate.mddoc37,229 bytes../../.claude/commands/portaljs-new-portal.mddoc18,844 bytes../../.claude/commands/portaljs-new-portal.mddoc18,844 bytes../../.claude/commands/portaljs-new-portal.mddoc18,844 bytes../../.claude/commands/portaljs-new-portal.mddoc18,844 bytes../../.claude/commands/portaljs-new-portal.mddoc18,844 bytes../../.claude/commands/portaljs-new-portal.mddoc18,844 bytes../../.claude/commands/portaljs-new-portal.mddoc18,844 bytes../../.claude/commands/portaljs-new-portal.mddoc18,844 bytes../../.claude/commands/portaljs-new-portal.mddoc18,844 bytes../../.claude/commands/portaljs-new-portal.mddoc18,844 bytes../../.claude/commands/portaljs-new-portal.mddoc18,844 bytes../../.claude/commands/portaljs-new-portal.mddoc18,844 bytes../../licenseruns1,064 bytes../../scripts/csv-to-parquet.shruns3,297 bytesSKILL.mdcore8,007 bytesSKILL.mdcore8,007 bytesSKILL.mdcore8,007 bytesSKILL.mdcore8,007 bytesreferences/reference.mddoc5,514 bytesreferences/sync-and-cutover.mddoc14,917 bytes../portaljs-add-chart/SKILL.mddoc4,416 bytes../portaljs-add-chart/references/reference.mddoc2,255 bytes../portaljs-add-dataset/SKILL.mddoc6,387 bytes../portaljs-add-dataset/references/reference.mddoc3,655 bytes../portaljs-add-dcat/SKILL.mddoc7,360 bytes../portaljs-add-dcat/references/reference.mddoc5,268 bytes../portaljs-add-geo/SKILL.mddoc6,928 bytes../portaljs-add-geo/references/reference.mddoc5,069 bytes../portaljs-add-map/SKILL.mddoc5,575 bytes../portaljs-add-map/references/reference.mddoc2,605 bytes../portaljs-add-resource/SKILL.mddoc6,291 bytes../portaljs-add-resource/references/reference.mddoc2,957 bytes../portaljs-architect/SKILL.mddoc6,430 bytes../portaljs-architect/references/reference.mddoc3,533 bytes../portaljs-check-data-quality/SKILL.mddoc5,971 bytes../portaljs-check-data-quality/references/reference.mddoc4,303 bytes../portaljs-connect-ckan/SKILL.mddoc6,235 bytes../portaljs-connect-ckan/references/reference.mddoc3,096 bytes../portaljs-define-schema/SKILL.mddoc6,709 bytes../portaljs-define-schema/references/reference.mddoc3,690 bytes../portaljs-deploy/SKILL.mddoc5,447 bytes../portaljs-deploy/references/reference.mddoc4,350 bytes../portaljs-migrate/SKILL.mddoc7,045 bytes../portaljs-migrate/references/reference.mddoc4,073 bytes../portaljs-new-portal/SKILL.mddoc6,511 bytes../portaljs-new-portal/references/reference.mddoc4,011 bytes
Read SKILL.md
# ArcGIS Hub → PortalJS
## Overview
Migrate an entire **ArcGIS Hub** open-data site into a **PortalJS Arc** portal in one pass.
Every Hub site is machine-readable — a DCAT-US catalog at `/data.json`, with every dataset
backed by an ArcGIS REST FeatureService — so migration is a **harvest → export → convert →
publish → verify** pipeline that runs almost fully automated on the operator's machine, no
server-side compute. The tooling is the reusable `arcgis-to-portaljs` migrator: input is one
Hub URL, output is a ready-to-deploy PortalJS catalog plus a parity report.
The skill is an orchestrator: it reuses the DCAT-US harvest from `portaljs-migrate`, the
`ogr2ogr`/`tippecanoe`/`duckdb` dual-tier conversion from `portaljs-add-geo`, and the bulk
Git-LFS → R2 push from `portaljs-migrate`. Its novel parts are the FeatureService REST exportView the complete source on GitHubportaljs-add-chart
When your agent uses it
Add a chart (line, bar, area, pie, or scatter) to a dataset's showcase in a PortalJS portal. Installs recharts, writes a reusable Chart component, and renders it in the showcase Views section. Use when visualizing a dataset already registered in datasets.json.
What it loads into context
Frontmatter
188 tokensAlways available to the agent
SKILL.md
1,162 tokensWhen the skill is activated
Reference documents
634 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Overview
- Prerequisites
- Instructions
- Output
- Error Handling
- Examples
- Resources
Files
SKILL.mdcore4,416 bytesSKILL.mdcore4,416 bytesSKILL.mdcore4,416 bytesreferences/reference.mddoc2,255 bytes
Read SKILL.md
# PortalJS — Add Chart
## Overview
Add a visualization to a dataset's **showcase** in a PortalJS portal. The skill installs
`recharts` (added directly — never `@portaljs/components`), writes a reusable client-side
`Chart` component into `components/`, and renders a `<Chart />` into the **Views** section
of the showcase route `pages/[owner]/[slug].tsx` for one chosen dataset. The chart reads the
same `/public/data/<file>` the showcase `<Table />` already uses, so no data is duplicated.
Five chart types are supported: line, bar, area, pie, and scatter.
## Prerequisites
- A scaffolded PortalJS portal (see `portaljs-new-portal`).View the complete source on GitHubportaljs-add-dataset
When your agent uses it
Add a dataset (CSV, TSV, JSON, or GeoJSON) to an existing PortalJS portal. Appends an entry to datasets.json so the catalog and showcase render it automatically; routes the data by source (local file vs remote URL) — R2 via Git LFS by default, remote URLs by passthrough. Use when registering a new dataset in a scaffolded portal.
What it loads into context
Frontmatter
228 tokensAlways available to the agent
SKILL.md
1,640 tokensWhen the skill is activated
Reference documents
937 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Overview
- Prerequisites
- Instructions
- Output
- Error Handling
- Examples
- Resources
Files
SKILL.mdcore6,387 bytesSKILL.mdcore6,387 bytesSKILL.mdcore6,387 bytesSKILL.mdcore6,387 bytesSKILL.mdcore6,387 bytesSKILL.mdcore6,387 bytesSKILL.mdcore6,387 bytesreferences/reference.mddoc3,655 bytes
Read SKILL.md
# PortalJS — Add Dataset
## Overview
Register a dataset in a PortalJS (`portaljs-catalog`) portal. The skill appends one entry to
`datasets.json` — the single source of truth for the catalog — and routes the underlying
bytes by **source first, then size**: a local file defaults to R2 via Git LFS, a remote URL
defaults to passthrough (no copy). No per-dataset page is created; the catalog at `/search`
lists the new entry and the dynamic showcase route `pages/[owner]/[slug].tsx` renders it
automatically at `/@<namespace>/<slug>`. Supported formats for the showcase preview: CSV,
TSV, JSON (array), and GeoJSON.
## Prerequisites
View the complete source on GitHubportaljs-add-dcat
When your agent uses it
Make a PortalJS portal harvestable by national/EU/US open-data portals — emit standards-compliant DCAT catalog feeds (DCAT 2/3, DCAT-AP, DCAT-US, national profiles) in JSON-LD, Turtle, and RDF/XML at build, with autodiscovery and per-profile conformance checking. Use when a portal needs to be harvested by data.europa.eu, data.gov, or a national open-data catalog.
What it loads into context
Frontmatter
229 tokensAlways available to the agent
SKILL.md
1,970 tokensWhen the skill is activated
Reference documents
1,557 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Overview
- Prerequisites
- Instructions
- Output
- Error Handling
- Examples
- Resources
Files
SKILL.mdcore7,360 bytesSKILL.mdcore7,360 bytesreferences/reference.mddoc5,268 bytes
Read SKILL.md
# PortalJS — Add DCAT
## Overview
Turn an existing PortalJS (`portaljs-catalog`) portal into a harvestable data catalog.
PortalJS is Frictionless-native — a dataset is a Data Package (see
`portaljs-define-schema`) — and DCAT is the serialization + harvest layer on top
(`lib/metadata/dcat.ts` + `lib/metadata/dcat-profiles.ts`). This skill selects one or
more DCAT application profiles, maps every dataset's metadata to them, and writes
static feed files at build time — JSON-LD, Turtle, and RDF/XML — so external catalogs
(data.europa.eu, data.gov, national portals) can harvest the datasets automatically,
on any static host, with no runtime.
## PrerequisitesView the complete source on GitHubportaljs-add-geo
When your agent uses it
Auto-ingest a geospatial file (GeoJSON, Shapefile, GeoPackage, KML/KMZ, FlatGeobuf, CSV-with-geometry) into a PortalJS portal on the user's own machine, with no server. Normalizes CRS to EPSG:4326, derives a PMTiles render tier and a GeoParquet query tier, pushes all three artifacts to Cloudflare R2 via Git LFS, and appends one dual-tier datasets.json entry the showcase auto-renders. Use when the source is a vector geo format that needs a map or spatial-query view.
What it loads into context
Frontmatter
336 tokensAlways available to the agent
SKILL.md
1,962 tokensWhen the skill is activated
Reference documents
1,481 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Overview
- Prerequisites
- Instructions
- Output
- Error Handling
- Examples
- Resources
Files
SKILL.mdcore6,928 bytesSKILL.mdcore6,928 bytesSKILL.mdcore6,928 bytesSKILL.mdcore6,928 bytesreferences/reference.mddoc5,069 bytes
Read SKILL.md
# PortalJS — Add Geo
## Overview
Turn one geospatial upload into a **dual-tier** PortalJS dataset entirely on the user's
machine — **no server-side container compute**, keeping the zero-backend bet end-to-end.
From a single source the skill derives two serverless tiers plus the preserved original:
- **PMTiles** (render tier) — a vector-tile archive `<MapPreview>` renders with MapLibre GL
over HTTP range requests; any dataset size pans and zooms with no tile server.
- **GeoParquet** (query tier) — a GeoParquet 1.1 file (covering `bbox` column, Hilbert-sorted)
`<GeoQuery>` runs spatial SQL over in place via DuckDB-Wasm.
- **Original** — the untouched upload in its native CRS, kept downloadable.
View the complete source on GitHubportaljs-add-map
When your agent uses it
Render a GeoJSON dataset on an interactive Leaflet map in the Views section of a dataset's showcase. Installs react-leaflet and a Map component, then renders the map for the chosen dataset. Use when a dataset's data is geographic and a map view is needed alongside the showcase's default metadata and download.
What it loads into context
Frontmatter
196 tokensAlways available to the agent
SKILL.md
1,474 tokensWhen the skill is activated
Reference documents
695 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Overview
- Prerequisites
- Instructions
- Output
- Error Handling
- Examples
- Resources
Files
SKILL.mdcore5,575 bytesSKILL.mdcore5,575 bytesSKILL.mdcore5,575 bytesSKILL.mdcore5,575 bytesSKILL.mdcore5,575 bytesreferences/reference.mddoc2,605 bytes
Read SKILL.md
# PortalJS — Add Map
## Overview
Add an interactive Leaflet map as a view on a dataset's **showcase** in a
`portaljs-catalog` portal. The skill installs `react-leaflet`/`leaflet` (added directly —
never `@portaljs/components`), writes a reusable `Map` component split across
`MapView.tsx` (the Leaflet code) and `Map.tsx` (a `dynamic(..., { ssr: false })` wrapper,
since Leaflet touches `window` at module load), and renders `<Map />` into the **Views**
section of the showcase route `pages/[owner]/[slug].tsx` for one chosen GeoJSON dataset.
The dataset should already carry `format: "geojson"` in `datasets.json`; if it doesn't
exist yet, the skill can copy the file and register it first.
## PrerequisitesView the complete source on GitHubportaljs-add-resource
When your agent uses it
Add another file (resource) to an EXISTING dataset in a PortalJS portal — a data dictionary, methodology, or an additional data file. Turns a single-file dataset into a multi-resource one; the showcase renders a section per resource. Use when a dataset needs a second file, such as a data dictionary, methodology doc, or an additional period's data.
What it loads into context
Frontmatter
213 tokensAlways available to the agent
SKILL.md
1,535 tokensWhen the skill is activated
Reference documents
732 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Overview
- Prerequisites
- Instructions
- Output
- Error Handling
- Examples
- Resources
Files
SKILL.mdcore6,291 bytesSKILL.mdcore6,291 bytesreferences/reference.mddoc2,957 bytes
Read SKILL.md
# PortalJS — Add Resource
## Overview
Add a resource — an additional file — to a dataset that already exists in a
`portaljs-catalog` portal. Where `/portaljs-add-dataset` creates a **new** dataset
(one file), this skill adds a file to an **existing** one: a data dictionary, a
methodology document, or another data file (e.g. a second year's figures).
Mirrors the Frictionless Data Package model: a dataset holds a `resources[]` array,
and the showcase at `/@<namespace>/<slug>` renders one section per resource (preview,
schema, download). A single-file dataset migrates to `resources[]` automatically the
first time a second file is added — no data is lost.
View the complete source on GitHubportaljs-architect
When your agent uses it
Recommend a data-portal architecture (storage, compute, catalog, access, hosting, metadata) from stated needs, then hand off to the build skills. The advisory entry point. Use when starting a new data-portal project and the underlying architecture has not yet been decided.
What it loads into context
Frontmatter
189 tokensAlways available to the agent
SKILL.md
1,550 tokensWhen the skill is activated
Reference documents
881 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Overview
- Prerequisites
- Instructions
- Output
- Error Handling
- Examples
- Resources
Files
SKILL.mdcore6,430 bytesSKILL.mdcore6,430 bytesreferences/reference.mddoc3,533 bytes
Read SKILL.md
# PortalJS — Architect
## Overview
The advisory entry point for a PortalJS project. Before anything gets scaffolded, this
skill works out what to build: given the kind of portal, the shape of the data, and its
purpose, it fills six architecture slots (storage, catalog, compute, access, hosting,
metadata), resolves two build-time knobs (per-dataset data tier and the portal-wide
`DATA_QUERY` mode), and hands off to the concrete build skills. It decides; it does not
build. When the brief is thin it interviews in short rounds and never dead-ends — every
question has a sensible default, reachable by replying "use defaults."
## Prerequisites
- A rough idea of the portal's purpose and data (exact numbers are not required — the
interview supplies defaults for anything missing).View the complete source on GitHubportaljs-check-data-quality
When your agent uses it
Audit a local or remote tabular file (CSV/TSV) for common data quality issues — schema, nulls, types, duplicates. Read-only. Use when a dataset needs a quality check before publishing, or a showcase renders wrong (blank cells, garbled numbers, an unsortable date column) and the cause needs isolating.
What it loads into context
Frontmatter
205 tokensAlways available to the agent
SKILL.md
1,457 tokensWhen the skill is activated
Reference documents
1,167 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Overview
- Prerequisites
- Instructions
- Output
- Error Handling
- Examples
- Resources
Scripts executed separately
../../scripts/check-data-quality.sh
Files
../../scripts/check-data-quality.shruns9,741 bytesSKILL.mdcore5,971 bytesSKILL.mdcore5,971 bytesSKILL.mdcore5,971 bytesSKILL.mdcore5,971 bytesSKILL.mdcore5,971 bytesSKILL.mdcore5,971 bytesSKILL.mdcore5,971 bytesreferences/reference.mddoc4,303 bytes
Read SKILL.md
# PortalJS — Check Data Quality
## Overview
Run a read-only quality audit of one CSV or TSV file, local or remote, and return a
structured JSON report. The audit profiles every column — null/blank counts, inferred
value types, numeric ranges, likely year/date fields — and flags duplicate rows,
duplicate values in identifier-like columns, ambiguous overlapping year columns (e.g.
`calendar year` vs `fiscal year`), and mixed-type columns. It never edits the source
file, `datasets.json`, or any other project file; it only reads the target file (a
remote URL is downloaded to a temp file that is deleted before the run ends) and
prints a report. Use it before publishing a dataset with `portaljs-add-dataset`, or to
diagnose why a showcase renders wrong.
View the complete source on GitHubportaljs-connect-ckan
When your agent uses it
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.
What it loads into context
Frontmatter
199 tokensAlways available to the agent
SKILL.md
1,580 tokensWhen the skill is activated
Reference documents
773 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Overview
- Prerequisites
- Instructions
- Output
- Error Handling
- Examples
- Resources
Files
SKILL.mdcore6,235 bytesSKILL.mdcore6,235 bytesreferences/reference.mddoc3,096 bytes
Read SKILL.md
# PortalJS — Connect CKAN
## Overview
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.View the complete source on GitHubportaljs-define-schema
When your agent uses it
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.
What it loads into context
Frontmatter
205 tokensAlways available to the agent
SKILL.md
1,630 tokensWhen the skill is activated
Reference documents
974 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Overview
- Prerequisites
- Instructions
- Output
- Error Handling
- Examples
- Resources
Files
SKILL.mdcore6,709 bytesSKILL.mdcore6,709 bytesreferences/reference.mddoc3,690 bytes
Read SKILL.md
# PortalJS — Define Schema
## Overview
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:View the complete source on GitHubportaljs-deploy
When your agent uses it
Deploy a PortalJS portal to PortalJS Arc — Datopian-managed static hosting on Cloudflare. Builds a static export, uploads it, and returns a live SLUG.arc.portaljs.com URL. One command, one target. Use when a portal is ready to publish or redeploy to a live URL.
What it loads into context
Frontmatter
193 tokensAlways available to the agent
SKILL.md
1,441 tokensWhen the skill is activated
Reference documents
1,052 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Overview
- Prerequisites
- Instructions
- Output
- Error Handling
- Examples
- Resources
Files
SKILL.mdcore5,447 bytesSKILL.mdcore5,447 bytesSKILL.mdcore5,447 bytesreferences/reference.mddoc4,350 bytes
Read SKILL.md
# PortalJS — Deploy
## Overview
Publish an existing PortalJS portal to **PortalJS Arc** — Datopian's managed static
hosting on Cloudflare. Build a static export, upload it to the Arc API, and print a live
`https://SLUG.arc.portaljs.com` URL. Re-running redeploys the same portal (idempotent on
the slug). This is a single-target skill — it deploys to Arc only. For self-hosting, run
`npm run build` and upload `out/` to any static host; no skill required for that path.
Arc serves static exports only — SSR is not hosted on Arc yet.
## Prerequisites
- A PortalJS portal directory with a `package.json` that lists `next` as a dependency.View the complete source on GitHubportaljs-migrate
When your agent uses it
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.
What it loads into context
Frontmatter
262 tokensAlways available to the agent
SKILL.md
1,817 tokensWhen the skill is activated
Reference documents
1,091 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Overview
- Prerequisites
- Instructions
- Output
- Error Handling
- Examples
- Resources
Files
SKILL.mdcore7,045 bytesSKILL.mdcore7,045 bytesSKILL.mdcore7,045 bytesSKILL.mdcore7,045 bytesSKILL.mdcore7,045 bytesSKILL.mdcore7,045 bytesSKILL.mdcore7,045 bytesSKILL.mdcore7,045 bytesSKILL.mdcore7,045 bytesSKILL.mdcore7,045 bytesSKILL.mdcore7,045 bytesSKILL.mdcore7,045 bytesSKILL.mdcore7,045 bytesSKILL.mdcore7,045 bytesSKILL.mdcore7,045 bytesSKILL.mdcore7,045 bytesSKILL.mdcore7,045 bytesSKILL.mdcore7,045 bytesSKILL.mdcore7,045 bytesSKILL.mdcore7,045 bytesreferences/reference.mddoc4,073 bytes
Read SKILL.md
# 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.View the complete source on GitHubportaljs-new-portal
When your agent uses it
Scaffold a new PortalJS data portal from a brief. Copies the canonical template from examples/portaljs-catalog and substitutes project tokens. Use when starting a brand-new data portal project from scratch.
What it loads into context
Frontmatter
181 tokensAlways available to the agent
SKILL.md
1,669 tokensWhen the skill is activated
Reference documents
1,065 tokensLoaded on request
Token counts are estimates. Scripts run separately; they are not counted as reference context.
The playbook
- Overview
- Prerequisites
- Instructions
- Output
- Error Handling
- Examples
- Resources
Files
SKILL.mdcore6,511 bytesSKILL.mdcore6,511 bytesreferences/reference.mddoc4,011 bytes
Read SKILL.md
# PortalJS — New Portal
## Overview
Scaffold a production-ready PortalJS data portal from a brief. The skill is
**interactive**: if the brief is thin it interviews the user in three short rounds
(mapped to the template's three surfaces — Home, Catalog, Showcase), echoes a brief
back for confirmation, then copies `examples/portaljs-catalog` (locally or via a
remote `tiged` fetch), substitutes placeholder tokens, sets the namespace mode and the
UI language, seeds any datasets named in the interview, installs dependencies, and verifies the scaffold
with a type check.
## Prerequisites
View the complete source on GitHubSkills included
- arcgis-to-portaljs
- portaljs-add-chart
- portaljs-add-dataset
- portaljs-add-dcat
- portaljs-add-geo
- portaljs-add-map
- portaljs-add-resource
- portaljs-architect
- portaljs-check-data-quality
- portaljs-connect-ckan
- portaljs-define-schema
- portaljs-deploy
- portaljs-migrate
- portaljs-new-portal
Repository facts
- License
- MIT
- Created
- Oct 14, 2011
- Last pushed
- Oct 28, 2026
- Forks
- 338
- Open issues
- 15
- Project activity
- Active
Rank over the last 12 weeks
Now #484 · best #350 · down 75 in 30 days
- #476 from Oct 31 to Nov 1
- #477 on Nov 2
- #480 on Nov 3
- #481 on Nov 4
- #482 on Nov 5
- #484 since Nov 6
31 earlier periods
- #339 on Aug 1
- #336 on Aug 6
- #330 from Aug 8 to Aug 9
- #352 on Aug 18
- #350 on Aug 20
- #354 on Aug 23
- #362 on Aug 28
- #359 on Aug 29
- #354 on Aug 30
- #372 on Sep 1
- #375 on Sep 8
- #377 on Sep 12
- #388 on Sep 16
- #383 on Sep 17
- #387 on Sep 18
- #394 on Sep 22
- #407 on Sep 29
- #401 on Oct 1
- #401 on Oct 5
- #409 on Oct 7
- #416 on Oct 10
- #420 on Oct 11
- #428 on Oct 12
- #438 on Oct 16
- #433 on Oct 18
- #449 on Oct 21
- #446 on Oct 22
- #465 on Oct 25
- #471 on Oct 28
- #472 on Oct 29
- #475 on Oct 30
Before you install
Network or broad shellAutomated signals, not a guarantee
Checked Nov 3, 2026
Not fully analyzed: some files were too long, unreadable or missing. This never lowers the level.
Show 222 notes
.claude/commands/arcgis-to-portaljs.md:1Analysis incomplete: Referenced executable target unavailable; not analyzed.claude/commands/arcgis-to-portaljs.md:1Analysis incomplete: Referenced executable target unavailable; not analyzed.claude/commands/arcgis-to-portaljs.md:1Analysis incomplete: Referenced executable target unavailable; not analyzed.claude/commands/arcgis-to-portaljs.md:1Analysis incomplete: Referenced executable target unavailable; not analyzed.claude/commands/arcgis-to-portaljs.md:1Analysis incomplete: Referenced executable target unavailable; not analyzed.claude/commands/arcgis-to-portaljs.md:1Analysis incomplete: Referenced executable target unavailable; not analyzed.claude/commands/arcgis-to-portaljs.md:1Analysis incomplete: Referenced executable target unavailable; not analyzed.claude/commands/arcgis-to-portaljs.md:1Analysis incomplete: Referenced executable target unavailable; not analyzed.claude/commands/arcgis-to-portaljs.md:1Analysis incomplete: Referenced executable target unavailable; not analyzed.claude/commands/arcgis-to-portaljs.md:1Analysis incomplete: Referenced executable target unavailable; not analyzed.claude/commands/arcgis-to-portaljs.md:1Analysis incomplete: Referenced executable target unavailable; not analyzed.claude/commands/arcgis-to-portaljs.md:1Analysis incomplete: Referenced executable target unavailable; not analyzed.claude/commands/arcgis-to-portaljs.md:1Analysis incomplete: Referenced executable target unavailable; not analyzed.claude/commands/arcgis-to-portaljs.md:1Analysis incomplete: Referenced executable target unavailable; not analyzed.claude/commands/arcgis-to-portaljs.md:1Analysis incomplete: Referenced executable target unavailable; not analyzed.claude/commands/arcgis-to-portaljs.md:1Analysis incomplete: Referenced executable target unavailable; not analyzed.claude/commands/arcgis-to-portaljs.md:1Analysis incomplete: Referenced executable target unavailable; not analyzed.claude/commands/arcgis-to-portaljs.md:1Analysis incomplete: Referenced executable target unavailable; not analyzed.claude/commands/arcgis-to-portaljs.md:1Analysis incomplete: Referenced executable target unavailable; not analyzed.claude/commands/arcgis-to-portaljs.md:1Analysis incomplete: Referenced executable target unavailable; not analyzed
- 39 broad permissionsin 27 files: skills/portaljs-add-chart/SKILL.md:1 skills/portaljs-add-dataset/SKILL.md:1 skills/portaljs-add-dcat/SKILL.md:1 and 24 more
- 15 dangerous shell commandsin 8 files: .claude/commands/portaljs-deploy.md:135 arcgis-to-portaljs/references/sync-and-cutover.md:126 .claude/commands/portaljs-add-geo.md:99 and 5 more
- 541 network referencesin 46 files: .claude/commands/arcgis-to-portaljs.md:16 .claude/commands/portaljs-deploy.md:66 skills/portaljs-add-dcat/references/reference.md:3 and 43 more
- No hidden or obfuscated text
- No instruction overrides
- 3 executable scriptsin 3 files: license:1 scripts/check-data-quality.sh:1 scripts/csv-to-parquet.sh:1
- 28 references to secretsin 7 files: .claude/commands/portaljs-migrate.md:76 .claude/commands/portaljs-deploy.md:51 .claude/commands/portaljs-add-dataset.md:176 and 4 more
- No requests to vote in Hot
Show all 626 signals by file
.claude-plugin/marketplace.json
.claude-plugin/plugin.json
- Network accessline 5
"author": { "name": "Datopian", "url": "https://www.datopian.com" - Network accessline 6
"name": "Datopian", "url": "https://www.datopian.com" }, - Network accessline 7
"url": "https://www.datopian.com" - Network accessline 8
}, "homepage": "https://github.com/datopian/portaljs", "repository": "https://github.com/datopian/portaljs", - Network accessline 9
"homepage": "https://github.com/datopian/portaljs", - Network accessline 10
"repository": "https://github.com/datopian/portaljs",
.claude/commands/arcgis-to-portaljs.md
- Broad permissionsline 1
Read, Write, Edit, Bash(ogr2ogr:*), Bash(ogrinfo:*), Bash(tippecanoe:*), Bash(duckdb:*), Bash(git:*), Bash(curl:*), Bash(jq:*), Bash(npx:*), Bash(node:*), Bash(mkdir:*), Bash(cp:*), Bash(wc:*), Bash(zip:*), Bash(command:*), WebFetch - Network accessline 16
Input is one Hub URL (e.g. `https://hub-lewisville.opendata.arcgis.com` or - Network accessline 17
`https://streamwaterdata.co.uk`). Output: `datasets.json` entries, data on R2, and - Network accessline 52
- **Hub URL** (required) — the site root, e.g. `https://hub-lewisville.opendata.arcgis.com` - Network accessline 53
or a Hub Premium custom domain (`https://streamwaterdata.co.uk`). The skill appends - Network accessline 65
I need an ArcGIS Hub site URL to migrate. Provide the site root, e.g. https://hub-lewisville.opendata.arcgis.com - Network accessline 66
https://hub-lewisville.opendata.arcgis.com - Network accessline 67
(a Hub Premium custom domain like https://streamwaterdata.co.uk also works.) - Dangerous shell operationline 95
# Debian: sudo apt-get install -y gdal-bin duckdb jq nodejs # tippecanoe: build from source - Network accessline 115
curl -fsSL "$DATA_JSON" -o /tmp/a2p-datajson.json - Network accessline 188
Every Hub `dataset[]` item's `identifier` embeds the AGOL item id (`https://www.arcgis.com/home/item.html?id=<ITEM_ID>&sublayer=<n>`). Extract it and GET the - Network accessline 189
(`https://www.arcgis.com/home/item.html?id=<ITEM_ID>&sublayer=<n>`). Extract it and GET the - Network accessline 194
ITEM_ID=$(jq -r '.identifier' <<<"$ITEM" | sed -nE 's/.*[?&]id=([0-9a-f]{32}).*/\1/p') # Prefer the Hub's own portal host; www.arcgis.com works for public AGOL items. curl -fsSL "https://www.arcgis.com/sharing/rest/content/items/$ITEM_ID?f= - Network accessline 195
# Prefer the Hub's own portal host; www.arcgis.com works for public AGOL items. curl -fsSL "https://www.arcgis.com/sharing/rest/content/items/$ITEM_ID?f=json" \ -o "/tmp/a2p-item-$ITEM_ID.json" # → .snippet .description .licenseInfo .ac - Network accessline 196
curl -fsSL "https://www.arcgis.com/sharing/rest/content/items/$ITEM_ID?f=json" \ - Network accessline 253
mkdir -p public/thumbnails EXT="${THUMB##*.}" # png / gif / jpg — keep the source extension curl -fsSL "https://www.arcgis.com/sharing/rest/content/items/$ITEM_ID/info/$THUMB" \ - Network accessline 254
EXT="${THUMB##*.}" # png / gif / jpg — keep the source extension curl -fsSL "https://www.arcgis.com/sharing/rest/content/items/$ITEM_ID/info/$THUMB" \ -o "public/thumbnails/$SLUG.$EXT" && echo "thumbnail: /thumbnails/$SLUG.$EXT" - Network accessline 255
curl -fsSL "https://www.arcgis.com/sharing/rest/content/items/$ITEM_ID/info/$THUMB" \ - Network accessline 274
# Fetch the layer definition ONCE and reuse it (paging size, count, AND the field # definitions — name/type/alias — which drive the schema + English headers, §6d): curl -fsS "$LAYER?f=json" -o "/tmp/a2p-layerdef-$SLUG.json" - Network accessline 275
# definitions — name/type/alias — which drive the schema + English headers, §6d): curl -fsS "$LAYER?f=json" -o "/tmp/a2p-layerdef-$SLUG.json" MAX=$(jq -r '.maxRecordCount // 1000' "/tmp/a2p-layerdef-$SLUG.json") - Network accessline 276
curl -fsS "$LAYER?f=json" -o "/tmp/a2p-layerdef-$SLUG.json" - Network accessline 277
MAX=$(jq -r '.maxRecordCount // 1000' "/tmp/a2p-layerdef-$SLUG.json") TOTAL=$(curl -fsS "$LAYER/query?where=1%3D1&returnCountOnly=true&f=json" | jq -r '.count') # Page and concatenate features: - Network accessline 278
TOTAL=$(curl -fsS "$LAYER/query?where=1%3D1&returnCountOnly=true&f=json" | jq -r '.count') - Network accessline 281
const [,,layer,maxStr,out] = process.argv const max = parseInt(maxStr,10) || 1000 // A bare fetch() will hang forever on a slow/stalled FeatureServer page (common on - Network accessline 282
const max = parseInt(maxStr,10) || 1000 // A bare fetch() will hang forever on a slow/stalled FeatureServer page (common on // dense geometry like contours/parcels). Cap every request and retry — without this the - Network accessline 283
// A bare fetch() will hang forever on a slow/stalled FeatureServer page (common on - Network accessline 290
const t = setTimeout(() => ac.abort(), 45000) try { const r = await fetch(url, { signal: ac.signal }) - Network accessline 291
try { const r = await fetch(url, { signal: ac.signal }) if (!r.ok) throw new Error(`HTTP ${r.status}`) - Network accessline 292
const r = await fetch(url, { signal: ac.signal }) - Network accessline 320
- **Per-request timeout is mandatory, not a nicety.** ArcGIS FeatureServers routinely stall mid-page on dense geometry; a bare `fetch()` with no `AbortController` will hang the entire - Network accessline 321
mid-page on dense geometry; a bare `fetch()` with no `AbortController` will hang the entire - Network accessline 353
layer's **native CRS with Z coordinates** — e.g. Lewisville contours download as EPSG:3857 + Z — so always pipe it through `ogr2ogr -t_srs EPSG:4326 -dim XY`; and it can be enormous, 514 MB for contours, so use a long `curl --max-time`) - Network accessline 354
Z — so always pipe it through `ogr2ogr -t_srs EPSG:4326 -dim XY`; and it can be enormous, 514 MB for contours, so use a long `curl --max-time`); or (b) **ask the customer for a File Geodatabase export** — as the data owner they generate - Network accessline 355
for contours, so use a long `curl --max-time`); or (b) **ask the customer for a File Geodatabase - Network accessline 462
required), `git lfs prune`. Then build each absolute R2 URL (`$R2_PUBLIC_BASE/lfs/datopian/$PROJECT_SLUG/<oid>`, `R2_PUBLIC_BASE` default `https://data.portaljs.com`). - Network accessline 464
`https://data.portaljs.com`). - Network accessline 503
layer `?f=json` `editingInfo`), `extent`, and `migratedAt`. Phase 3 sync (§10) reads it to detect per-layer drift cheaply on a schedule; producing it here is what makes the shadow re-syncable at no extra cost. See [`sync-and-cutover.md`](ht - Network accessline 505
extra cost. See [`sync-and-cutover.md`](https://github.com/datopian/portaljs/blob/main/skills/arcgis-to-portaljs/references/sync-and-cutover.md). - Network accessline 570
Phase 0 migrates **once**. Phase 3 keeps the PortalJS shadow tracking the live Hub and preserves old URLs at cutover. Full design + copy-paste templates: [`sync-and-cutover.md`](https://github.com/datopian/portaljs/blob/main/skills/arcgis-t - Network accessline 571
URLs at cutover. Full design + copy-paste templates: [`sync-and-cutover.md`](https://github.com/datopian/portaljs/blob/main/skills/arcgis-to-portaljs/references/sync-and-cutover.md). Mental model is unchanged — **AGOL edits, PortalJS shadow - Network accessline 572
[`sync-and-cutover.md`](https://github.com/datopian/portaljs/blob/main/skills/arcgis-to-portaljs/references/sync-and-cutover.md). - Network accessline 580
LIVE_EDIT=$(curl -sS -m30 "$SVC?f=json" | jq -r '.editingInfo.dataLastEditDate // .editingInfo.lastEditDate // empty') - Network accessline 581
LIVE_COUNT=$(curl -sS -m30 "$SVC/query?where=1=1&returnCountOnly=true&f=json" | jq -r '.count') - Network accessline 636
domain can rot independently of the Hub: Stream's apex `streamwaterdata.co.uk` serves a certificate for an unrelated site (only `www.` — the CNAME to `hub.arcgis.com` — works). `curl -sv` the apex AND `www.` first, pick the working host - Network accessline 637
certificate for an unrelated site (only `www.` — the CNAME to `hub.arcgis.com` — works). `curl -sv` the apex AND `www.` first, pick the working host for every fetch, and record the broken variant in the report (it's also a cutover selli - Network accessline 638
`curl -sv` the apex AND `www.` first, pick the working host for every fetch, and record
.claude/commands/portaljs-add-chart.md
- Broad permissionsline 1
Read, Write, Edit, Bash - Network accessline 137
setIsLoading(true) setError(null) fetch(url) - Network accessline 138
setError(null) fetch(url) .then((r) => { - Network accessline 139
fetch(url) - Network accessline 299
Next: run `npm run dev` and visit http://localhost:3000/@NAMESPACE/SLUG to verify the chart renders.
.claude/commands/portaljs-add-dataset.md
- Broad permissionsline 1
Read, Write, Edit, Bash, WebFetch - Network accessline 45
- **Source** — a local file path (`./data/file.csv`) or a public URL (`https://…/data.csv`) - Network accessline 130
curl -fL "$SOURCE" -o "/tmp/$DATASET_SLUG.$EXT" - Network accessline 175
API="${PORTALJS_ARC_API:-https://api.arc.portaljs.com}" - Access to secretsline 176
[Credential-related source omitted] - Network accessline 179
[Credential-related source omitted] - Network accessline 180
[Credential-related source omitted] - Network accessline 181
[Credential-related source omitted] - Access to secretsline 181
[Credential-related source omitted] - Network accessline 182
# Pushing data needs write: request ?actions=read,write,verify (default is read-only, # pull). ?ttl=<secs> to tune. LFS_URL=$(curl -fsS -X POST "$API/v1/repos/<project-slug>/lfs-token?actions=read,write,verify" \ - Network accessline 183
[Credential-related source omitted] - Dangerous shell operationline 184
[Credential-related source omitted] - Network accessline 184
[Credential-related source omitted] - Access to secretsline 184
[Credential-related source omitted] - Access to secretsline 185
[Credential-related source omitted] - Network accessline 193
[Credential-related source omitted] - Network accessline 194
> --ttl 3600 --algorithm RS256 --key-file ../../giftless/jwt_private_key) > git config lfs.url "https://_jwt:$TOKEN@lfs.portaljs.com/datopian/<project-slug>" > ``` - Network accessline 195
> git config lfs.url "https://_jwt:$TOKEN@lfs.portaljs.com/datopian/<project-slug>" - Network accessline 240
`R2_PUBLIC_BASE` defaults to **`https://data.portaljs.com`** — the public read domain on the - Network accessline 241
`portaljs-giftless` R2 bucket (GET/HEAD + range + CORS, edge-cached). So the browser fetches `https://data.portaljs.com/lfs/datopian/<project-slug>/<oid>` directly. Override it only for an OSS self-host with its own bucket/domain (`export R - Network accessline 242
`https://data.portaljs.com/lfs/datopian/<project-slug>/<oid>` directly. Override it only for - Network accessline 307
Next: run `npm run dev` and visit http://localhost:3000/@NAMESPACE/DATASET_SLUG to verify,
.claude/commands/portaljs-add-dcat.md
- Broad permissionsline 1
Read, Write, Edit, Bash, WebFetch - Network accessline 66
organization (name + homepage) and a contact (name + email). Without them the feed is emitted but **fails conformance** — the generator will say what's missing. - **Site URL** — the portal's public origin (e.g. `https://data.example.org`) - Network accessline 67
emitted but **fails conformance** — the generator will say what's missing. - **Site URL** — the portal's public origin (e.g. `https://data.example.org`), so feed links are absolute. Without it links are root-relative (fine only for same-o - Network accessline 68
- **Site URL** — the portal's public origin (e.g. `https://data.example.org`), so feed - Network accessline 135
"contactPoint": { "fn": "<name>", "email": "<email>" }, "license": "<default license URI>", "themes": ["http://publications.europa.eu/resource/authority/data-theme/GOVE"], - Network accessline 136
"license": "<default license URI>", "themes": ["http://publications.europa.eu/resource/authority/data-theme/GOVE"], "languages": ["http://publications.europa.eu/resource/authority/language/ENG"], - Network accessline 137
"themes": ["http://publications.europa.eu/resource/authority/data-theme/GOVE"], - Network accessline 138
"languages": ["http://publications.europa.eu/resource/authority/language/ENG"], - Dangerous shell operationline 193
curl -s https://www.itb.ec.europa.eu/shacl/dcat-ap/api/validate -H 'Content-Type: application/json' -H 'Accept: application/ld+json' -d "$(python3 -c 'import json,sys;print(json.dumps({"contentToValidate":open("public/catalog.dcat - Network accessline 193
curl -s https://www.itb.ec.europa.eu/shacl/dcat-ap/api/validate \ - Network accessline 198
(validation types from `.../shacl/dcat-ap/api/info`; also usable offline via `pip install pyshacl` + the [DCAT-AP SHACL shapes](https://github.com/SEMICeu/DCAT-AP/tree/master/releases)). - Network accessline 199
`pip install pyshacl` + the [DCAT-AP SHACL shapes](https://github.com/SEMICeu/DCAT-AP/tree/master/releases)). - Network accessline 200
- **DCAT-US** — `pip install pyshacl` + the official [DCAT-US 3.0 SHACL shapes](https://raw.githubusercontent.com/DOI-DO/dcat-us/main/shacl/dcat-us_3.0_shacl_shapes.ttl): `pyshacl -s dcat-us_3.0_shacl_shapes.ttl -a public/catalog.dcat-u - Network accessline 201
[DCAT-US 3.0 SHACL shapes](https://raw.githubusercontent.com/DOI-DO/dcat-us/main/shacl/dcat-us_3.0_shacl_shapes.ttl): - Network accessline 206
`dcatap.3_0_1_base` on the ITB endpoint above, over `public/catalog.geodcat-ap.ttl`). For the full spatial profile use the official [GeoDCAT-AP 3.0.0 SHACL shapes](https://semiceu.github.io/GeoDCAT-AP/releases/3.0.0/shacl/geodcat-ap-SHA - Network accessline 207
For the full spatial profile use the official [GeoDCAT-AP 3.0.0 SHACL shapes](https://semiceu.github.io/GeoDCAT-AP/releases/3.0.0/shacl/geodcat-ap-SHACL.ttl): `pyshacl -s geodcat-ap-SHACL.ttl -df turtle -a public/catalog.geodcat-ap.ttl` - Network accessline 208
[GeoDCAT-AP 3.0.0 SHACL shapes](https://semiceu.github.io/GeoDCAT-AP/releases/3.0.0/shacl/geodcat-ap-SHACL.ttl): - Network accessline 212
vocabularies; run with `-i rdfs` to clear the subclass ones. - **DCAT-AP_IT** — run the AgID SPARQL rules ([italia/daf-semantic-validator](https://github.com/italia/daf-semantic-validator/tree/master/dist/data/ontologies/agid/DCAT-AP_IT/v - Network accessline 213
- **DCAT-AP_IT** — run the AgID SPARQL rules ([italia/daf-semantic-validator](https://github.com/italia/daf-semantic-validator/tree/master/dist/data/ontologies/agid/DCAT-AP_IT/validators/sparql)) over `public/catalog.dcat-ap-it.ttl` wit - Network accessline 214
([italia/daf-semantic-validator](https://github.com/italia/daf-semantic-validator/tree/master/dist/data/ontologies/agid/DCAT-AP_IT/validators/sparql)) - Network accessline 215
over `public/catalog.dcat-ap-it.ttl` with any SPARQL engine, or `dcat-ap-it validate public/catalog.dcat-ap-it.ttl` ([ondata/dcat-ap-it-generator](https://github.com/ondata/dcat-ap-it-generator)). Errors are mandatory properties, warnin - Network accessline 216
public/catalog.dcat-ap-it.ttl` ([ondata/dcat-ap-it-generator](https://github.com/ondata/dcat-ap-it-generator)). - Network accessline 217
Errors are mandatory properties, warnings recommended ones. Before registering with dati.gov.it, upload the Turtle to the official validator, https://validatore.dati.gov.it (browser only). - Network accessline 218
dati.gov.it, upload the Turtle to the official validator, https://validatore.dati.gov.it
.claude/commands/portaljs-add-geo.md
- Broad permissionsline 1
Read, Write, Edit, Bash, WebFetch - Network accessline 98
macOS: brew install gdal tippecanoe duckdb Debian/Ubuntu: sudo apt-get install -y gdal-bin duckdb # tippecanoe: apt where available, else build from source — https://github.com/felt/tippecanoe - Dangerous shell operationline 99
Debian/Ubuntu: sudo apt-get install -y gdal-bin duckdb # tippecanoe: apt where available, - Network accessline 99
Debian/Ubuntu: sudo apt-get install -y gdal-bin duckdb # tippecanoe: apt where available, else build from source — https://github.com/felt/tippecanoe Windows: not supported natively — use WSL (Ubuntu) and follow - Network accessline 100
else build from source — https://github.com/felt/tippecanoe - Network accessline 122
### 4. Fetch (if URL) and detect the input format - Network accessline 127
curl -fL "$SOURCE" -o "/tmp/$DATASET_SLUG.$EXT" - Network accessline 288
API="${PORTALJS_ARC_API:-https://api.arc.portaljs.com}" - Network accessline 289
[Credential-related source omitted] - Access to secretsline 289
[Credential-related source omitted] - Network accessline 290
[Credential-related source omitted] - Network accessline 291
[Credential-related source omitted] - Access to secretsline 291
[Credential-related source omitted] - Dangerous shell operationline 292
[Credential-related source omitted] - Network accessline 292
[Credential-related source omitted] - Access to secretsline 292
[Credential-related source omitted] - Access to secretsline 293
[Credential-related source omitted] - Network accessline 298
[Credential-related source omitted] - Network accessline 300
> then `git config lfs.url "https://_jwt:$TOKEN@lfs.portaljs.com/datopian/<project-slug>"`. - Network accessline 316
**Build the absolute R2 URL for each artifact** (`R2_PUBLIC_BASE` defaults to `https://data.portaljs.com`; object key = `lfs/datopian/<project-slug>/<oid>`): - Network accessline 317
`https://data.portaljs.com`; object key = `lfs/datopian/<project-slug>/<oid>`): - Network accessline 387
curl -sI -H "Range: bytes=0-0" "$GEOPARQUET_URL" | head -1 # expect: HTTP/… 206 - Network accessline 406
Next: run `npm run dev` and open http://localhost:3000/@NAMESPACE/DATASET_SLUG — the map
.claude/commands/portaljs-add-map.md
- Broad permissionsline 1
Read, Write, Edit, Bash, WebFetch - Network accessline 80
mkdir -p PORTAL_DIR/public/data cp SOURCE PORTAL_DIR/public/data/MAP_SLUG.geojson # or for URLs: curl -L SOURCE -o PORTAL_DIR/public/data/MAP_SLUG.geojson - Network accessline 82
# or for URLs: curl -L SOURCE -o PORTAL_DIR/public/data/MAP_SLUG.geojson - Network accessline 155
useEffect(() => { if (!url) return fetch(url) - Network accessline 156
if (!url) return fetch(url) .then((r) => { - Network accessline 157
fetch(url) - Network accessline 181
> <TileLayer attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' - Network accessline 182
<TileLayer attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" - Network accessline 183
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' - Network accessline 184
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" - Network accessline 320
Next: run `npm run dev` and visit http://localhost:3000/@NAMESPACE/SLUG to verify the map renders.
.claude/commands/portaljs-add-resource.md
- Broad permissionsline 1
Read, Write, Edit, Bash, WebFetch - Network accessline 60
mkdir -p PORTAL_DIR/public/data cp SOURCE PORTAL_DIR/public/data/RESOURCE_NAME.EXT # or for URLs: curl -L SOURCE -o PORTAL_DIR/public/data/RESOURCE_NAME.EXT - Network accessline 62
# or for URLs: curl -L SOURCE -o PORTAL_DIR/public/data/RESOURCE_NAME.EXT
.claude/commands/portaljs-architect.md
- Broad permissionsline 1
Read, Write, Bash
.claude/commands/portaljs-check-data-quality.md
.claude/commands/portaljs-connect-ckan.md
- Broad permissionsline 1
Read, Write, Edit, Bash, WebFetch - Network accessline 36
- **CKAN base URL** (required) — e.g. `https://demo.dev.datopian.com`. The root of the - Network accessline 57
To connect a CKAN backend I need: 1. CKAN base URL (e.g. https://demo.dev.datopian.com) — required - Network accessline 58
1. CKAN base URL (e.g. https://demo.dev.datopian.com) — required - Network accessline 76
curl -s -m 20 "CKAN_URL/api/3/action/package_search?rows=1" - Network accessline 85
curl -s -m 20 "CKAN_URL/api/3/action/organization_show?id=ORG" - Network accessline 142
async function ckanAction(action: string, params: Record<string, string>): Promise<any> { const qs = new URLSearchParams(params).toString() const res = await fetch(`${DMS}/api/3/action/${action}?${qs}`) - Network accessline 143
const qs = new URLSearchParams(params).toString() const res = await fetch(`${DMS}/api/3/action/${action}?${qs}`) if (!res.ok) throw new Error(`CKAN ${action} failed: ${res.status} ${res.statusText}`) - Network accessline 144
const res = await fetch(`${DMS}/api/3/action/${action}?${qs}`) - Network accessline 444
Next: run `npm run dev` and visit http://localhost:3000, or run /portaljs-deploy to publish.
.claude/commands/portaljs-define-schema.md
.claude/commands/portaljs-deploy.md
- Broad permissionsline 1
Read, Write, Edit, Bash - Access to secretsline 51
[Credential-related source omitted] - Network accessline 66
AUTH="${PORTALJS_ARC_AUTH:-https://arc.portaljs.com}" - Network accessline 67
API="${PORTALJS_ARC_API:-https://api.arc.portaljs.com}" - Network accessline 75
const AUTH = process.env.PORTALJS_ARC_AUTH || 'https://arc.portaljs.com' - Network accessline 76
const API = process.env.PORTALJS_ARC_API || 'https://api.arc.portaljs.com' - Network accessline 86
async function main() { const start = await fetch(`${AUTH}/device/code`, { - Network accessline 87
const start = await fetch(`${AUTH}/device/code`, { - Network accessline 102
if (Date.now() > deadline) throw new Error('Timed out waiting for authorization. Re-run /portaljs-deploy.') await sleep(wait) const poll = await fetch(`${AUTH}/device/token`, { - Network accessline 103
await sleep(wait) const poll = await fetch(`${AUTH}/device/token`, { method: 'POST', - Network accessline 104
const poll = await fetch(`${AUTH}/device/token`, { - Network accessline 117
[Credential-related source omitted] - Network accessline 118
[Credential-related source omitted] - Network accessline 119
[Credential-related source omitted] - Dangerous shell operationline 135
rm -f /tmp/arc-login.mjs - Network accessline 138
After the flow completes, re-read `TOKEN` from `~/.portaljs/credentials` (snippet above) and continue to step 3. Non-interactive/CI: skip the browser flow by setting `PORTALJS_TOKEN` (mint a token in the dashboard at https://arc.portaljs.co - Network accessline 139
continue to step 3. Non-interactive/CI: skip the browser flow by setting `PORTALJS_TOKEN` (mint a token in the dashboard at https://arc.portaljs.com) — it takes precedence over the file. If the device flow can't run at all (no Node, fully o - Network accessline 140
(mint a token in the dashboard at https://arc.portaljs.com) — it takes precedence over the - Network accessline 144
To deploy to PortalJS Arc you need a token. Sign in at https://arc.portaljs.com and either: - Access to secretsline 145
[Credential-related source omitted] - Network accessline 149
(The API base URL defaults to `https://api.arc.portaljs.com`; override with `PORTALJS_ARC_API` - Network accessline 150
for staging. The auth worker defaults to `https://arc.portaljs.com`; override with - Network accessline 229
PORTAL_DIR="." # ← portal directory (step 1) SLUG="my-portal" # ← validated slug (step 1) API="${PORTALJS_ARC_API:-https://api.arc.portaljs.com}" - Network accessline 231
API="${PORTALJS_ARC_API:-https://api.arc.portaljs.com}" - Access to secretsline 234
[Credential-related source omitted] - Network accessline 243
# Pass the bearer token via a 0600 curl config file, not argv — so it doesn't leak - Network accessline 245
[Credential-related source omitted] - Network accessline 246
[Credential-related source omitted] - Network accessline 247
HTTP=$(curl -s -o /tmp/arc-resp.json -w "%{http_code}" -m 120 -K "$HDR" \ - Dangerous shell operationline 250
rm -f "$HDR" - Network accessline 274
PORTAL_DIR="." # ← portal directory (step 1) DEPLOYMENT_ID="<from step 5's response>" API="${PORTALJS_ARC_API:-https://api.arc.portaljs.com}" - Network accessline 275
DEPLOYMENT_ID="<from step 5's response>" API="${PORTALJS_ARC_API:-https://api.arc.portaljs.com}" # TOKEN already resolved in step 5. - Network accessline 276
API="${PORTALJS_ARC_API:-https://api.arc.portaljs.com}" - Dangerous shell operationline 290
rm -f "$FILELIST" - Access to secretsline 294
[Credential-related source omitted] - Access to secretsline 296
[Credential-related source omitted] - Network accessline 300
[Credential-related source omitted] - Network accessline 301
[Credential-related source omitted] - Network accessline 302
HTTP=$(curl -s -o /tmp/arc-source-resp.json -w "%{http_code}" -m 300 -K "$HDR" \ - Dangerous shell operationline 305
rm -f "$HDR" /tmp/arc-source.tgz - Network accessline 320
✓ Deployed to PortalJS Arc - URL: https://SLUG.arc.portaljs.com - Network accessline 321
- URL: https://SLUG.arc.portaljs.com - Network accessline 337
orphans at their old URLs. Pick the slug once; it's your portal's permanent address. - **Auth lives outside the repo.** The token is read from `PORTALJS_TOKEN` or `~/.portaljs/credentials` — never commit it. `https://arc.portaljs.com` is - Network accessline 338
- **Auth lives outside the repo.** The token is read from `PORTALJS_TOKEN` or `~/.portaljs/credentials` — never commit it. `https://arc.portaljs.com` is where you sign in and manage tokens. - Network accessline 339
`~/.portaljs/credentials` — never commit it. `https://arc.portaljs.com` is where you sign in
.claude/commands/portaljs-migrate.md
- Broad permissionsline 1
Read, Write, Edit, Bash, WebFetch - Access to secretsline 76
[Credential-related source omitted] - Access to secretsline 86
[Credential-related source omitted] - Access to secretsline 104
[Credential-related source omitted] - Network accessline 138
- URL ends in `.json` or contains `/data.json` → **dcat** (DCAT-US Project Open Data JSON). - URL contains `/api/explore/` → **ods**; `/api/catalog/` → **socrata**. - Otherwise probe CKAN: `curl -s -m 20 "SOURCE_URL/api/3/action/package_sea - Network accessline 139
- URL contains `/api/explore/` → **ods**; `/api/catalog/` → **socrata**. - Otherwise probe CKAN: `curl -s -m 20 "SOURCE_URL/api/3/action/package_search?rows=1"` → if JSON with `"success": true`, it's **ckan**. - Network accessline 140
- Otherwise probe CKAN: `curl -s -m 20 "SOURCE_URL/api/3/action/package_search?rows=1"` → - Network accessline 142
- Else probe in turn: `SOURCE_URL/api/explore/v2.1/catalog/datasets?limit=1` (ods), `SOURCE_URL/data.json` (dcat), then content-negotiate RDF: `curl -fsSL -H "Accept: application/ld+json,text/turtle,application/rdf+xml" SOURCE_URL` — if - Network accessline 143
`SOURCE_URL/data.json` (dcat), then content-negotiate RDF: `curl -fsSL -H "Accept: application/ld+json,text/turtle,application/rdf+xml" SOURCE_URL` — if the body is JSON-LD/Turtle/RDF-XML (starts with `{`/`[`, `@prefix`/`PREFIX`, or `<? - Network accessline 144
`curl -fsSL -H "Accept: application/ld+json,text/turtle,application/rdf+xml" SOURCE_URL` — if - Network accessline 150
ask them to confirm the URL / pick the `--source` type — don't dead-end. (Socrata is read through the central Discovery API, so for a Socrata site pass `--source socrata` with the site root, e.g. `https://data.cityofnewyork.us`.) - Network accessline 152
site root, e.g. `https://data.cityofnewyork.us`.) - Network accessline 303
cd PORTAL_DIR curl -fsSL -H "Accept: application/ld+json,text/turtle,application/rdf+xml" \ - Network accessline 304
curl -fsSL -H "Accept: application/ld+json,text/turtle,application/rdf+xml" \ - Network accessline 354
Page the catalog: `https://api.us.socrata.com/api/catalog/v1?domains=<host>&limit=100&offset=…` - Network accessline 460
```bash SLUG=<portal-slug> # the portal's deploy slug (same one /portaljs-deploy uses) API="${PORTALJS_ARC_API:-https://api.arc.portaljs.com}" - Network accessline 461
[Credential-related source omitted] - Network accessline 462
[Credential-related source omitted] - Network accessline 463
[Credential-related source omitted] - Access to secretsline 463
[Credential-related source omitted] - Network accessline 464
[Credential-related source omitted] - Access to secretsline 464
[Credential-related source omitted] - Network accessline 465
LFS_URL=$(curl -fsS -X POST "$API/v1/repos/$SLUG/lfs-token?actions=read,write,verify" \ - Access to secretsline 466
[Credential-related source omitted] - Network accessline 488
# path = $R2_PUBLIC_BASE/lfs/datopian/<portal-slug>/<OID> ``` `R2_PUBLIC_BASE` defaults to **`https://data.portaljs.com`** — the public read domain on - Network accessline 489
``` `R2_PUBLIC_BASE` defaults to **`https://data.portaljs.com`** — the public read domain on the `portaljs-giftless` R2 bucket (GET/HEAD + range + CORS, edge-cached), so the browser - Network accessline 490
`R2_PUBLIC_BASE` defaults to **`https://data.portaljs.com`** — the public read domain on - Access to secretsline 524
[Credential-related source omitted]
.claude/commands/portaljs-new-portal.md
- Broad permissionsline 1
Read, Write, Edit, Bash - Dangerous shell operationline 175
rm -rf "./$PROJECT_SLUG/node_modules" "./$PROJECT_SLUG/.next" - Network accessline 357
✓ Branding: PortalJS placeholder mark (favicon + navbar logo) — swap the files in public/ (icon.svg, favicon.ico, apple-touch-icon.png, icon-512.png) for your own. ✓ Run: cd PROJECT_SLUG && npm run dev → http://localhost:3000 - Network accessline 359
✓ Run: cd PROJECT_SLUG && npm run dev → http://localhost:3000
license
- Executable scriptline 1
Executable file
scripts/check-data-quality.sh
- Executable scriptline 1
#!/usr/bin/env bash - Dangerous shell operationline 12
rm -f "$TEMP_FILE" - Network accessline 24
url, out_path = sys.argv[1:3] with urllib.request.urlopen(url) as response, open(out_path, "wb") as out_file: - Network accessline 25
with urllib.request.urlopen(url) as response, open(out_path, "wb") as out_file:
scripts/csv-to-parquet.sh
- Executable scriptline 1
#!/usr/bin/env bash - Network accessline 38
Install it (it's a single static binary, no runtime): macOS: brew install duckdb Linux: curl -L https://github.com/duckdb/duckdb/releases/latest/download/duckdb_cli-linux-amd64.zip -o duckdb.zip && unzip duckdb.zip - Network accessline 39
macOS: brew install duckdb Linux: curl -L https://github.com/duckdb/duckdb/releases/latest/download/duckdb_cli-linux-amd64.zip -o duckdb.zip && unzip duckdb.zip Other: https://duckdb.org/docs/installation - Network accessline 40
Linux: curl -L https://github.com/duckdb/duckdb/releases/latest/download/duckdb_cli-linux-amd64.zip -o duckdb.zip && unzip duckdb.zip - Network accessline 41
Other: https://duckdb.org/docs/installation
skills/arcgis-to-portaljs/SKILL.md
- Broad permissionsline 1
Read, Write, Edit, Bash(ogr2ogr:*), Bash(ogrinfo:*), Bash(tippecanoe:*), Bash(duckdb:*), Bash(git:*), Bash(curl:*), Bash(jq:*), Bash(npx:*), Bash(node:*), Bash(mkdir:*), Bash(cp:*), Bash(wc:*), Bash(command:*), WebFetch - Network accessline 47
The canonical, full step-by-step workflow is [`.claude/commands/arcgis-to-portaljs.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/arcgis-to-portaljs.md) - Network accessline 48
[`.claude/commands/arcgis-to-portaljs.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/arcgis-to-portaljs.md) - Network accessline 90
| Symptom | Cause | Fix | | --- | --- | --- | | `MISSING_INPUT` | No Hub URL provided | Pass the site root (e.g. `https://hub-lewisville.opendata.arcgis.com`) and retry. | - Network accessline 91
| --- | --- | --- | | `MISSING_INPUT` | No Hub URL provided | Pass the site root (e.g. `https://hub-lewisville.opendata.arcgis.com`) and retry. | | `MISSING_TOOLS` | `ogr2ogr`/`tippecanoe`/`duckdb`/`jq` (or duckdb `spatial`) absent | Print - Network accessline 92
| `MISSING_INPUT` | No Hub URL provided | Pass the site root (e.g. `https://hub-lewisville.opendata.arcgis.com`) and retry. | - Network accessline 104
/arcgis-to-portaljs https://hub-lewisville.opendata.arcgis.com slug=lewisville - Network accessline 110
/arcgis-to-portaljs https://streamwaterdata.co.uk --dry-run - Network accessline 116
/arcgis-to-portaljs https://streamwaterdata.co.uk --only sewer-catchments,water-boundaries --namespace-mode owner - Network accessline 121
- Full workflow: [`.claude/commands/arcgis-to-portaljs.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/arcgis-to-portaljs.md) - Network accessline 123
- Ongoing sync, parity dashboard, and cutover (Phase 3): [`references/sync-and-cutover.md`](references/sync-and-cutover.md) - Related skills: `portaljs-migrate`, `portaljs-add-geo`, `portaljs-add-dataset`, `portaljs-deploy` - ArcGIS REST qu - Network accessline 125
- ArcGIS REST query API: <https://developers.arcgis.com/rest/services-reference/enterprise/query-feature-service-layer/> · tippecanoe: <https://github.com/felt/tippecanoe> · DuckDB spatial: <https://duckdb.org/docs/extensions/spatial>
skills/arcgis-to-portaljs/references/reference.md
- Network accessline 3
Detailed reference for the `arcgis-to-portaljs` skill. The executable workflow lives in [`.claude/commands/arcgis-to-portaljs.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/arcgis-to-portaljs.md). - Network accessline 4
[`.claude/commands/arcgis-to-portaljs.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/arcgis-to-portaljs.md). - Network accessline 77
`git lfs track "data/**"` → one commit → claim slug + mint Arc JWT → `git config lfs.url` → one push (bytes → Giftless/R2, no GitHub remote required) → `git lfs prune`. R2 URL = `${R2_PUBLIC_BASE:-https://data.portaljs.com}/lfs/datopian/<sl - Network accessline 78
one push (bytes → Giftless/R2, no GitHub remote required) → `git lfs prune`. R2 URL = `${R2_PUBLIC_BASE:-https://data.portaljs.com}/lfs/datopian/<slug>/<oid>`. OSS self-host signs locally with `giftless/mint-token.py`. Dual-tier `datasets.j - Network accessline 79
`${R2_PUBLIC_BASE:-https://data.portaljs.com}/lfs/datopian/<slug>/<oid>`. OSS self-host signs
skills/arcgis-to-portaljs/references/sync-and-cutover.md
- Network accessline 40
{ "generatedAt": "2026-07-14T16:00:00Z", "site": "https://hub-lewisville.opendata.arcgis.com", - Network accessline 41
"generatedAt": "2026-07-14T16:00:00Z", "site": "https://hub-lewisville.opendata.arcgis.com", "layers": { - Network accessline 42
"site": "https://hub-lewisville.opendata.arcgis.com", - Network accessline 43
"layers": { "geo/parcels-hosted": { "serviceUrl": "https://services2.arcgis.com/kXGqZY4GIOcEYxoF/arcgis/rest/services/Parcels_Hosted/FeatureServer/0", - Network accessline 44
"geo/parcels-hosted": { "serviceUrl": "https://services2.arcgis.com/kXGqZY4GIOcEYxoF/arcgis/rest/services/Parcels_Hosted/FeatureServer/0", "recordCount": 30694, - Network accessline 45
"serviceUrl": "https://services2.arcgis.com/kXGqZY4GIOcEYxoF/arcgis/rest/services/Parcels_Hosted/FeatureServer/0", - Network accessline 66
SVC="$serviceUrl" # from the ledger # 1) Edit timestamp (authoritative when present). epoch ms. LIVE_EDIT=$(curl -sS -m30 "$SVC?f=json" | jq -r '.editingInfo.dataLastEditDate // .editingInfo.lastEditDate // empty') - Network accessline 67
# 1) Edit timestamp (authoritative when present). epoch ms. LIVE_EDIT=$(curl -sS -m30 "$SVC?f=json" | jq -r '.editingInfo.dataLastEditDate // .editingInfo.lastEditDate // empty') # 2) Live count (always available; the fallback + a second gu - Network accessline 68
LIVE_EDIT=$(curl -sS -m30 "$SVC?f=json" | jq -r '.editingInfo.dataLastEditDate // .editingInfo.lastEditDate // empty') - Network accessline 70
LIVE_COUNT=$(curl -sS -m30 "$SVC/query?where=1=1&returnCountOnly=true&f=json" | jq -r '.count') - Dangerous shell operationline 126
sudo apt-get update - Dangerous shell operationline 127
sudo apt-get install -y gdal-bin duckdb jq - Network accessline 128
# tippecanoe: prebuilt release or build from source (cache this step in practice) sudo apt-get install -y build-essential libsqlite3-dev zlib1g-dev git clone --depth 1 https://github.com/felt/tippecanoe /tmp/tippecanoe - Dangerous shell operationline 129
sudo apt-get install -y build-essential libsqlite3-dev zlib1g-dev - Network accessline 129
sudo apt-get install -y build-essential libsqlite3-dev zlib1g-dev git clone --depth 1 https://github.com/felt/tippecanoe /tmp/tippecanoe make -C /tmp/tippecanoe -j2 && sudo make -C /tmp/tippecanoe install - Network accessline 130
git clone --depth 1 https://github.com/felt/tippecanoe /tmp/tippecanoe - Dangerous shell operationline 131
make -C /tmp/tippecanoe -j2 && sudo make -C /tmp/tippecanoe install - Network accessline 234
Then wire them where the new portal is served: - **Cloudflare** (Arc is on Cloudflare): a [Bulk Redirect list](https://developers.cloudflare.com/rules/url-forwarding/bulk-redirects/), or `_redirects` for Pages-style hosting. - Network accessline 235
- **Cloudflare** (Arc is on Cloudflare): a [Bulk Redirect list](https://developers.cloudflare.com/rules/url-forwarding/bulk-redirects/), or `_redirects` for Pages-style hosting.
skills/portaljs-add-chart/SKILL.md
- Broad permissionsline 1
Read, Write, Edit, Bash(npm:*), Bash(npx:*) - Broad permissionsline 1
Read, Write, Edit, Bash(npm:*), Bash(npx:*) - Network accessline 38
The canonical, full step-by-step workflow is [`.claude/commands/portaljs-add-chart.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-chart.md) — - Network accessline 38
The canonical, full step-by-step workflow is [`.claude/commands/portaljs-add-chart.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-chart.md) — - Network accessline 39
[`.claude/commands/portaljs-add-chart.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-chart.md) — - Network accessline 39
[`.claude/commands/portaljs-add-chart.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-chart.md) — - Network accessline 96
- Full workflow: [`.claude/commands/portaljs-add-chart.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-chart.md) - Network accessline 96
- Full workflow: [`.claude/commands/portaljs-add-chart.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-chart.md) - Network accessline 97
- Chart-type and prop reference: [`references/reference.md`](references/reference.md) - Related skills: `portaljs-add-dataset`, `portaljs-add-map`, `portaljs-define-schema` - recharts documentation: <https://recharts.org/> - Network accessline 97
- Chart-type and prop reference: [`references/reference.md`](references/reference.md) - Related skills: `portaljs-add-dataset`, `portaljs-add-map`, `portaljs-define-schema` - recharts documentation: <https://recharts.org/> - Network accessline 99
- recharts documentation: <https://recharts.org/> - Network accessline 99
- recharts documentation: <https://recharts.org/>
skills/portaljs-add-chart/references/reference.md
- Network accessline 3
Detailed reference for the `portaljs-add-chart` skill. The executable workflow lives in [`.claude/commands/portaljs-add-chart.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-chart.md). - Network accessline 3
Detailed reference for the `portaljs-add-chart` skill. The executable workflow lives in [`.claude/commands/portaljs-add-chart.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-chart.md). - Network accessline 4
[`.claude/commands/portaljs-add-chart.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-chart.md). - Network accessline 4
[`.claude/commands/portaljs-add-chart.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-chart.md).
skills/portaljs-add-dataset/SKILL.md
- Broad permissionsline 1
Read, Write, Edit, Bash(npm:*), Bash(npx:*), Bash(git:*), Bash(curl:*), Bash(mkdir:*), Bash(cp:*), WebFetch - Broad permissionsline 1
Read, Write, Edit, Bash(npm:*), Bash(npx:*), Bash(git:*), Bash(curl:*), Bash(mkdir:*), Bash(cp:*), WebFetch - Network accessline 41
The canonical, full step-by-step workflow is [`.claude/commands/portaljs-add-dataset.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-dataset.md) — - Network accessline 41
The canonical, full step-by-step workflow is [`.claude/commands/portaljs-add-dataset.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-dataset.md) — - Network accessline 42
[`.claude/commands/portaljs-add-dataset.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-dataset.md) — - Network accessline 42
[`.claude/commands/portaljs-add-dataset.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-dataset.md) — - Network accessline 88
Moves the file into `data/`, tracks it with Git LFS, pushes it to R2, and appends a manifest entry whose `file` is the resulting `https://data.portaljs.com/...` URL. - Network accessline 88
Moves the file into `data/`, tracks it with Git LFS, pushes it to R2, and appends a manifest entry whose `file` is the resulting `https://data.portaljs.com/...` URL. - Network accessline 89
entry whose `file` is the resulting `https://data.portaljs.com/...` URL. - Network accessline 89
entry whose `file` is the resulting `https://data.portaljs.com/...` URL. - Network accessline 94
/portaljs-add-dataset https://example.org/open-data/trade.csv namespace=trade - Network accessline 94
/portaljs-add-dataset https://example.org/open-data/trade.csv namespace=trade - Network accessline 102
/portaljs-add-dataset https://example.org/boundaries.geojson namespace=reference adopt=true - Network accessline 102
/portaljs-add-dataset https://example.org/boundaries.geojson namespace=reference adopt=true - Network accessline 117
- Full workflow: [`.claude/commands/portaljs-add-dataset.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-dataset.md) - Network accessline 117
- Full workflow: [`.claude/commands/portaljs-add-dataset.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-dataset.md) - Network accessline 118
- Manifest fields and routing details: [`references/reference.md`](references/reference.md) - Related skills: `portaljs-new-portal`, `portaljs-add-chart`, `portaljs-add-map`, `portaljs-define-schema` - Git LFS documentation: <https://git-lf - Network accessline 118
- Manifest fields and routing details: [`references/reference.md`](references/reference.md) - Related skills: `portaljs-new-portal`, `portaljs-add-chart`, `portaljs-add-map`, `portaljs-define-schema` - Git LFS documentation: <https://git-lf - Network accessline 120
- Git LFS documentation: <https://git-lfs.com/> - Network accessline 120
- Git LFS documentation: <https://git-lfs.com/>
skills/portaljs-add-dataset/references/reference.md
- Network accessline 3
Detailed reference for the `portaljs-add-dataset` skill. The executable workflow lives in [`.claude/commands/portaljs-add-dataset.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-dataset.md). - Network accessline 3
Detailed reference for the `portaljs-add-dataset` skill. The executable workflow lives in [`.claude/commands/portaljs-add-dataset.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-dataset.md). - Network accessline 4
[`.claude/commands/portaljs-add-dataset.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-dataset.md). - Network accessline 4
[`.claude/commands/portaljs-add-dataset.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-dataset.md).
skills/portaljs-add-dcat/SKILL.md
- Broad permissionsline 1
Read, Write, Edit, Bash(npm:*), Bash(npx:*), Bash(node:*), WebFetch - Broad permissionsline 1
Read, Write, Edit, Bash(npm:*), Bash(npx:*), Bash(node:*), WebFetch - Network accessline 44
The canonical, full step-by-step workflow is [`.claude/commands/portaljs-add-dcat.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-dcat.md) — - Network accessline 44
The canonical, full step-by-step workflow is [`.claude/commands/portaljs-add-dcat.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-dcat.md) — - Network accessline 45
[`.claude/commands/portaljs-add-dcat.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-dcat.md) — - Network accessline 45
[`.claude/commands/portaljs-add-dcat.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-dcat.md) — - Network accessline 108
/portaljs-add-dcat profiles=dcat-ap site=https://data.example.org - Network accessline 108
/portaljs-add-dcat profiles=dcat-ap site=https://data.example.org - Network accessline 117
/portaljs-add-dcat profiles=dcat-us site=https://data.example.gov - Network accessline 117
/portaljs-add-dcat profiles=dcat-us site=https://data.example.gov - Network accessline 126
/portaljs-add-dcat profiles=dcat-ap,dcat-ap-de site=https://daten.example.de - Network accessline 126
/portaljs-add-dcat profiles=dcat-ap,dcat-ap-de site=https://daten.example.de - Network accessline 133
- Full workflow: [`.claude/commands/portaljs-add-dcat.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-dcat.md) - Network accessline 133
- Full workflow: [`.claude/commands/portaljs-add-dcat.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-dcat.md) - Network accessline 134
- Profile registry, serialization formats, and validator details: [`references/reference.md`](references/reference.md) - Related skills: `portaljs-define-schema`, `portaljs-new-portal`, `portaljs-deploy`, `portaljs-migrate` - DCAT specifica - Network accessline 134
- Profile registry, serialization formats, and validator details: [`references/reference.md`](references/reference.md) - Related skills: `portaljs-define-schema`, `portaljs-new-portal`, `portaljs-deploy`, `portaljs-migrate` - DCAT specifica - Network accessline 136
- DCAT specification: <https://www.w3.org/TR/vocab-dcat-3/> - Network accessline 136
- DCAT specification: <https://www.w3.org/TR/vocab-dcat-3/>
skills/portaljs-add-dcat/references/reference.md
- Network accessline 3
Detailed reference for the `portaljs-add-dcat` skill. The executable workflow lives in [`.claude/commands/portaljs-add-dcat.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-dcat.md). - Network accessline 3
Detailed reference for the `portaljs-add-dcat` skill. The executable workflow lives in [`.claude/commands/portaljs-add-dcat.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-dcat.md). - Network accessline 4
[`.claude/commands/portaljs-add-dcat.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-dcat.md). - Network accessline 4
[`.claude/commands/portaljs-add-dcat.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-dcat.md). - Network accessline 41
- **DCAT-AP** — EU ITB SHACL validator REST API (`https://www.itb.ec.europa.eu/shacl/dcat-ap/api/validate`), - Network accessline 41
- **DCAT-AP** — EU ITB SHACL validator REST API (`https://www.itb.ec.europa.eu/shacl/dcat-ap/api/validate`), - Network accessline 42
`validationType: dcatap.3_0_1_base` for the harvest gate; or offline with `pip install pyshacl` and the [DCAT-AP SHACL shapes](https://github.com/SEMICeu/DCAT-AP/tree/master/releases). - **DCAT-US** — `pip install pyshacl` + the - Network accessline 42
`validationType: dcatap.3_0_1_base` for the harvest gate; or offline with `pip install pyshacl` and the [DCAT-AP SHACL shapes](https://github.com/SEMICeu/DCAT-AP/tree/master/releases). - **DCAT-US** — `pip install pyshacl` + the - Network accessline 43
and the [DCAT-AP SHACL shapes](https://github.com/SEMICeu/DCAT-AP/tree/master/releases). - Network accessline 43
and the [DCAT-AP SHACL shapes](https://github.com/SEMICeu/DCAT-AP/tree/master/releases). - Network accessline 44
- **DCAT-US** — `pip install pyshacl` + the [DCAT-US 3.0 SHACL shapes](https://raw.githubusercontent.com/DOI-DO/dcat-us/main/shacl/dcat-us_3.0_shacl_shapes.ttl). Requires an IRI-identified `dct:publisher` — a blank-node publisher is rej - Network accessline 44
- **DCAT-US** — `pip install pyshacl` + the [DCAT-US 3.0 SHACL shapes](https://raw.githubusercontent.com/DOI-DO/dcat-us/main/shacl/dcat-us_3.0_shacl_shapes.ttl). Requires an IRI-identified `dct:publisher` — a blank-node publisher is rej - Network accessline 45
[DCAT-US 3.0 SHACL shapes](https://raw.githubusercontent.com/DOI-DO/dcat-us/main/shacl/dcat-us_3.0_shacl_shapes.ttl). - Network accessline 45
[DCAT-US 3.0 SHACL shapes](https://raw.githubusercontent.com/DOI-DO/dcat-us/main/shacl/dcat-us_3.0_shacl_shapes.ttl). - Network accessline 46
Requires an IRI-identified `dct:publisher` — a blank-node publisher is rejected. - **GeoDCAT-AP** — validates as DCAT-AP for the harvest gate; full spatial profile via the [GeoDCAT-AP 3.0.0 SHACL shapes](https://semiceu.github.io/GeoDCAT- - Network accessline 46
Requires an IRI-identified `dct:publisher` — a blank-node publisher is rejected. - **GeoDCAT-AP** — validates as DCAT-AP for the harvest gate; full spatial profile via the [GeoDCAT-AP 3.0.0 SHACL shapes](https://semiceu.github.io/GeoDCAT- - Network accessline 47
- **GeoDCAT-AP** — validates as DCAT-AP for the harvest gate; full spatial profile via the [GeoDCAT-AP 3.0.0 SHACL shapes](https://semiceu.github.io/GeoDCAT-AP/releases/3.0.0/shacl/geodcat-ap-SHACL.ttl) (run with `-i rdfs` to clear subc - Network accessline 47
- **GeoDCAT-AP** — validates as DCAT-AP for the harvest gate; full spatial profile via the [GeoDCAT-AP 3.0.0 SHACL shapes](https://semiceu.github.io/GeoDCAT-AP/releases/3.0.0/shacl/geodcat-ap-SHACL.ttl) (run with `-i rdfs` to clear subc - Network accessline 48
[GeoDCAT-AP 3.0.0 SHACL shapes](https://semiceu.github.io/GeoDCAT-AP/releases/3.0.0/shacl/geodcat-ap-SHACL.ttl) - Network accessline 48
[GeoDCAT-AP 3.0.0 SHACL shapes](https://semiceu.github.io/GeoDCAT-AP/releases/3.0.0/shacl/geodcat-ap-SHACL.ttl) - Network accessline 49
(run with `-i rdfs` to clear subclass-range warnings). - **DCAT-AP_IT** — the AgID SPARQL rules ([italia/daf-semantic-validator](https://github.com/italia/daf-semantic-validator/tree/master/dist/data/ontologies/agid/DCAT-AP_IT/validators/ - Network accessline 49
(run with `-i rdfs` to clear subclass-range warnings). - **DCAT-AP_IT** — the AgID SPARQL rules ([italia/daf-semantic-validator](https://github.com/italia/daf-semantic-validator/tree/master/dist/data/ontologies/agid/DCAT-AP_IT/validators/ - Network accessline 50
- **DCAT-AP_IT** — the AgID SPARQL rules ([italia/daf-semantic-validator](https://github.com/italia/daf-semantic-validator/tree/master/dist/data/ontologies/agid/DCAT-AP_IT/validators/sparql)) run with any SPARQL engine, or `dcat-ap-it v - Network accessline 50
- **DCAT-AP_IT** — the AgID SPARQL rules ([italia/daf-semantic-validator](https://github.com/italia/daf-semantic-validator/tree/master/dist/data/ontologies/agid/DCAT-AP_IT/validators/sparql)) run with any SPARQL engine, or `dcat-ap-it v - Network accessline 51
([italia/daf-semantic-validator](https://github.com/italia/daf-semantic-validator/tree/master/dist/data/ontologies/agid/DCAT-AP_IT/validators/sparql)) - Network accessline 51
([italia/daf-semantic-validator](https://github.com/italia/daf-semantic-validator/tree/master/dist/data/ontologies/agid/DCAT-AP_IT/validators/sparql)) - Network accessline 52
run with any SPARQL engine, or `dcat-ap-it validate` from [ondata/dcat-ap-it-generator](https://github.com/ondata/dcat-ap-it-generator); the official check is https://validatore.dati.gov.it (browser upload). - Network accessline 52
run with any SPARQL engine, or `dcat-ap-it validate` from [ondata/dcat-ap-it-generator](https://github.com/ondata/dcat-ap-it-generator); the official check is https://validatore.dati.gov.it (browser upload). - Network accessline 53
[ondata/dcat-ap-it-generator](https://github.com/ondata/dcat-ap-it-generator); the - Network accessline 53
[ondata/dcat-ap-it-generator](https://github.com/ondata/dcat-ap-it-generator); the - Network accessline 54
official check is https://validatore.dati.gov.it (browser upload). - Network accessline 54
official check is https://validatore.dati.gov.it (browser upload).
skills/portaljs-add-geo/SKILL.md
- Broad permissionsline 1
Read, Write, Edit, Bash(ogr2ogr:*), Bash(ogrinfo:*), Bash(tippecanoe:*), Bash(duckdb:*), Bash(git:*), Bash(curl:*), Bash(npx:*), Bash(node:*), Bash(mkdir:*), Bash(cp:*), Bash(wc:*), Bash(command:*), WebFetch - Broad permissionsline 1
Read, Write, Edit, Bash(ogr2ogr:*), Bash(ogrinfo:*), Bash(tippecanoe:*), Bash(duckdb:*), Bash(git:*), Bash(curl:*), Bash(npx:*), Bash(node:*), Bash(mkdir:*), Bash(cp:*), Bash(wc:*), Bash(command:*), WebFetch - Network accessline 51
The canonical, full step-by-step workflow is [`.claude/commands/portaljs-add-geo.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-geo.md) - Network accessline 51
The canonical, full step-by-step workflow is [`.claude/commands/portaljs-add-geo.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-geo.md) - Network accessline 52
[`.claude/commands/portaljs-add-geo.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-geo.md) - Network accessline 52
[`.claude/commands/portaljs-add-geo.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-geo.md) - Network accessline 58
print the per-OS install and stop. 3. Validate the portal directory and confirm the geo showcase components exist. 4. Fetch (if URL) and detect the input format; reject raster and bare `.shp`. - Network accessline 58
print the per-OS install and stop. 3. Validate the portal directory and confirm the geo showcase components exist. 4. Fetch (if URL) and detect the input format; reject raster and bare `.shp`. - Network accessline 59
3. Validate the portal directory and confirm the geo showcase components exist. 4. Fetch (if URL) and detect the input format; reject raster and bare `.shp`. 5. Preserve the original, then normalize to EPSG:4326 GeoJSON with `ogr2ogr -t_srs - Network accessline 59
3. Validate the portal directory and confirm the geo showcase components exist. 4. Fetch (if URL) and detect the input format; reject raster and bare `.shp`. 5. Preserve the original, then normalize to EPSG:4326 GeoJSON with `ogr2ogr -t_srs - Network accessline 60
4. Fetch (if URL) and detect the input format; reject raster and bare `.shp`. - Network accessline 60
4. Fetch (if URL) and detect the input format; reject raster and bare `.shp`. - Network accessline 106
/portaljs-add-geo source=https://example.com/admin-boundaries.zip slug=admin-boundaries - Network accessline 106
/portaljs-add-geo source=https://example.com/admin-boundaries.zip slug=admin-boundaries - Network accessline 117
- Full workflow: [`.claude/commands/portaljs-add-geo.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-geo.md) - Network accessline 117
- Full workflow: [`.claude/commands/portaljs-add-geo.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-geo.md) - Network accessline 118
- Flags, thresholds, and the dual-tier manifest shape: [`references/reference.md`](references/reference.md) - Related skills: `portaljs-add-dataset`, `portaljs-add-map`, `portaljs-add-resource`, `portaljs-deploy` - tippecanoe: <https://gith - Network accessline 118
- Flags, thresholds, and the dual-tier manifest shape: [`references/reference.md`](references/reference.md) - Related skills: `portaljs-add-dataset`, `portaljs-add-map`, `portaljs-add-resource`, `portaljs-deploy` - tippecanoe: <https://gith - Network accessline 120
- tippecanoe: <https://github.com/felt/tippecanoe> · DuckDB spatial: <https://duckdb.org/docs/extensions/spatial> - Network accessline 120
- tippecanoe: <https://github.com/felt/tippecanoe> · DuckDB spatial: <https://duckdb.org/docs/extensions/spatial>
skills/portaljs-add-geo/references/reference.md
- Network accessline 3
Detailed reference for the `portaljs-add-geo` skill. The executable workflow lives in [`.claude/commands/portaljs-add-geo.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-geo.md). - Network accessline 3
Detailed reference for the `portaljs-add-geo` skill. The executable workflow lives in [`.claude/commands/portaljs-add-geo.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-geo.md). - Network accessline 4
[`.claude/commands/portaljs-add-geo.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-geo.md). - Network accessline 4
[`.claude/commands/portaljs-add-geo.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-geo.md). - Network accessline 14
Install: macOS `brew install gdal tippecanoe duckdb`; Debian/Ubuntu `apt-get install gdal-bin duckdb` plus tippecanoe (apt where available, else build from [felt/tippecanoe](https://github.com/felt/tippecanoe)); Windows is unsupported first - Network accessline 14
Install: macOS `brew install gdal tippecanoe duckdb`; Debian/Ubuntu `apt-get install gdal-bin duckdb` plus tippecanoe (apt where available, else build from [felt/tippecanoe](https://github.com/felt/tippecanoe)); Windows is unsupported first - Network accessline 15
`apt-get install gdal-bin duckdb` plus tippecanoe (apt where available, else build from [felt/tippecanoe](https://github.com/felt/tippecanoe)); Windows is unsupported first-cut — use WSL (Ubuntu) and follow the Debian path. - Network accessline 15
`apt-get install gdal-bin duckdb` plus tippecanoe (apt where available, else build from [felt/tippecanoe](https://github.com/felt/tippecanoe)); Windows is unsupported first-cut — use WSL (Ubuntu) and follow the Debian path. - Network accessline 16
[felt/tippecanoe](https://github.com/felt/tippecanoe)); Windows is unsupported first-cut — - Network accessline 16
[felt/tippecanoe](https://github.com/felt/tippecanoe)); Windows is unsupported first-cut —
skills/portaljs-add-map/SKILL.md
- Broad permissionsline 1
Read, Write, Edit, Bash(npm:*), Bash(npx:*), WebFetch - Broad permissionsline 1
Read, Write, Edit, Bash(npm:*), Bash(npx:*), WebFetch - Network accessline 40
The canonical, full step-by-step workflow is [`.claude/commands/portaljs-add-map.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-map.md) — the - Network accessline 40
The canonical, full step-by-step workflow is [`.claude/commands/portaljs-add-map.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-map.md) — the - Network accessline 41
[`.claude/commands/portaljs-add-map.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-map.md) — the - Network accessline 41
[`.claude/commands/portaljs-add-map.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-map.md) — the - Network accessline 102
/portaljs-add-map source=https://example.com/districts.geojson slug=districts namespace=reference - Network accessline 102
/portaljs-add-map source=https://example.com/districts.geojson slug=districts namespace=reference - Network accessline 107
- Full workflow: [`.claude/commands/portaljs-add-map.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-map.md) - Network accessline 107
- Full workflow: [`.claude/commands/portaljs-add-map.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-map.md) - Network accessline 108
- Map props and troubleshooting reference: [`references/reference.md`](references/reference.md) - Related skills: `portaljs-add-dataset`, `portaljs-add-chart`, `portaljs-define-schema` - react-leaflet documentation: <https://react-leaflet.j - Network accessline 108
- Map props and troubleshooting reference: [`references/reference.md`](references/reference.md) - Related skills: `portaljs-add-dataset`, `portaljs-add-chart`, `portaljs-define-schema` - react-leaflet documentation: <https://react-leaflet.j - Network accessline 110
- react-leaflet documentation: <https://react-leaflet.js.org/> - Network accessline 110
- react-leaflet documentation: <https://react-leaflet.js.org/>
skills/portaljs-add-map/references/reference.md
- Network accessline 3
Detailed reference for the `portaljs-add-map` skill. The executable workflow lives in [`.claude/commands/portaljs-add-map.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-map.md). - Network accessline 3
Detailed reference for the `portaljs-add-map` skill. The executable workflow lives in [`.claude/commands/portaljs-add-map.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-map.md). - Network accessline 4
[`.claude/commands/portaljs-add-map.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-map.md). - Network accessline 4
[`.claude/commands/portaljs-add-map.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-map.md).
skills/portaljs-add-resource/SKILL.md
- Broad permissionsline 1
Read, Write, Edit, Bash(npm:*), Bash(curl:*), Bash(mkdir:*), Bash(cp:*), WebFetch - Broad permissionsline 1
Read, Write, Edit, Bash(npm:*), Bash(curl:*), Bash(mkdir:*), Bash(cp:*), WebFetch - Network accessline 43
The canonical, full step-by-step workflow lives in [`.claude/commands/portaljs-add-resource.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-resource.md) - Network accessline 43
The canonical, full step-by-step workflow lives in [`.claude/commands/portaljs-add-resource.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-resource.md) - Network accessline 44
[`.claude/commands/portaljs-add-resource.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-resource.md) - Network accessline 44
[`.claude/commands/portaljs-add-resource.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-resource.md) - Network accessline 51
2. Validate the portal and locate the dataset entry by slug (and namespace, if given). If the dataset does not exist, offer `/portaljs-add-dataset` instead. 3. Detect the format from extension/Content-Type, fetch (check HTTP status) or - Network accessline 51
2. Validate the portal and locate the dataset entry by slug (and namespace, if given). If the dataset does not exist, offer `/portaljs-add-dataset` instead. 3. Detect the format from extension/Content-Type, fetch (check HTTP status) or - Network accessline 52
given). If the dataset does not exist, offer `/portaljs-add-dataset` instead. 3. Detect the format from extension/Content-Type, fetch (check HTTP status) or confirm the local path exists, then copy into `PORTAL_DIR/public/data/` under a - Network accessline 52
given). If the dataset does not exist, offer `/portaljs-add-dataset` instead. 3. Detect the format from extension/Content-Type, fetch (check HTTP status) or confirm the local path exists, then copy into `PORTAL_DIR/public/data/` under a - Network accessline 53
3. Detect the format from extension/Content-Type, fetch (check HTTP status) or - Network accessline 53
3. Detect the format from extension/Content-Type, fetch (check HTTP status) or - Network accessline 80
| "Dataset not found" | `DATASET` slug/namespace doesn't match any entry in `datasets.json` | List datasets from `datasets.json` and ask the user to pick, or run `/portaljs-add-dataset` to create it | | `npx next build` fails with a JSON pa - Network accessline 80
| "Dataset not found" | `DATASET` slug/namespace doesn't match any entry in `datasets.json` | List datasets from `datasets.json` and ask the user to pick, or run `/portaljs-add-dataset` to create it | | `npx next build` fails with a JSON pa - Network accessline 81
| `npx next build` fails with a JSON parse error | Manually edited `datasets.json` has a trailing comma or unescaped character | Re-open the file, fix the JSON, and rebuild before reporting success | | Resource file fails to fetch (non-2xx) - Network accessline 81
| `npx next build` fails with a JSON parse error | Manually edited `datasets.json` has a trailing comma or unescaped character | Re-open the file, fix the JSON, and rebuild before reporting success | | Resource file fails to fetch (non-2xx) - Network accessline 82
| Resource file fails to fetch (non-2xx) | `SOURCE` URL is wrong, private, or the host is down | Confirm the URL in a browser or with `curl -I SOURCE`; ask for a corrected URL or a local path | - Network accessline 82
| Resource file fails to fetch (non-2xx) | `SOURCE` URL is wrong, private, or the host is down | Confirm the URL in a browser or with `curl -I SOURCE`; ask for a corrected URL or a local path | - Network accessline 99
/portaljs-add-resource climate-observations https://example.org/data/methodology.json --name methodology --title "Methodology notes" - Network accessline 99
/portaljs-add-resource climate-observations https://example.org/data/methodology.json --name methodology --title "Methodology notes" - Network accessline 114
- [`.claude/commands/portaljs-add-resource.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-resource.md) — canonical workflow this skill follows - Network accessline 114
- [`.claude/commands/portaljs-add-resource.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-resource.md) — canonical workflow this skill follows - Network accessline 115
- [`references/reference.md`](references/reference.md) — resource entry fields, single-to-multi-resource layout, troubleshooting - Related skills: `/portaljs-add-dataset` (create a new dataset), `/portaljs-define-schema` (describe a resourc - Network accessline 115
- [`references/reference.md`](references/reference.md) — resource entry fields, single-to-multi-resource layout, troubleshooting - Related skills: `/portaljs-add-dataset` (create a new dataset), `/portaljs-define-schema` (describe a resourc - Network accessline 117
- [Frictionless Data — Data Package resources](https://datapackage.org/standard/data-resource/) — the data model this feature mirrors - Network accessline 117
- [Frictionless Data — Data Package resources](https://datapackage.org/standard/data-resource/) — the data model this feature mirrors
skills/portaljs-add-resource/references/reference.md
- Network accessline 3
Companion reference for the [`/portaljs-add-resource`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-resource.md) command — - Network accessline 3
Companion reference for the [`/portaljs-add-resource`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-resource.md) command — - Network accessline 4
[`/portaljs-add-resource`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-resource.md) command — - Network accessline 4
[`/portaljs-add-resource`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-add-resource.md) command —
skills/portaljs-architect/SKILL.md
- Network accessline 35
## Instructions The canonical, full step-by-step workflow lives in [`.claude/commands/portaljs-architect.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-architect.md) — - Network accessline 35
## Instructions The canonical, full step-by-step workflow lives in [`.claude/commands/portaljs-architect.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-architect.md) — - Network accessline 36
The canonical, full step-by-step workflow lives in [`.claude/commands/portaljs-architect.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-architect.md) — that file is the single source of truth. Follow it when e - Network accessline 36
The canonical, full step-by-step workflow lives in [`.claude/commands/portaljs-architect.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-architect.md) — that file is the single source of truth. Follow it when e - Network accessline 37
[`.claude/commands/portaljs-architect.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-architect.md) — - Network accessline 37
[`.claude/commands/portaljs-architect.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-architect.md) — - Network accessline 103
## Resources - Full workflow: [`.claude/commands/portaljs-architect.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-architect.md) - Network accessline 103
## Resources - Full workflow: [`.claude/commands/portaljs-architect.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-architect.md) - Network accessline 104
- Full workflow: [`.claude/commands/portaljs-architect.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-architect.md) - Network accessline 104
- Full workflow: [`.claude/commands/portaljs-architect.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-architect.md) - Network accessline 105
- Reference: [`references/reference.md`](references/reference.md) - Decision framework: [`site/content/docs/architecture/decision-framework.md`](https://github.com/datopian/portaljs/blob/main/site/content/docs/architecture/decision-framewor - Network accessline 105
- Reference: [`references/reference.md`](references/reference.md) - Decision framework: [`site/content/docs/architecture/decision-framework.md`](https://github.com/datopian/portaljs/blob/main/site/content/docs/architecture/decision-framewor - Network accessline 106
- Decision framework: [`site/content/docs/architecture/decision-framework.md`](https://github.com/datopian/portaljs/blob/main/site/content/docs/architecture/decision-framework.md) - Network accessline 106
- Decision framework: [`site/content/docs/architecture/decision-framework.md`](https://github.com/datopian/portaljs/blob/main/site/content/docs/architecture/decision-framework.md)
skills/portaljs-architect/references/reference.md
- Network accessline 3
Detailed reference for the `portaljs-architect` skill. The executable workflow lives in [`.claude/commands/portaljs-architect.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-architect.md). - Network accessline 3
Detailed reference for the `portaljs-architect` skill. The executable workflow lives in [`.claude/commands/portaljs-architect.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-architect.md). - Network accessline 4
[`.claude/commands/portaljs-architect.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-architect.md). - Network accessline 4
[`.claude/commands/portaljs-architect.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-architect.md).
skills/portaljs-check-data-quality/SKILL.md
- Broad permissionsline 1
Bash(curl:*), Bash(awk:*), Bash(sort:*), Bash(head:*), Bash(wc:*) - Broad permissionsline 1
Bash(curl:*), Bash(awk:*), Bash(sort:*), Bash(head:*), Bash(wc:*) - Network accessline 41
The canonical, full step-by-step workflow is [`.claude/commands/portaljs-check-data-quality.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-check-data-quality.md) — - Network accessline 41
The canonical, full step-by-step workflow is [`.claude/commands/portaljs-check-data-quality.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-check-data-quality.md) — - Network accessline 42
[`.claude/commands/portaljs-check-data-quality.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-check-data-quality.md) — - Network accessline 42
[`.claude/commands/portaljs-check-data-quality.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-check-data-quality.md) — - Network accessline 97
/portaljs-check-data-quality https://example.com/trash.csv - Network accessline 97
/portaljs-check-data-quality https://example.com/trash.csv - Network accessline 121
- Full workflow: [`.claude/commands/portaljs-check-data-quality.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-check-data-quality.md) - Network accessline 121
- Full workflow: [`.claude/commands/portaljs-check-data-quality.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-check-data-quality.md) - Network accessline 122
- Detailed check catalog and troubleshooting: [`references/reference.md`](references/reference.md) - Related skills: `portaljs-add-dataset`, `portaljs-define-schema` - Python `csv` module (parsing behavior this audit relies on): <https://do - Network accessline 122
- Detailed check catalog and troubleshooting: [`references/reference.md`](references/reference.md) - Related skills: `portaljs-add-dataset`, `portaljs-define-schema` - Python `csv` module (parsing behavior this audit relies on): <https://do - Network accessline 124
- Python `csv` module (parsing behavior this audit relies on): <https://docs.python.org/3/library/csv.html> - Network accessline 124
- Python `csv` module (parsing behavior this audit relies on): <https://docs.python.org/3/library/csv.html>
skills/portaljs-check-data-quality/references/reference.md
- Network accessline 3
Detailed reference for the `portaljs-check-data-quality` skill. The executable workflow lives in [`.claude/commands/portaljs-check-data-quality.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-check-data-quality - Network accessline 3
Detailed reference for the `portaljs-check-data-quality` skill. The executable workflow lives in [`.claude/commands/portaljs-check-data-quality.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-check-data-quality - Network accessline 4
[`.claude/commands/portaljs-check-data-quality.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-check-data-quality.md). - Network accessline 4
[`.claude/commands/portaljs-check-data-quality.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-check-data-quality.md).
skills/portaljs-connect-ckan/SKILL.md
- Broad permissionsline 1
Read, Write, Edit, Bash(npm:*), Bash(npx:*), WebFetch - Broad permissionsline 1
Read, Write, Edit, Bash(npm:*), Bash(npx:*), WebFetch - Network accessline 35
- A scaffolded PortalJS portal (see `portaljs-new-portal`) with `package.json`, `pages/`, `datasets.json`, `pages/search.tsx`, and `pages/[owner]/[slug].tsx` present. - A CKAN base URL that is publicly reachable, e.g. `https://demo.dev.da - Network accessline 35
- A scaffolded PortalJS portal (see `portaljs-new-portal`) with `package.json`, `pages/`, `datasets.json`, `pages/search.tsx`, and `pages/[owner]/[slug].tsx` present. - A CKAN base URL that is publicly reachable, e.g. `https://demo.dev.da - Network accessline 36
`datasets.json`, `pages/search.tsx`, and `pages/[owner]/[slug].tsx` present. - A CKAN base URL that is publicly reachable, e.g. `https://demo.dev.datopian.com`. - Node 18+ and npm available in the portal directory (no new packages are insta - Network accessline 36
`datasets.json`, `pages/search.tsx`, and `pages/[owner]/[slug].tsx` present. - A CKAN base URL that is publicly reachable, e.g. `https://demo.dev.datopian.com`. - Node 18+ and npm available in the portal directory (no new packages are insta - Network accessline 37
- A CKAN base URL that is publicly reachable, e.g. `https://demo.dev.datopian.com`. - Network accessline 37
- A CKAN base URL that is publicly reachable, e.g. `https://demo.dev.datopian.com`. - Network accessline 42
The canonical, full step-by-step workflow is [`.claude/commands/portaljs-connect-ckan.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-connect-ckan.md) — - Network accessline 42
The canonical, full step-by-step workflow is [`.claude/commands/portaljs-connect-ckan.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-connect-ckan.md) — - Network accessline 43
[`.claude/commands/portaljs-connect-ckan.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-connect-ckan.md) — - Network accessline 43
[`.claude/commands/portaljs-connect-ckan.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-connect-ckan.md) — - Network accessline 93
/portaljs-connect-ckan url=https://demo.dev.datopian.com - Network accessline 93
/portaljs-connect-ckan url=https://demo.dev.datopian.com - Network accessline 99
/portaljs-connect-ckan url=https://demo.dev.datopian.com org=my-org - Network accessline 99
/portaljs-connect-ckan url=https://demo.dev.datopian.com org=my-org - Network accessline 105
/portaljs-connect-ckan url=https://data.example.gov group=education dir=./my-portal - Network accessline 105
/portaljs-connect-ckan url=https://data.example.gov group=education dir=./my-portal - Network accessline 110
- Full workflow: [`.claude/commands/portaljs-connect-ckan.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-connect-ckan.md) - Network accessline 110
- Full workflow: [`.claude/commands/portaljs-connect-ckan.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-connect-ckan.md) - Network accessline 111
- Client, filters, and troubleshooting reference: [`references/reference.md`](references/reference.md) - Related skills: `portaljs-new-portal`, `portaljs-add-dataset`, `portaljs-deploy` - CKAN Action API documentation: <https://docs.ckan.or - Network accessline 111
- Client, filters, and troubleshooting reference: [`references/reference.md`](references/reference.md) - Related skills: `portaljs-new-portal`, `portaljs-add-dataset`, `portaljs-deploy` - CKAN Action API documentation: <https://docs.ckan.or - Network accessline 113
- CKAN Action API documentation: <https://docs.ckan.org/en/latest/api/> - Network accessline 113
- CKAN Action API documentation: <https://docs.ckan.org/en/latest/api/>
skills/portaljs-connect-ckan/references/reference.md
- Network accessline 3
Detailed reference for the `portaljs-connect-ckan` skill. The executable workflow lives in [`.claude/commands/portaljs-connect-ckan.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-connect-ckan.md). - Network accessline 3
Detailed reference for the `portaljs-connect-ckan` skill. The executable workflow lives in [`.claude/commands/portaljs-connect-ckan.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-connect-ckan.md). - Network accessline 4
[`.claude/commands/portaljs-connect-ckan.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-connect-ckan.md). - Network accessline 4
[`.claude/commands/portaljs-connect-ckan.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-connect-ckan.md).
skills/portaljs-define-schema/SKILL.md
- Broad permissionsline 1
Read, Write, Edit, Bash(npx:*), Bash(node:*), Bash(head:*) - Broad permissionsline 1
Read, Write, Edit, Bash(npx:*), Bash(node:*), Bash(head:*) - Network accessline 55
The canonical, full step-by-step workflow is [`.claude/commands/portaljs-define-schema.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-define-schema.md) — - Network accessline 55
The canonical, full step-by-step workflow is [`.claude/commands/portaljs-define-schema.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-define-schema.md) — - Network accessline 56
[`.claude/commands/portaljs-define-schema.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-define-schema.md) — - Network accessline 56
[`.claude/commands/portaljs-define-schema.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-define-schema.md) — - Network accessline 122
- Full workflow: [`.claude/commands/portaljs-define-schema.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-define-schema.md) - Network accessline 122
- Full workflow: [`.claude/commands/portaljs-define-schema.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-define-schema.md) - Network accessline 123
- Field-type and troubleshooting reference: [`references/reference.md`](references/reference.md) - Related skills: `portaljs-add-dataset`, `portaljs-add-dcat`, `portaljs-check-data-quality` - Frictionless Table Schema specification: <https: - Network accessline 123
- Field-type and troubleshooting reference: [`references/reference.md`](references/reference.md) - Related skills: `portaljs-add-dataset`, `portaljs-add-dcat`, `portaljs-check-data-quality` - Frictionless Table Schema specification: <https: - Network accessline 125
- Frictionless Table Schema specification: <https://datapackage.org/standard/table-schema/> - Network accessline 125
- Frictionless Table Schema specification: <https://datapackage.org/standard/table-schema/>
skills/portaljs-define-schema/references/reference.md
- Network accessline 3
Detailed reference for the `portaljs-define-schema` skill. The executable workflow lives in [`.claude/commands/portaljs-define-schema.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-define-schema.md). - Network accessline 3
Detailed reference for the `portaljs-define-schema` skill. The executable workflow lives in [`.claude/commands/portaljs-define-schema.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-define-schema.md). - Network accessline 4
[`.claude/commands/portaljs-define-schema.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-define-schema.md). - Network accessline 4
[`.claude/commands/portaljs-define-schema.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-define-schema.md).
skills/portaljs-deploy/SKILL.md
- Broad permissionsline 1
Read, Write, Edit, Bash(npm:*), Bash(npx:*), Bash(curl:*) - Broad permissionsline 1
Read, Write, Edit, Bash(npm:*), Bash(npx:*), Bash(curl:*) - Network accessline 22
Publish an existing PortalJS portal to **PortalJS Arc** — Datopian's managed static hosting on Cloudflare. Build a static export, upload it to the Arc API, and print a live `https://SLUG.arc.portaljs.com` URL. Re-running redeploys the same - Network accessline 22
Publish an existing PortalJS portal to **PortalJS Arc** — Datopian's managed static hosting on Cloudflare. Build a static export, upload it to the Arc API, and print a live `https://SLUG.arc.portaljs.com` URL. Re-running redeploys the same - Network accessline 23
hosting on Cloudflare. Build a static export, upload it to the Arc API, and print a live `https://SLUG.arc.portaljs.com` URL. Re-running redeploys the same portal (idempotent on the slug). This is a single-target skill — it deploys to Arc o - Network accessline 23
hosting on Cloudflare. Build a static export, upload it to the Arc API, and print a live `https://SLUG.arc.portaljs.com` URL. Re-running redeploys the same portal (idempotent on the slug). This is a single-target skill — it deploys to Arc o - Network accessline 24
`https://SLUG.arc.portaljs.com` URL. Re-running redeploys the same portal (idempotent on - Network accessline 24
`https://SLUG.arc.portaljs.com` URL. Re-running redeploys the same portal (idempotent on - Network accessline 43
The canonical, full step-by-step workflow is [`.claude/commands/portaljs-deploy.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-deploy.md) — the - Network accessline 43
The canonical, full step-by-step workflow is [`.claude/commands/portaljs-deploy.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-deploy.md) — the - Network accessline 44
[`.claude/commands/portaljs-deploy.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-deploy.md) — the - Network accessline 44
[`.claude/commands/portaljs-deploy.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-deploy.md) — the - Network accessline 65
- **Verified:** `npm run build` exits 0, `out/index.html` exists, the export-hygiene check passes. - **Result:** the portal is live at `https://SLUG.arc.portaljs.com`; re-running updates - Network accessline 65
- **Verified:** `npm run build` exits 0, `out/index.html` exists, the export-hygiene check passes. - **Result:** the portal is live at `https://SLUG.arc.portaljs.com`; re-running updates - Network accessline 66
check passes. - **Result:** the portal is live at `https://SLUG.arc.portaljs.com`; re-running updates the same slug in place. - Network accessline 66
check passes. - **Result:** the portal is live at `https://SLUG.arc.portaljs.com`; re-running updates the same slug in place. - Network accessline 67
- **Result:** the portal is live at `https://SLUG.arc.portaljs.com`; re-running updates - Network accessline 67
- **Result:** the portal is live at `https://SLUG.arc.portaljs.com`; re-running updates - Access to secretsline 99
[Credential-related source omitted] - Access to secretsline 99
[Credential-related source omitted] - Network accessline 105
- Full workflow: [`.claude/commands/portaljs-deploy.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-deploy.md) - Network accessline 105
- Full workflow: [`.claude/commands/portaljs-deploy.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-deploy.md) - Network accessline 106
- Deploy internals reference: [`references/reference.md`](references/reference.md) - Related skills: `portaljs-new-portal`, `portaljs-add-dataset`, `portaljs-connect-ckan` - PortalJS Arc dashboard (sign in, manage tokens): <https://arc.port - Network accessline 106
- Deploy internals reference: [`references/reference.md`](references/reference.md) - Related skills: `portaljs-new-portal`, `portaljs-add-dataset`, `portaljs-connect-ckan` - PortalJS Arc dashboard (sign in, manage tokens): <https://arc.port - Network accessline 108
- PortalJS Arc dashboard (sign in, manage tokens): <https://arc.portaljs.com> - Network accessline 108
- PortalJS Arc dashboard (sign in, manage tokens): <https://arc.portaljs.com>
skills/portaljs-deploy/references/reference.md
- Network accessline 3
Detailed reference for the `portaljs-deploy` skill. The executable workflow lives in [`.claude/commands/portaljs-deploy.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-deploy.md). - Network accessline 3
Detailed reference for the `portaljs-deploy` skill. The executable workflow lives in [`.claude/commands/portaljs-deploy.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-deploy.md). - Network accessline 4
[`.claude/commands/portaljs-deploy.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-deploy.md). - Network accessline 4
[`.claude/commands/portaljs-deploy.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-deploy.md). - Network accessline 26
[Credential-related source omitted] - Network accessline 26
[Credential-related source omitted] - Network accessline 27
[Credential-related source omitted] - Network accessline 27
[Credential-related source omitted] - Network accessline 28
| `PORTALJS_ARC_API` | `https://api.arc.portaljs.com` | Deploy/whoami API base; override for staging. | - Network accessline 28
| `PORTALJS_ARC_API` | `https://api.arc.portaljs.com` | Deploy/whoami API base; override for staging. | - Network accessline 29
| `PORTALJS_ARC_AUTH` | `https://arc.portaljs.com` | Device-authorization worker; override for staging. | - Network accessline 29
| `PORTALJS_ARC_AUTH` | `https://arc.portaljs.com` | Device-authorization worker; override for staging. | - Network accessline 75
skill skips the gate automatically rather than failing. - **Repeated 401 after re-login** — the token was revoked server-side; sign in again at <https://arc.portaljs.com> and confirm the account owns the slug. - Network accessline 75
skill skips the gate automatically rather than failing. - **Repeated 401 after re-login** — the token was revoked server-side; sign in again at <https://arc.portaljs.com> and confirm the account owns the slug. - Network accessline 76
- **Repeated 401 after re-login** — the token was revoked server-side; sign in again at <https://arc.portaljs.com> and confirm the account owns the slug. - **Upload times out** — the tarball is large; check `check-export` output for files - Network accessline 76
- **Repeated 401 after re-login** — the token was revoked server-side; sign in again at <https://arc.portaljs.com> and confirm the account owns the slug. - **Upload times out** — the tarball is large; check `check-export` output for files - Network accessline 77
<https://arc.portaljs.com> and confirm the account owns the slug. - Network accessline 77
<https://arc.portaljs.com> and confirm the account owns the slug.
skills/portaljs-migrate/SKILL.md
- Broad permissionsline 1
Read, Write, Edit, Bash(npm:*), Bash(npx:*), Bash(node:*), Bash(curl:*), Bash(git:*), WebFetch - Broad permissionsline 1
Read, Write, Edit, Bash(npm:*), Bash(npx:*), Bash(node:*), Bash(curl:*), Bash(git:*), WebFetch - Access to secretsline 44
[Credential-related source omitted] - Access to secretsline 44
[Credential-related source omitted] - Network accessline 52
Full step-by-step workflow: [`.claude/commands/portaljs-migrate.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-migrate.md). - Network accessline 52
Full step-by-step workflow: [`.claude/commands/portaljs-migrate.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-migrate.md). - Network accessline 53
[`.claude/commands/portaljs-migrate.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-migrate.md). - Network accessline 53
[`.claude/commands/portaljs-migrate.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-migrate.md). - Access to secretsline 85
[Credential-related source omitted] - Access to secretsline 85
[Credential-related source omitted] - Network accessline 97
/portaljs-migrate --source ckan --source-url https://demo.dev.datopian.com \ - Network accessline 97
/portaljs-migrate --source ckan --source-url https://demo.dev.datopian.com \ - Network accessline 106
/portaljs-migrate --source dcat --source-url https://catalog.data.gov/data.json \ --target static --copy-mode download --org-filter epa-gov - Network accessline 106
/portaljs-migrate --source dcat --source-url https://catalog.data.gov/data.json \ --target static --copy-mode download --org-filter epa-gov - Network accessline 115
/portaljs-migrate --source dcat-rdf \ --source-url https://data.europa.eu/api/hub/search/catalog.jsonld \ - Network accessline 115
/portaljs-migrate --source dcat-rdf \ --source-url https://data.europa.eu/api/hub/search/catalog.jsonld \ - Network accessline 116
--source-url https://data.europa.eu/api/hub/search/catalog.jsonld \ - Network accessline 116
--source-url https://data.europa.eu/api/hub/search/catalog.jsonld \ - Network accessline 125
/portaljs-migrate --source ckan --source-url https://old-portal.example.org \ - Network accessline 125
/portaljs-migrate --source ckan --source-url https://old-portal.example.org \ - Network accessline 126
--target ckan --target-url https://new-portal.example.org --owner-org research - Network accessline 126
--target ckan --target-url https://new-portal.example.org --owner-org research - Network accessline 133
- Command source: [`.claude/commands/portaljs-migrate.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-migrate.md) - Network accessline 133
- Command source: [`.claude/commands/portaljs-migrate.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-migrate.md) - Network accessline 135
- 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/ - Network accessline 135
- 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/ - Network accessline 137
- CKAN Action API reference: https://docs.ckan.org/en/latest/api/ - Network accessline 137
- CKAN Action API reference: https://docs.ckan.org/en/latest/api/
skills/portaljs-migrate/references/reference.md
- Network accessline 3
Field mappings, sink options, and troubleshooting detail for the [`/portaljs-migrate`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-migrate.md) command. Read the - Network accessline 3
Field mappings, sink options, and troubleshooting detail for the [`/portaljs-migrate`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-migrate.md) command. Read the - Network accessline 4
[`/portaljs-migrate`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-migrate.md) command. Read the - Network accessline 4
[`/portaljs-migrate`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-migrate.md) command. Read the - Access to secretsline 30
[Credential-related source omitted] - Access to secretsline 30
[Credential-related source omitted]
skills/portaljs-new-portal/SKILL.md
- Broad permissionsline 1
Read, Write, Edit, Bash(npm:*), Bash(npx:*), Bash(cp:*), Bash(mkdir:*), Bash(git:*) - Broad permissionsline 1
Read, Write, Edit, Bash(npm:*), Bash(npx:*), Bash(cp:*), Bash(mkdir:*), Bash(git:*) - Network accessline 40
The canonical, full step-by-step workflow is [`.claude/commands/portaljs-new-portal.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-new-portal.md) — - Network accessline 40
The canonical, full step-by-step workflow is [`.claude/commands/portaljs-new-portal.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-new-portal.md) — - Network accessline 41
[`.claude/commands/portaljs-new-portal.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-new-portal.md) — - Network accessline 41
[`.claude/commands/portaljs-new-portal.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-new-portal.md) — - Network accessline 123
- Full workflow: [`.claude/commands/portaljs-new-portal.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-new-portal.md) - Network accessline 123
- Full workflow: [`.claude/commands/portaljs-new-portal.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-new-portal.md) - Network accessline 124
- Template and token reference: [`references/reference.md`](references/reference.md) - Related skills: `portaljs-add-dataset`, `portaljs-add-chart`, `portaljs-add-map`, `portaljs-connect-ckan` - PortalJS documentation: <https://portaljs.org - Network accessline 124
- Template and token reference: [`references/reference.md`](references/reference.md) - Related skills: `portaljs-add-dataset`, `portaljs-add-chart`, `portaljs-add-map`, `portaljs-connect-ckan` - PortalJS documentation: <https://portaljs.org - Network accessline 126
- PortalJS documentation: <https://portaljs.org> - Network accessline 126
- PortalJS documentation: <https://portaljs.org>
skills/portaljs-new-portal/references/reference.md
- Network accessline 3
Detailed reference for the `portaljs-new-portal` skill. The executable workflow lives in [`.claude/commands/portaljs-new-portal.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-new-portal.md). - Network accessline 3
Detailed reference for the `portaljs-new-portal` skill. The executable workflow lives in [`.claude/commands/portaljs-new-portal.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-new-portal.md). - Network accessline 4
[`.claude/commands/portaljs-new-portal.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-new-portal.md). - Network accessline 4
[`.claude/commands/portaljs-new-portal.md`](https://github.com/datopian/portaljs/blob/main/.claude/commands/portaljs-new-portal.md). - Network accessline 49
The skill defaults to a **remote** fetch (`npx tiged "datopian/portaljs/examples/portaljs-catalog#main"`) - Network accessline 49
The skill defaults to a **remote** fetch (`npx tiged "datopian/portaljs/examples/portaljs-catalog#main"`)
How the signals fit together
Facts from a static read of the files at the pinned commit. They describe what the code does, not why.
Some files could not be read; the facts below still hold.
Signal confidence: 500 facts
- Broad permissions in prose of documentation.claude/commands/arcgis-to-portaljs.md:1Low confidence
- Network access in prose of documentation.claude/commands/arcgis-to-portaljs.md:16Low confidence
- Network access in prose of documentation.claude/commands/arcgis-to-portaljs.md:17Low confidence
- Network access in prose of documentation.claude/commands/arcgis-to-portaljs.md:52Low confidence
- Network access in prose of documentation.claude/commands/arcgis-to-portaljs.md:53Low confidence
- Network access in code of documentation.claude/commands/arcgis-to-portaljs.md:65Low confidence
- Network access in code of documentation.claude/commands/arcgis-to-portaljs.md:66Low confidence
- Network access in code of documentation.claude/commands/arcgis-to-portaljs.md:67Low confidence
- Dangerous shell operation in code of documentation.claude/commands/arcgis-to-portaljs.md:95Low confidence
- Network access in code of documentation.claude/commands/arcgis-to-portaljs.md:115Low confidence
- Network access in prose of documentation.claude/commands/arcgis-to-portaljs.md:188Low confidence
- Network access in prose of documentation.claude/commands/arcgis-to-portaljs.md:189Low confidence
- Network access in code of documentation.claude/commands/arcgis-to-portaljs.md:194Low confidence
- Network access in code of documentation.claude/commands/arcgis-to-portaljs.md:195Low confidence
- Network access in code of documentation.claude/commands/arcgis-to-portaljs.md:196Low confidence
- Network access in code of documentation.claude/commands/arcgis-to-portaljs.md:253Low confidence
- Network access in code of documentation.claude/commands/arcgis-to-portaljs.md:254Low confidence
- Network access in code of documentation.claude/commands/arcgis-to-portaljs.md:255Low confidence
- Network access in code of documentation.claude/commands/arcgis-to-portaljs.md:274Low confidence
- Network access in code of documentation.claude/commands/arcgis-to-portaljs.md:275Low confidence
- Network access in code of documentation.claude/commands/arcgis-to-portaljs.md:276Low confidence
- Network access in code of documentation.claude/commands/arcgis-to-portaljs.md:277Low confidence
- Network access in code of documentation.claude/commands/arcgis-to-portaljs.md:278Low confidence
- Network access in code of documentation.claude/commands/arcgis-to-portaljs.md:281Low confidence
- Network access in code of documentation.claude/commands/arcgis-to-portaljs.md:282Low confidence
- Network access in code of documentation.claude/commands/arcgis-to-portaljs.md:283Low confidence
- Network access in code of documentation.claude/commands/arcgis-to-portaljs.md:290Low confidence
- Network access in code of documentation.claude/commands/arcgis-to-portaljs.md:291Low confidence
- Network access in code of documentation.claude/commands/arcgis-to-portaljs.md:292Low confidence
- Network access in prose of documentation.claude/commands/arcgis-to-portaljs.md:320Low confidence
- Network access in prose of documentation.claude/commands/arcgis-to-portaljs.md:321Low confidence
- Network access in prose of documentation.claude/commands/arcgis-to-portaljs.md:353Low confidence
- Network access in prose of documentation.claude/commands/arcgis-to-portaljs.md:354Low confidence
- Network access in prose of documentation.claude/commands/arcgis-to-portaljs.md:355Low confidence
- Network access in prose of documentation.claude/commands/arcgis-to-portaljs.md:462Low confidence
- Network access in prose of documentation.claude/commands/arcgis-to-portaljs.md:464Low confidence
- Network access in prose of documentation.claude/commands/arcgis-to-portaljs.md:503Low confidence
- Network access in prose of documentation.claude/commands/arcgis-to-portaljs.md:505Low confidence
- Network access in prose of documentation.claude/commands/arcgis-to-portaljs.md:570Low confidence
- Network access in prose of documentation.claude/commands/arcgis-to-portaljs.md:571Low confidence
- Network access in prose of documentation.claude/commands/arcgis-to-portaljs.md:572Low confidence
- Network access in code of documentation.claude/commands/arcgis-to-portaljs.md:580Low confidence
- Network access in code of documentation.claude/commands/arcgis-to-portaljs.md:581Low confidence
- Network access in prose of documentation.claude/commands/arcgis-to-portaljs.md:636Low confidence
- Network access in prose of documentation.claude/commands/arcgis-to-portaljs.md:637Low confidence
- Network access in prose of documentation.claude/commands/arcgis-to-portaljs.md:638Low confidence
- Broad permissions in prose of documentation.claude/commands/portaljs-add-chart.md:1Low confidence
- Network access in code of documentation.claude/commands/portaljs-add-chart.md:137Low confidence
- Network access in code of documentation.claude/commands/portaljs-add-chart.md:138Low confidence
- Network access in code of documentation.claude/commands/portaljs-add-chart.md:139Low confidence
and 450 more
Only the first 500 facts are listed.
Works with
| Agent | Status | Evidence | Install to |
|---|---|---|---|
| Claude Code | Native | Manifest .claude-plugin/marketplace.json | .claude/skills/<skill-name>/ |
| Codex | Native | Manifest AGENTS.md | .agents/skills/<skill-name>/ |
| Cursor | Compatible | Standard SKILL.md skills/arcgis-to-portaljs/SKILL.md | .cursor/skills/<skill-name>/ |
| Gemini CLI | Compatible | Standard SKILL.md skills/arcgis-to-portaljs/SKILL.md | .gemini/skills/<skill-name>/ |
| GitHub Copilot | Compatible | Standard SKILL.md skills/arcgis-to-portaljs/SKILL.md | .github/skills/<skill-name>/ |
| OpenCode | Compatible | Standard SKILL.md skills/arcgis-to-portaljs/SKILL.md | .opencode/skills/<skill-name>/ |
- Native The repository ships a manifest, folder or frontmatter field for this agent.
- Compatible A standard SKILL.md that this agent can read.
- Unknown No evidence either way.
Derived automatically from paths, manifests and frontmatter. Not tested on each agent.
Explore alternatives and comparisons
Add this badge to your README
It updates every night and links to this page.
[](https://hotskills.dev/skill/datopian-portaljs/)