sourcecoop
Skill11 starsChanged 30 days agoApache-2.0View on GitHub
Upload geospatial data to Source Cooperative with proper metadata and READMEs using Portolan CLI.
- Reads credentials
- Installs packages
1 other project uses a version of this.
Adopted by
Most recently taken up by
- isaaccorley/geospatial-skillstheir own version, first seen Mar 19, 2026
Other versions1 project uses a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 1
- isaaccorley/geospatial-skills★ 78same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository13 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- catalog-graderSkill
- customize-portolan-browserSkill
- enrich-metadataSkill
- git-backed-catalogSkill
- portolan-bootstrapSkill
- portolan-cliSkill
- portolan-migrateSkill
- portolan-thumbnailsSkill
- reading-portolanSkill
- register-catalogSkill
- report-catalog-issueSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
17 rules. About 0 are common, 4 are distinctive, and 13 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
13
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- could be automatic: a setting could enforce it
- Very specific: line 36
Write metadata: contact, license, providers, source_url.
- Distinctive: line 38
Run the validator locally.
- Distinctive: line 43
Ask the user for:
- Very specific: line 56
Do not use a regional bucket such as s3://us-west-2.opendata.source.coop/{org}/{product}/ or …
- Distinctive: line 73
Run the second command on the server.
- Very specific: line 141
Add --pmtiles for vector collections so the catalog provides a render path (PORTO-CORE-065).
- Very specific: line 171
Never hand-edit a generated README.
- Distinctive: line 200
Read the PTL rule ids in the output.
- Very specific: line 214
After the push, probe the published host.
- Very specific: line 235
Check that .env sets PORTOLAN_S3_ENDPOINT=https://data.source.coop.
- Very specific: line 236
Check that PORTOLAN_REMOTE takes the form s3://{org}/{product}/.
- Very specific: line 242
Run source-coop creds. When its error includes Run 'source-coop login', run source-coop login.
- Very specific: line 243
Run eval "$(source-coop creds --format env)" again in the shell you push from.
- Very specific: line 244
Check that PORTOLAN_REMOTE names the organization and the repository you have write access to.
- Very specific: line 251
Remove PORTOLAN_PROFILE from .env and from the shell, and remove --profile from the command.
- Very specific: line 252
Run eval "$(source-coop creds --format env)" in the shell you push from.
- Very specific: line 273
Run portolan metadata validate.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
<!-- drift: depends-on: portolan-cli, rashid, portolan-spec, source-coop-cli -->Source Cooperative Upload Skill
You are helping a user publish a Portolan catalog to Source Cooperative, an open data commons for geospatial data. This skill covers the upload path. To build the catalog from a data source, use the portolan-bootstrap skill first, then return here.
The Portolan spec is ground truth. The CLI and the validator implement it. Run portolan <cmd> --help for the flags of any command below. Do not restate the help text in your answers.
Prerequisites
Source Cooperative serves its object storage through a data proxy at data.source.coop. The source-coop CLI authenticates you against the proxy and issues temporary S3 credentials. Check for it first:
source-coop --versionThis skill describes version 0.3.0. An older version does not refresh expired credentials. Install it with Homebrew, or with the installer script the CLI README documents:
brew install source-cooperative/tap/source-coopYou also need a Source Cooperative account with write access to the repository. The user without access requests it at hello@source.coop.
Workflow Overview
- Gather the organization and product names.
- Log in with
source-coop, set the remote and the endpoint in.env, and export the credentials. - Initialize the catalog with a license.
- Add files.
- Write metadata: contact, license, providers,
source_url. - Generate READMEs and write
AGENTS.md. - Run the validator locally.
- Push, then probe the published host.
Step 1: Gather Information
Ask the user for:
- The Source Cooperative organization slug (required). Examples:
nlebovits,radiant-mlhub,vida. - The product name (optional). Defaults to the current directory name.
The proxy addresses the account as the bucket and the repository as the key prefix. Build the remote URL from them:
s3://{org}/{product}/The same URL form works for every storage region. Source Cooperative stores repositories in more than one region, such as us-west-2, ca-central-1, and an Azure region in West Europe. The proxy finds the region of the repository. The remote contains no region.
Do not use a regional bucket such as s3://us-west-2.opendata.source.coop/{org}/{product}/ or s3://ca-central-1.opendata.source.coop/{org}/{product}/. The source-coop credentials are valid only at the proxy. AWS rejects them at a regional bucket with InvalidAccessKeyId.
Step 2: Log in and set the remote
source-coop login opens a browser for the OAuth2 authorization code flow. It caches the temporary credentials and a refresh token in the OS keyring:
source-coop loginlogin receives the OAuth2 redirect on a local port. On a machine with no browser, forward a port over SSH and give the same port to login:
ssh -L 8400:127.0.0.1:8400 user@server
source-coop login --port 8400Run the second command on the server. Open the URL that it prints in a local browser.
The remote
The remote is the destination that portolan push writes to. The proxy addresses the account as the bucket and the repository as the key prefix. portolan push reads the destination from PORTOLAN_REMOTE when you give it no argument.
The CLI refuses to store remote, profile, region, and s3_endpoint in .portolan/config.yaml. That file is pushed with the catalog. Put the remote and the proxy endpoint in .env at the catalog root. portolan push excludes .env from the upload.
cat > .env << 'EOF'
PORTOLAN_REMOTE=s3://{org}/{product}/
PORTOLAN_S3_ENDPOINT=https://data.source.coop
EOF
portolan config listconfig list shows remote and s3_endpoint with (from env). Without the endpoint, the push goes to AWS and fails with InvalidAccessKeyId.
The credentials
portolan push reads the credentials from the AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN environment variables. Export them in the shell you push from:
eval "$(source-coop creds --format env)"The credentials expire, and the shell keeps the old values. source-coop creds refreshes expired credentials from the cached refresh token. When an upload fails with AccessDenied or 403 Forbidden, run the eval line again.
Do not set PORTOLAN_PROFILE, and do not pass --profile to portolan push. portolan-cli 0.8.0 reads a named profile only from ~/.aws/credentials. It ignores credential_process and endpoint_url in ~/.aws/config. A profile name other than default also discards the credentials that the eval line set. The push then finds no credentials and stalls against the instance metadata service at 169.254.169.254.
The AWS profile for other tools
The aws CLI, boto3, rclone, and DuckDB run credential_process from ~/.aws/config. The Source Cooperative docs give this profile:
[profile source-coop]
credential_process = source-coop creds
endpoint_url = https://data.source.coopportolan push does not use this profile. Use it to list the prefix and to confirm what the push wrote:
aws s3 ls s3://{org}/{product}/ --profile source-coop --recursiveStep 3: Initialize Catalog
portolan init requires a license. With --auto and no --license, it exits with PRTLN-VAL004. Every collection inherits the catalog license, and portolan add refuses a collection without one.
portolan init --title "{product_title}" --auto --license CC-BY-4.0
portolan infoinit writes catalog.json, AGENTS.md, and README.md beside each other, linked with rel: agents and rel: describedby (PORTO-CORE-005, PORTO-CORE-061, PORTO-CORE-062). It also writes versions.json. That file is a CLI artifact, not part of the spec.
Step 4: add files
Files must sit in collection subdirectories. Files at the catalog root are skipped.
mkdir -p buildings
mv *.parquet buildings/
portolan add .Add --pmtiles for vector collections so the catalog provides a render path (PORTO-CORE-065). The CLI writes the PMTiles as a rel: pmtiles link with a pmtiles:layers array (PORTO-FMT-011) and a default style asset under styles/.
Step 5: write metadata
portolan metadata init writes a .portolan/metadata.yaml template at every STAC level. portolan metadata validate requires contact.name, contact.email, and license. The CLI requires no other field. The spec requires more.
Fill these fields at every level:
contact: name and email of the maintainer.license: an SPDX identifier.providers: at least oneproducer, the organization that created the data (PORTO-CORE-047). Thehostis whoever maintains this catalog, not AWS or Source Cooperative. Leave the host out and the CLI derives it fromcontact. The host needs aurlor anemail(PORTO-CORE-051).source_url: the page the data came from.
Most Source Cooperative uploads are mirrors. The producer and the host differ. For a mirror, the spec requires a via link of type text/html to the original source (PORTO-CORE-053) and a top-level updated field set at each sync (PORTO-CORE-057). The CLI derives both from providers and source_url when you run portolan add. When the source publishes its own STAC catalog, add a canonical link to that STAC root as well (PORTO-CORE-054).
Temporal defaults for items without a date live under defaults.temporal in the same file. There is no temporal_extent key.
Recommended fields: keywords, citation, attribution, processing_notes, and known_issues.
portolan metadata init
portolan metadata validateStep 6: Generate READMEs and write AGENTS.md
portolan readmeNever hand-edit a generated README. Edit .portolan/metadata.yaml and regenerate. PORTO-CORE-063 requires four things in the README:
- the title
- the description
- the license
- the data provenance
AGENTS.md is not generated from metadata. The CLI scaffolds a stub. Replace the stub at the catalog and at every collection with real content. Describe the data, explain how the files connect, and show queries you ran against the data. Follow the portolan-bootstrap skill and specs/best-practices/documentation.md for what belongs there.
Linking to Source Cooperative
Source Cooperative serves the same objects under two hostnames. source.coop renders a page a person can read. data.source.coop returns raw bytes.
source.coop: the human-facing host. Use it inmetadata.yamllinks, STACdescriptionfields, generated READMEs, and issue and pull request bodies.data.source.coop: STAC assethrefvalues,curl, DuckDBread_parquet(), anything a client resolves programmatically.
https://source.coop/{org}/{product} # human-facing page
https://data.source.coop/{org}/{product}/catalog.json # machine-facing bytesStep 7: Validate before push
An object conforms only when it passes the validator. Run it before every push and fix every error:
portolan checkRead the PTL rule ids in the output. Each one cites the spec requirement it enforces.
Step 8: Push and probe
Push from a shell with fresh credentials:
eval "$(source-coop creds --format env)"
portolan push --dry-run
portolan push --verbose--workers sets the number of parallel collections and has no cap. --concurrency sets the concurrent uploads within a collection and defaults to 8. On a home network, leave --adaptive on and lower --chunk-concurrency before you raise anything.
After the push, probe the published host. The host must honor Range requests with an accurate HEAD Content-Length (PORTO-CORE-043) and send CORS headers on every file (PORTO-CORE-045). rashid check takes the local catalog directory, never a URL. The base URL makes the relative hrefs probeable:
rashid check --live \
--live-base-url https://data.source.coop/{org}/{product}/ .Then open the catalog in the browser and confirm the default style renders visible data: https://browser.portolan-sdi.org/#/external/data.source.coop/{org}/{product}/catalog.json.
Styles
Styles are collection-level assets with the style role and media type application/vnd.mapbox.style+json (PORTO-CORE-069, PORTO-FMT-015). With more than one style, exactly one asset carries both style and default (PORTO-CORE-070). The CLI writes the source URL in each style as pmtiles://../<file>.pmtiles. A bare relative path fails to load in MapLibre. There is no portolan:styles array in the spec.
Style files upload with portolan push like any other asset. For how many styles to write and what they should show, follow the portolan-bootstrap skill and specs/best-practices/styling.md.
Troubleshooting
InvalidAccessKeyId
AWS received the request, not the proxy. The URL in the error contains an amazonaws.com host.
- Check that
.envsetsPORTOLAN_S3_ENDPOINT=https://data.source.coop. - Check that
PORTOLAN_REMOTEtakes the forms3://{org}/{product}/. A regional bucket such asus-west-2.opendata.source.coopsends the request to AWS.
Access denied or 403 Forbidden
The credentials expired, or they do not cover the prefix.
- Run
source-coop creds. When its error includesRun 'source-coop login', runsource-coop login. - Run
eval "$(source-coop creds --format env)"again in the shell you push from. - Check that
PORTOLAN_REMOTEnames the organization and the repository you have write access to. - Contact hello@source.coop for access to a different repository.
Push stalls at 169.254.169.254
The push found no credentials and queried the instance metadata service. The error names http://169.254.169.254/latest/api/token.
- Remove
PORTOLAN_PROFILEfrom.envand from the shell, and remove--profilefrom the command. - Run
eval "$(source-coop creds --format env)"in the shell you push from.
Bucket not found
The proxy returns NoSuchBucket: bucket not found: {org} when the first path segment is not an account. Check the organization slug in PORTOLAN_REMOTE. The remote takes the form s3://{org}/{product}/, not the name of an S3 bucket.
Push conflict
Someone else pushed since your last pull. portolan pull requires the remote URL as an argument:
portolan pull s3://{org}/{product}/
portolan pushSlow uploads
Raise --concurrency first, then --workers when the catalog has many collections. Watch for errors.
Metadata validation fails
Run portolan metadata validate. Add the missing contact.name, contact.email, or license to the named metadata.yaml.
Live probe fails
A CORS or range finding from rashid check --live names a host you do not control. Report it to hello@source.coop with the failing URL and the rule id.
Complete Example
cd ~/data/phl-aerial-imagery
portolan init --title "Philadelphia Aerial Imagery" --auto --license CC-BY-4.0
cat > .env << 'EOF'
PORTOLAN_REMOTE=s3://nlebovits/phl-aerial-imagery/
PORTOLAN_S3_ENDPOINT=https://data.source.coop
EOF
source-coop login
portolan add . --pmtiles
portolan metadata init
# Edit .portolan/metadata.yaml: contact, license, providers, source_url
portolan metadata validate
portolan readme
# Write AGENTS.md at the catalog and at every collection
portolan check
eval "$(source-coop creds --format env)"
portolan push --verbose
rashid check --live \
--live-base-url https://data.source.coop/nlebovits/phl-aerial-imagery/ .Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

