A lightweight Pi harness: skills and extensions live in this directory and are loaded at launch. They are not installed into global Pi settings (~/.pi/agent/settings.json) or a project .pi/ config.
Pi 0.85.1+ is required (pi on PATH). Your existing provider auth, models, and global packages stay in global Pi settings. This repo only adds local skills.
A visual overview of what is here follows. The harness is based on Pi and loads services from DeCODER, AIDRIN, SetGo, Open Knowledge Network (OKN) and Science Made Readable (literature search). Once loaded the quickest way to see what is possible is to try the examples.
flowchart LR
subgraph Sources
direction TB
DG["DeCODER Graph"]
end
subgraph MCP
direction TB
DeCODER
OKN
SMR["Science Made Readable\n(literature)"]
AIDRIN["AIDRIN\n(stdio)"]
end
subgraph Skills
direction TB
decoder["DeCODER"]
SetGo
end
LLM[LLM]
Harness[Harness]
MCP <--> Harness
Skills <--> Harness
Sources <--> Harness
Harness <--> LLM
./bin/pi always cds to the repo root before starting Pi so the project MCP
config in .pi/mcp.json (AIDRIN, OKN, Science Made Readable) is discovered even if you invoke the launcher from another
directory.
desktop/ is a Tauri window on the same launcher. It starts ./bin/pi --mode rpc and renders the chat, tool output, and files under runs/. Skills, MCP, and model auth stay in Pi. See desktop/README.md.
AIDRIN is an optional uv group (heavy: base AIDRIN plus MCP extras). Default
uv sync stays lean.
uv sync --group aidrin
./bin/pi
# then in-session: `list_metrics` / `run_aidrin_metric` on a small CSV.pi/mcp.json runs uv run --group aidrin aidrin-mcp (stdio). That process has
no web-style path allowlist — it can read whatever the launching user can.
Leave the separate [agentic] extra off unless you intentionally want that
pipeline (needs an API key).
A session that finds one ecoforecast scores parquet, keeps one site and one
lead, and scores that file with these tools is in
AIDRIN_EXAMPLE.md.
From this repo (loads every SKILL.md under skills/):
./bin/piThat is:
pi --no-skills -e /path/to/decoder-pi/extensions/load-skills.ts--no-skills turns off discovery of ~/.pi/agent/skills/, .pi/skills/, and
settings skill paths. The extension then contributes this repo's skills/
directory (resolved from the extension file, so cwd does not matter).
Without the extension (same skill set):
pi --no-skills --skill ./skillsOne skill only:
pi --no-skills --skill ./skills/sparqlKeep your global skills as well (omit --no-skills):
pi --skill ./skillsFrom any directory:
pi --no-skills -e /home/fils/src/Projects/earthcube/decoder-pi/extensions/load-skills.tsDo not run pi install on this repo. Extra args (--print, --model, an
initial prompt) pass through ./bin/pi.
Inside a session: /skill:sparql, /skill:catalog-plot, /skill:catalog-map,
/skill:forecast-inventory, /skill:forecast-parquet, /skill:surface-inventory,
/skill:hydrography-tiles, /skill:geotiff-list, /skill:handoff.
decoder-pi/
├── bin/pi # launcher
├── extensions/load-skills.ts # resources_discover → skills/
├── skills/
│ ├── sparql/ # SPARQL 1.1 CLI + templates
│ ├── catalog-plot/ # bars, depth hist/ranges
│ ├── catalog-map/ # lat/lon, box, WKT, coastlines, near
│ ├── forecast-inventory/ # ecoforecast catalog
│ ├── forecast-parquet/ # parquet CRPS / mean, or one lead
│ ├── surface-inventory/ # earthsurface catalog
│ ├── hydrography-tiles/ # 20° hydrography tile index
│ ├── geotiff-list/ # raster URL table (no download)
│ └── handoff/ # human-gated session handoff record
├── pyproject.toml # SPARQLWrapper + matplotlib + pyarrow
└── AGENTS.md
Add another skill as skills/<name>/SKILL.md. ./bin/pi picks it up with no
command change.
Adapted from DOOS doos-sparql. Curated schema.org / GeoSPARQL templates plus
ad-hoc SPARQL 1.1. Always requires an explicit --endpoint.
uv sync # once; SPARQLWrapper
uv run python skills/sparql/scripts/sparql_query.py list
uv run python skills/sparql/scripts/sparql_query.py run \
--endpoint http://localhost:7878/query \
--query probe_triples \
--show-querySee skills/sparql/SKILL.md for the cookbook and remaining templates.
Copy-paste session prompts that chain SPARQL → plot/map/parquet are in
EXAMPLES.md.
These consume SPARQL JSON (or --endpoint, which shells out to the SPARQL CLI).
They plot catalog metadata, not observation time series.
EP=https://qlever.geocodes-aws.earthcube.org/graphspace/deepoceans
EF=https://qlever.geocodes-aws.earthcube.org/graphspace/ecoforecast
uv run python skills/catalog-plot/scripts/plot.py depth-hist --endpoint $EP
uv run python skills/catalog-plot/scripts/plot.py depth-ranges --endpoint $EP
uv run python skills/catalog-map/scripts/map.py points --endpoint $EP --limit 2000
uv run python skills/catalog-map/scripts/map.py near --endpoint $EP --lat -62 --lon -58 --km 800
uv run python skills/forecast-inventory/scripts/inventory.py themes --endpoint $EF
uv run python skills/forecast-parquet/scripts/parquet_plot.py plot \
--endpoint $EF --contains 'scores/bundled-parquet' --y crps --site TALL
uv run python skills/forecast-parquet/scripts/parquet_plot.py horizon \
--from-parquet skills/forecast-parquet/fixtures/scores_horizon.parquet \
--site TALL --lead 7 --y crpsOffline fixtures:
uv run python skills/catalog-plot/scripts/plot.py depth-hist \
--from-json skills/catalog-plot/fixtures/depth_hist.json -o /tmp/depth-hist.png