SuperAPI AI Directory

portolan-cli

Data & analytics

View repository

Updated 10-16 04:39

About this skill

Portolan CLI

Publish and manage cloud-native geospatial data catalogs.

Portolan is a CLI for publishing and managing cloud-native geospatial data catalogs. It orchestrates format conversion (GeoParquet, COG), versioning, and sync to object storage (S3, GCS, Azure) — no running servers, just static files.

Specification: The Portolan Spec defines catalog structure, format requirements, and versioning rules. When in doubt about requirements, read the spec files directly (core.md, structure.md, versions.md, formats/vector.md, formats/raster.md, formats/pointcloud.md, best-practices.md) for the most up-to-date information.

Key concepts:

  • STAC (SpatioTemporal Asset Catalog) — The catalog metadata spec. Portolan is a STAC profile, not a competing spec.
  • GeoParquet — Cloud-optimized vector data (columnar, spatial indexing)
  • COG (Cloud-Optimized GeoTIFF) — Cloud-optimized raster data (HTTP range requests)
  • COPC (Cloud-Optimized Point Cloud) — Cloud-optimized point cloud data
  • PMTiles — Cloud-optimized vector/raster tiles for web map rendering
  • versions.json — Single source of truth for version history, sync state, and checksums

Installation

pipx install portolan-cli    # Isolated (recommended)
pip install portolan-cli     # Or with pip
uv pip install portolan-cli  # Or with uv

If portolan is not installed, guide the user through installation before proceeding.

Catalog Structure

Portolan catalogs use a flat hierarchy with STAC metadata:

project/
├── .portolan/
│   ├── config.yaml              # Internal config (sentinel file)
│   └── state.json               # Local sync state
├── catalog.json                 # STAC Catalog (root metadata)
├── versions.json                # Catalog-level version tracking
└── {collection_id}/
    ├── collection.json          # STAC Collection metadata
    ├── versions.json            # Collection-level versioning
    ├── {data}.parquet           # Single-file collection asset
    ├── {data}.pmtiles           # Visualization derivative
    └── thumbnail.png            # Preview image

Single-file collections (one GeoParquet/COG) use collection-level assets directly — no item directory needed.

Partitioned collections (>2GB) use item subdirectories per partition.

All STAC links use relative paths (SELF_CONTAINED) — catalogs are portable across hosting locations.

CLI Commands

portolan init

Initialize a new Portolan catalog.

portolan init                       # Initialize in current directory
portolan init --auto                # Skip prompts, use defaults
portolan init --title "My Catalog"  # Set title
portolan init /path/to/data --auto  # Initialize in specific directory

portolan scan

Scan a directory for geospatial files and potential issues.

portolan scan                         # Scan current directory
portolan scan --json                  # JSON output
portolan scan /data/geospatial
portolan scan /large/tree --max-depth=2

portolan check

Validate a Portolan catalog or check files for cloud-native status.

portolan check                        # Validate all (metadata + geo-assets)
portolan check --metadata             # Validate metadata only
portolan check --geo-assets           # Check geo-assets only
portolan check --fix                  # Fix both metadata and geo-assets

portolan add

Track files in the catalog.

portolan add demographics/census.parquet
portolan add file1.geojson file2.geojson   # Add multiple files
portolan add imagery/                      # Add all files in directory
portolan add .                             # Add all files in catalog

portolan push

Push local catalog changes to cloud object storage.

portolan push s3://mybucket/catalog --collection demographics
portolan push gs://mybucket/catalog -c imagery --dry-run
portolan push s3://mybucket/catalog
portolan push --dry-run  # Uses configured remote

portolan pull

Pull updates from a remote catalog.

portolan pull s3://mybucket/my-catalog --collection demographics
portolan pull s3://mybucket/catalog -c imagery --dry-run
portolan pull s3://mybucket/catalog
portolan pull s3://mybucket/catalog --workers 4

portolan sync

Sync local catalog with remote storage (pull + push).

portolan sync s3://mybucket/catalog --collection demographics
portolan sync s3://mybucket/catalog -c imagery --dry-run
portolan sync s3://mybucket/catalog -c data --fix --force

portolan clone

Clone a remote catalog to a local directory.

portolan clone s3://mybucket/my-catalog
portolan clone s3://mybucket/my-catalog .
portolan clone s3://mybucket/catalog -c demographics

portolan status

Show local vs remote version state for collections.

portolan status                    # Status for all collections
portolan status -c demographics    # Status for one collection
portolan status --offline          # Skip remote check
portolan status --json             # JSON output for agents

portolan list

List all files in the catalog with tracking status.

portolan list                           # List all files with status
portolan list --collection demographics # Filter by collection
portolan list --tracked-only            # Show only tracked files

portolan info

Show information about a file, collection, or catalog.

portolan info demographics/census.parquet  # File info
portolan info demographics/                # Collection info
portolan info                              # Catalog info
portolan info demographics/census.parquet --json

portolan rm

Remove files from tracking.

portolan rm --keep imagery/old_data.tif     # Safe: untrack only
portolan rm --dry-run vectors/              # Preview
portolan rm -f demographics/census.parquet  # Force delete and untrack

portolan partition

Partition a large GeoParquet file for better query performance.

portolan partition buildings.parquet --preview
portolan partition buildings.parquet output/
portolan partition buildings.parquet output/ --target-rows 50000

portolan extract

Extract data from external sources into Portolan catalogs.

portolan extract arcgis https://services.arcgis.com/.../FeatureServer ./output
portolan extract arcgis URL --layers "Census*" --dry-run
portolan extract arcgis URL --filter "sdn_*" --resume

portolan metadata

Manage catalog metadata for README generation.

portolan metadata init                # Create template at catalog root
portolan metadata init demographics   # Create template for collection
portolan metadata validate            # Validate metadata.yaml

portolan readme

Generate README.md from STAC metadata and metadata.yaml.

portolan readme                    # Generate at catalog root
portolan readme demographics       # Generate for collection
portolan readme --stdout           # Print without writing
portolan readme --check            # CI mode: exit 1 if stale

portolan stac-geoparquet

Generate items.parquet for efficient STAC queries.

portolan stac-geoparquet                       # Generate for ALL collections
portolan stac-geoparquet -c landsat            # Generate for one collection
portolan stac-geoparquet -c imagery --dry-run  # Preview

portolan config

Manage catalog configuration.

portolan config set backend iceberg
portolan config get remote
portolan config list

portolan clean

Remove all Portolan metadata while preserving data files.

portolan clean           # Remove all metadata
portolan clean --dry-run # Preview what would be removed

Common Workflows

Publishing a New Catalog

portolan init --title "My Geospatial Data"
portolan scan /data/geospatial
portolan check --geo-assets --fix    # Convert to cloud-native formats
portolan add demographics/
portolan push s3://mybucket/my-catalog --collection demographics

Full Sync (Recommended)

Single command: pull -> init -> scan -> check -> push:

portolan sync s3://mybucket/my-catalog --collection demographics
portolan sync s3://mybucket/my-catalog -c demographics --fix

Versioning

Versions follow Semantic Versioning per collection:

  • Major: Breaking changes (schema changes, column removals, CRS changes)
  • Minor: New features (new columns, new items)
  • Patch: Data updates (same schema, new data)

Each collection's versions.json tracks version history with SHA-256 checksums per asset.

JSON Output

All commands support --json or --format json:

portolan scan . --json
portolan check --format json
portolan --format json init --auto

Consistent envelope: {"success": true, "command": "...", "data": {...}, "errors": []}.

Python API

from portolan_cli import Catalog, FormatType, detect_format

catalog = Catalog("/path/to/data")
format_type = detect_format("data.parquet")  # Returns FormatType.GEOPARQUET

Troubleshooting

Error Solution
"Not inside a Portolan catalog" Run portolan init or navigate into existing catalog
"Catalog already exists" Remove catalog.json and .portolan/ to reinitialize
"Push conflict: remote has newer version" Run portolan pull first, or --force to overwrite
"Pull blocked by uncommitted changes" Push local changes first, or --force to discard
Shapefile missing components Ensure .shp, .shx, .dbf files are all present
Non-cloud-native files Use portolan check --fix to convert (vectors -> GeoParquet, rasters -> COG)