Skip to main content

Connector framework for financial data — typed fetch, hybrid-search catalogs, distribute via Hugging Face Hub or S3.

Project description

parsimony

PyPI version License Python CI Docs

Parsimony is a unified interface to public data, designed for agents. The same call shape works across every source, every result carries its own provenance, and the result shape keeps the agent's context light.

Quickstart

import asyncio
from parsimony_fred import CONNECTORS as fred

async def main():
    connectors = fred.bind_env()                              # FRED_API_KEY from os.environ
    result = await connectors["fred_fetch"](series_id="UNRATE")
    print(result.data.tail())
    print(result.provenance)                                  # source, params, fetched_at

asyncio.run(main())

That code shape is the same one you write for the European Central Bank, the OECD, SEC EDGAR, CoinGecko, or a private connector your team published yesterday. Install another parsimony-* package and the kernel finds it through entry-points; nothing else changes.

Why parsimony

The call shape is the same for every source. await connectors["fred_fetch"](series_id="UNRATE") and await connectors["sdmx_fetch"](agency="ECB", flow="ICP", key="M.U2.N.000000.4.ANR") look identical. Parameters are Pydantic models; results are typed.

Provenance is automatic. Every Result carries its source, params, and fetched_at. Credentials are injected at the call boundary, so they never appear in provenance, logs, Parquet output, or the LLM-facing to_llm() projection.

Made for agents that run Python in a code interpreter. Connectors return data into Python variables in the agent's notebook or REPL. The optional with_callback hook prints whatever summary you want after every fetch, so the agent sees what happened without the full dataframe ever entering the LLM context.

def summarise(result):
    print(f"{result.provenance.source}({result.provenance.params}) -> {len(result.data)} rows")

connectors = fred.bind_env().with_callback(summarise)
await connectors["fred_fetch"](series_id="UNRATE")
# UNRATE is now in a local variable. The model only saw the one-line summary.

Partial credentials are not an error. bind_env() resolves whatever env vars are set and leaves the rest unbound. Calling an unbound connector raises UnauthorizedError; inspect connectors.unbound to list what is missing.

Catalogs ship as Hugging Face datasets. parsimony publish --provider sdmx --target 'hf://yourorg/catalog-{namespace}' produces a hybrid FAISS + BM25 index over thousands of series. Search before you fetch:

from parsimony import Catalog

cat = await Catalog.from_url("hf://parsimony-dev/sdmx_datasets")
hits = await cat.search("euro area unemployment", limit=10)

A fragment-deduplicating embedder fits 8000+ SDMX dataflows in roughly 3 GB of memory at publish time instead of 18.

Private connectors are first-class. A customer-internal plugin uses the same parsimony.providers entry-point contract as a public one; the kernel cannot tell them apart at discovery time. Your data spec does not have to ship to PyPI to be agent-addressable.


Install

The kernel ships with no connectors of its own. Pick what you need:

pip install parsimony-core                          # kernel only (small footprint)
pip install parsimony-core parsimony-fred           # + FRED
pip install 'parsimony-core[standard]'              # + Catalog (FAISS + BM25 + sentence-transformers)
pip install parsimony-mcp                           # MCP server, separate distribution

Other install variants (ONNX runtime, LiteLLM embedders, CPU-only torch) are documented at docs.parsimony.dev/install. The full list of officially-maintained connectors lives at ockham-sh/parsimony-connectors.

Imports are always from parsimony import .... The bare parsimony PyPI name is squatted by an unrelated project, so the distribution ships as parsimony-core.

CPU-only deployments: [standard] pulls torch from the default PyPI channel, which is the CUDA wheel and pulls roughly 4 GB of GPU libraries. On servers without a GPU, install the CPU wheel explicitly first to keep the image small:

pip install torch --index-url https://download.pytorch.org/whl/cpu
pip install 'parsimony-core[standard]'

Core primitives

The kernel exposes three decorators and one runtime type:

  • @connector declares a typed fetch or search function.
  • @enumerator populates a catalog (KEY, TITLE, METADATA, no DATA).
  • @loader persists observations into a DataStore.

Provenance on every result:

result.provenance  # Provenance(source="fred", params={"series_id": "UNRATE"}, fetched_at=...)

Repo boundaries

Parsimony ships across three repositories, each with a single job:

Repo PyPI Role
parsimony parsimony-core The kernel. Primitives, discovery, catalog, publish CLI
parsimony-connectors parsimony-<name> First-party data source plugins
parsimony-mcp parsimony-mcp MCP (Model Context Protocol) server

The kernel knows nothing about specific connectors. Connectors depend on the kernel through the stable parsimony.providers entry-point contract. Consumers like the MCP server call discover.load_all() and pick up whatever is installed.

The plugin contract

Every data source is a separate distribution implementing one contract:

# your-connector/pyproject.toml
[project]
name = "parsimony-yourname"
dependencies = ["parsimony-core>=0.4,<0.5", "pydantic"]

[project.urls]
Homepage = "https://your-provider.example"

[project.entry-points."parsimony.providers"]
yourname = "parsimony_yourname"

Your module exports CONNECTORS (required) and optional CATALOGS / RESOLVE_CATALOG (if the plugin publishes catalogs):

# parsimony_yourname/__init__.py
from parsimony import Connectors, connector

@connector(env={"api_key": "YOUR_API_KEY"})
async def yourname_fetch(params, *, api_key: str): ...

CONNECTORS = Connectors([yourname_fetch])

Per-connector env vars live on the decorator (env={...}); homepage and version come from pyproject.toml. The full spec is in docs/contract.md, which is the authoritative reference for plugin authors.

For a customer-private connector, see docs/building-a-private-connector.md.

Discovering plugins

from parsimony import discover

for provider in discover.iter_providers():
    print(provider.dist_name, provider.version, provider.module_path)

Or from the command line:

parsimony list                  # what is installed plus declared catalogs
parsimony list --strict         # run conformance suite; non-zero exit on failure
parsimony list --strict --json  # machine-readable artefact for security review

The conformance suite (parsimony.testing.assert_plugin_valid) verifies that every connector exports a CONNECTORS collection, has non-empty descriptions, and that declared env_map keys map to real keyword-only dependencies on the function. It is the merge gate in the connectors monorepo.

Publishing catalogs

parsimony publish --provider NAME --target URL_TEMPLATE builds one catalog per namespace declared on a plugin's CATALOGS export and pushes each to URL_TEMPLATE.format(namespace=...).

parsimony publish --provider sdmx --target 'hf://myorg/catalog-{namespace}'
parsimony publish --provider sdmx --target 'file:///tmp/out/{namespace}'

The file:// output is byte-identical to what hf:// would write, so you can stage locally, sign, and upload from a separate machine. See docs/contract.md §6 for the publish contract.

Cache

Heavy artefacts (HF snapshots, ONNX models, fragment embeddings, connector scratch) live in a shared user-home cache so a parsimony-mcp server and a REPL session reuse the same downloads. Override the root with PARSIMONY_CACHE_DIR. Inspect or clear with parsimony cache info and parsimony cache clear. Layout details: docs.parsimony.dev/cache.

MCP server

The MCP server is a separate distribution, parsimony-mcp:

pip install parsimony-mcp
parsimony-mcp init

Connectors tagged tool (search, list, metadata) become MCP tools the agent can call. Bulk fetch goes through the agent's code interpreter via discover.load_all().bind_env(). See the parsimony-mcp README for the rationale.

Documentation

Full docs at docs.parsimony.dev:

Contributing

The kernel does not accept provider-specific code. That is structurally enforced by tests/test_kernel_purity.py.

License

Apache 2.0.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

parsimony_core-0.5.0.tar.gz (81.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

parsimony_core-0.5.0-py3-none-any.whl (84.3 kB view details)

Uploaded Python 3

File details

Details for the file parsimony_core-0.5.0.tar.gz.

File metadata

  • Download URL: parsimony_core-0.5.0.tar.gz
  • Upload date:
  • Size: 81.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for parsimony_core-0.5.0.tar.gz
Algorithm Hash digest
SHA256 339e57b835e09e4b8425eb877bd912c3655bdf0428207aba388f83ed13a93cf6
MD5 ad5f72b8de1c390774c032e2bdb28a13
BLAKE2b-256 26d52409b6d058ceb39dc2a71ba3f2bd8c1d58291d14bd2528e839dab81b0c8b

See more details on using hashes here.

Provenance

The following attestation bundles were made for parsimony_core-0.5.0.tar.gz:

Publisher: publish.yml on ockham-sh/parsimony

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file parsimony_core-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: parsimony_core-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 84.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for parsimony_core-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b4604f4a91ca026f8f3efbf7f0f271d9393a6877c6aea14dee74efe112d0606f
MD5 a86c01792e9ec66b54448ccf56558d16
BLAKE2b-256 fd599b817f77454b4eeb2002b9cecfce48c9e98f52339901bcce12a4b3410471

See more details on using hashes here.

Provenance

The following attestation bundles were made for parsimony_core-0.5.0-py3-none-any.whl:

Publisher: publish.yml on ockham-sh/parsimony

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page