Skip to main content

STAC Scout

Find the data. Prove it exists. Know what you're getting.

intent → task semantics → catalog federation → live item evidence → asset plan → manifest

CI Python License: MIT STAC

A deterministic decision layer for the STAC ecosystem.

STAC is syntax. Dataset choice is semantics.

A model can generate a valid STAC query.

That does not mean it chose the right dataset.

A Collection can advertise the right spatial and temporal extent.

That does not mean an Item actually exists for your AOI and date.

An asset can be called B08.

That does not mean a caller should silently assume what it contains.

STAC Scout lives in that gap.

"find imagery for this task"
            │
            ▼
      what does the task need?
            │
            ▼
      which datasets fit?
            │
            ▼
      do matching items exist?
            │
            ▼
      which assets are actually required?
            │
            ▼
      how much data will this read?
            │
            ▼
      can the decision be replayed?

The operating rule is simple:

Never infer what can be inspected.

What Scout actually does

natural language / structured request
              │
              ▼
         IntentDraft
              │
        task_type + facts
              ▼
     ┌───────────────────┐
     │    TaskAdvisor   │◄──── versioned task rules
     └────────┬─────────┘
              │
              ▼
        ScoutRequest
              │
      ┌───────┴────────┐
      │                │
      ▼                ▼
 ScoutEngine     FederatedScout
      │                │
      │         provider isolation
      │         dataset identity
      │         duplicate evidence
      │         explicit failures
      │                │
      └───────┬────────┘
              ▼
         live Item probe
              │
        AOI coverage
              │
         asset semantics
              │
         access planning
              │
              ▼
      manifest + replay

Scout does not replace pystac-client, odc-stac, or a STAC API.

It decides what should be asked, checks what came back, and records why.

The invariants

These are not style preferences. They are the contract.

  • Collection metadata is not availability evidence. Item Search is.
  • intersects is not AOI coverage.
  • Unknown is not false.
  • Required and preferred measurements are different things.
  • Task rules do not invent dates.
  • Explicit user constraints beat defaults.
  • Probable duplicates stay visible.
  • Provider health is not scientific quality.
  • A language model may classify intent; it does not own geospatial truth.
  • Every useful decision should be reproducible.

Or shorter:

metadata ≠ evidence
similarity ≠ identity
availability ≠ suitability
confidence ≠ proof

Install

python -m pip install -e ".[dev]"

Python 3.12 or newer is required.

For Planetary Computer access recipes:

python -m pip install -e ".[planetary-computer]"

Geo Task Intelligence

Geo Task Intelligence workflow

The user often knows the problem, not the bands.

"assess wildfire impact"
        ↓
optical
        ↓
NIR + SWIR2 required
        ↓
surface reflectance preferred
        ↓
before/after strategy
        ↓
comparison_windows still required from the user

Scout keeps that knowledge in a versioned, inspectable registry instead of hiding it in prompts.

List the built-in task archetypes:

stac-scout tasks
stac-scout task-profile wildfire_impact

Derive task-aware data requirements:

stac-scout advise request.json --task wildfire_impact

The output includes:

TaskProfile
├── rule_id
├── rationale
├── sources
├── required measurements
├── preferred measurements
├── temporal strategy
├── processing preferences
└── mask preferences

TaskAdvice
├── enriched ScoutRequest
├── derivations[]
│   ├── rule_id
│   ├── field
│   ├── value
│   ├── required | preferred
│   └── rationale
├── follow_up_requirements[]
└── notes[]

Task rules live in:

src/stac_scout/data/tasks.toml

The scientific basis and rule boundaries are documented in docs/TASK_RULES.md.

Rules are allowed to say "I don't know"

For example, a before/after wildfire task does not cause Scout to hallucinate a pre-fire window.

It returns:

{
  "follow_up_requirements": ["comparison_windows"]
}

Likewise, if the user explicitly asks for SAR while a task's default modality is optical, Scout preserves SAR and skips incompatible optical band defaults.

No spectral fan fiction.

Intent boundary

STAC Scout deliberately does not ship an LLM SDK in the core package.

Any structured-output model can produce an IntentDraft.

Get the contract:

stac-scout intent-contract
stac-scout schema intent

The model may identify a supported task_type.

It is explicitly told not to invent:

  • coordinates;
  • dates;
  • dataset names;
  • measurement names;
  • hidden constraints.

Those belong to deterministic code, explicit user input, or live metadata.

Resolve an intent directly:

stac-scout resolve-intent intent.json

Resolve it and apply task intelligence:

stac-scout advise-intent intent.json

If required information is still ambiguous, the draft stays unresolved.

That is a feature.

Providers are adapters, not assumptions

List the built-in provider registry:

stac-scout providers
stac-scout providers --all

Check operational health:

stac-scout health
stac-scout health --provider earth-search

The default enabled providers are:

  • Element 84 Earth Search
  • Microsoft Planetary Computer

Provider quirks stay behind adapters.

Planetary Computer signing is recorded explicitly and generated recipes use the official planetary_computer.sign_inplace path instead of reimplementing SAS handling.

Provider latency and uptime are reported as operational evidence only.

Network behavior is bounded: adapters use explicit connect/read timeouts, a finite transient-retry budget, capped backoff/Retry-After delays, and typed provider errors. A reachable provider with invalid metadata is reported as degraded rather than falsely labeled unreachable.

A slow endpoint does not make a scientifically suitable dataset worse.

Federation without pretending everything is the same

Search a single provider:

stac-scout discover request.json --provider earth-search

Or a raw STAC endpoint:

stac-scout discover request.json \
  --catalog https://earth-search.aws.element84.com/v1

Search across enabled providers:

stac-scout federate request.json
stac-scout federate request.json --max-workers 4 --overall-timeout 30

Federation isolates expected provider failures such as timeouts, rate limits, authentication errors, malformed metadata, and unsupported capabilities. Each failure reports its type, HTTP status when known, and whether retry is reasonable. Unexpected internal exceptions are not converted into provider failures.

Dataset identity is conservative:

sci:doi
  → exact

collection id + platform / constellation / instrument evidence
  → probable

everything else
  → local to that catalog

Only exact groups are considered safe to collapse.

Probable matches stay visible.

Because two catalogs agreeing on a name is not the same thing as two catalogs describing the same scientific product.

The catalog says maybe. Items say yes or no.

Verification is item-level.

stac-scout verify request.json \
  --provider earth-search \
  --collection sentinel-2-l2a

Scout records:

  • matching Item count;
  • Item IDs;
  • timestamps;
  • asset keys;
  • cloud metadata when available;
  • AOI coverage ratio;
  • fraction of each Item intersected by the AOI;
  • warnings when geometry or metadata cannot be evaluated.

AOI coverage normalizes antimeridian-crossing geometry and measures overlap in an AOI-centered WGS84 equal-area projection rather than treating raw longitude/latitude as a flat Cartesian plane.

Because this is geospatial software.

Asset planning

A scientifically correct Collection can still produce a bad access plan.

Scout resolves requested measurements against declared asset and band metadata rather than guessing asset names.

stac-scout plan request.json \
  --provider earth-search \
  --collection sentinel-2-l2a \
  --manifest scout.manifest.json \
  --recipe load.py

Planning can produce:

measurement → asset + selection evidence
resampling strategy + evidence
windowed-read estimate
explicit target output resolution
provider signing requirements
warnings
odc-stac recipe

max_source_resolution_m answers “is this source data fine enough?” while target_resolution_m answers “what output grid should I request?”. It requires an explicit target_crs whose units are meters (or odc-stac's explicit "utm" selector), because odc-stac interprets resolution in output-CRS units. Scout never reuses the source threshold as an output resampling instruction. The legacy input name max_spatial_resolution_m is accepted as a source-resolution alias for compatibility.

If multiple assets remain equally supported after semantic, role, coverage, media-type, and GSD evidence, Scout reports the selection as ambiguous instead of choosing the alphabetically first key. Unknown resampling semantics likewise remain unresolved rather than defaulting to bilinear.

When file:size exists, Scout estimates transfer volume from the AOI/item intersection fraction.

It is an estimate, not a bandwidth prophecy.

Manifests: because catalogs move

A successful query today is not a frozen scientific record.

Scout writes a versioned provenance manifest containing the canonical request/query, provider/catalog identity, search limit and completeness, Collection fingerprint, full access plan, selected-asset metadata, and the observed decision-matching Item set. Ephemeral asset URLs are not copied into the provenance snapshot.

Replay it later:

stac-scout replay scout.manifest.json

By default replay reuses the manifest's recorded max_items. You can override it explicitly, but Scout records that the limits differ.

Replay reports:

comparison status: complete / partial / inconclusive
retained Item IDs
confirmed missing Item IDs
confirmed new Item IDs
unresolved missing Item IDs
unresolved new Item IDs
Collection metadata changed: true / false / unknown

A search that returns exactly max_items is marked limit_reached, not assumed complete or definitely truncated. If either historical or current completeness cannot be proven, Scout will not promote ordering/sample differences into confirmed drift.

The manifest is evidence of the decision.

It is not a copy of the remote data.

CLI map

stac-scout
├── version
├── validate-request
├── schema
│
├── intent-contract
├── resolve-intent
├── advise-intent
│
├── tasks
├── task-profile
├── advise
│
├── providers
├── health
├── inspect-catalog
│
├── discover
├── federate
├── verify
├── plan
└── replay

Repository map

stac-scout/
├── src/stac_scout/
│   ├── catalogs/          # STAC access boundary
│   ├── data/
│   │   ├── providers.toml
│   │   └── tasks.toml
│   ├── discovery/         # candidate retrieval
│   ├── models/            # strict contracts
│   ├── normalize/         # provider metadata → stable models
│   ├── planning/          # assets, raster semantics, volume
│   ├── provenance/        # manifest + replay
│   ├── verify/            # live evidence + dateline-safe coverage
│   ├── federation.py
│   ├── health.py
│   ├── identity.py
│   ├── reasoning.py
│   ├── scout.py
│   ├── tasking.py
│   └── tasks.py
├── evals/
│   ├── cases/
│   ├── federation_cases/
│   ├── task_cases/
│   ├── runner.py
│   └── live.py
├── docs/
│   ├── ARCHITECTURE.md
│   └── TASK_RULES.md
├── skill/
│   └── SKILL.md
└── tests/

Evals over vibes

The deterministic evaluation corpus checks contracts that affect dataset decisions:

python evals/runner.py

It covers:

  • request invariants;
  • cross-provider identity;
  • task-derived measurements;
  • task modality;
  • temporal strategy;
  • follow-up requirements.

Remote providers are intentionally kept out of ordinary CI.

Live checks run separately:

python evals/live.py

That separation is deliberate:

deterministic behavior
  → CI gate

remote catalog state
  → live observation

Development

ruff check .
ruff format --check .
mypy
pytest --cov=stac_scout --cov-report=term-missing
python evals/runner.py
python -m build

CI runs on Python 3.12 and 3.13.

Coverage must stay at or above 90%.

The wheel is also checked to ensure the provider and task registries are actually packaged.

What Scout refuses to fake

"the collection covers 2024, so data must exist"
"cloud_cover=8 means my AOI is clear"
"B08 probably means NIR"
"these two collections have similar names, merge them"
"the provider is fast, therefore the dataset is better"
"wildfire task means I'll invent a pre-fire date"
"the model sounded confident"

Those are shortcuts.

Scout's job is to turn them into inspectable claims.

Philosophy

STAC gives us a language.

Scout adds skepticism.

Or, in GeoGeek form:

The map can look right while the geography is wrong.
The query can run while the dataset choice is wrong.
Check the semantics. Check the evidence.

License

MIT


Find it. Verify it. Plan it. Replay it.

catalog metadata ≠ ground truth

Release files for stac-scout 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for stac-scout 0.5.0
File Size Uploaded
stac_scout-0.5.0.tar.gz 91.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for stac-scout 0.5.0
File Interpreter ABI Platform
stac_scout-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 157.6 kB

Release files / stac_scout-0.5.0.tar.gz

Download URL stac_scout-0.5.0.tar.gz
Size 91.2 kB
Tags Source
SHA-256 checksum
How to use checksums
ce547f315f750af509e090da61456a0d01144214fc2ca0ae61392dfd9a654ccc
BLAKE2b-256 checksum
How to use checksums
586a6b25fd7dad61c9b0ad1bae3156519342f5d44a463332bd8ed72faee64332
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 20, 2026.

Transparency log

Release files / stac_scout-0.5.0-py3-none-any.whl

Download URL stac_scout-0.5.0-py3-none-any.whl
Size 66.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f41677311eca87bf27826648944d7ae3d49e5c7e22c8bcc698dd77a5053b1ee1
BLAKE2b-256 checksum
How to use checksums
e7f0f1a6a5f0d92322345070ba0cff23d66f208682267d750df4b268250783be
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 20, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page