Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

Protocore

Protocore is the agent loop, and nothing else.

It is a Python 3.12+ library holding one thing: the ReAct runtime that drives an LLM agent turn by turn — the loop, the context budget, the tool surface, the compaction, the stop conditions. Everything the loop touches from outside is a Protocol you implement: the model client, the stores, the event transport, the tools themselves. There is no database driver here, no HTTP endpoint, no deployment logic, and no import that reaches upward out of the package.

That constraint is the point. An agent loop is where the hard, unglamorous correctness lives — what to do when the model answers with prose instead of the tool it was told to call, when a tool result is a hundred kilobytes, when the context window fills mid-turn, when a run must be snapshotted and resumed on another process. Protocore isolates that from the plumbing so it can be tested exhaustively and reused across products.

Русская версия: README.md · Docs: docs/index.md (EN) · docs/ru/index.md (RU)

What you get

  • 20 interface ProtocolsILLMProvider, IRunStore, ISessionStore, IToolRegistry, IMemory, IWorkspace, ISearchIndex, IEventStream, ISkillStore, IHookManager, and the rest, plus an IBlobStore ABC. They are the whole outward surface; the core never learns what is behind them.
  • A ReAct runtimeQueryEngine owns the per-run mutable state, query() drives one turn and yields a stream of typed TurnEvents. Snapshot and resume are first-class, so a run survives a process restart.
  • A three-layer tool surface — tenant policy, then a lean clipped surface, then progressive discovery over BM25 retrieval, with a permission gate in front of dispatch.
  • Two-tier context compaction — the loop keeps working when the transcript outgrows the window, and the compaction is deterministic enough to test.
  • 524 runtime constants — every tunable value is a field on a frozen RuntimeConstants snapshot injected per tenant. No magic numbers in the executable path, and new behaviour defaults off.
  • In-memory adapters, shipped inside the package, so you can drive a real turn end to end with no external services at all.

Install

pip install protocore==2.0.0a2

Name the version explicitly. The published release is a pre-release, and pip skips those unless you ask — but do not ask with a bare --pre, because that flag applies to the whole resolution and will pull pre-release builds of pydantic too. The pin comes off when there is a stable release.

Or, to work on it, with uv:

uv sync --extra dev

Python ≥ 3.12. Runtime dependencies are pydantic, pluggy, jinja2, and typing-extensions — nothing else.

Quickstart

The core is adapter-driven: build a QueryEngine with your adapters, seed the history with a user message, then iterate. query(engine) is a sync function that resets per-turn state and returns an async iterator — it is deliberately not an async generator, so the reset happens at the call rather than on the first __anext__.

The example below uses the bundled in-memory adapters, so it runs as-is:

import asyncio

from protocore import (
    Message, MessageRole, StopReason, TextBlock, default_runtime_constants,
)
from protocore.runtime.query_engine import QueryEngine, QueryEngineConfig
from protocore.runtime.query import query
from protocore.tests_support.adapters import (
    InMemoryBlobStore, InMemoryEventStream, InMemoryHookManager,
    InMemoryLLMProvider, InMemorySkillStore, InMemoryToolRegistry,
)


async def main() -> None:
    llm = InMemoryLLMProvider()
    llm.queue_response(text="Hello from Protocore.", stop_reason=StopReason.end_turn)

    engine = QueryEngine(
        config=QueryEngineConfig(
            run_id="run-1",
            tenant_id="default",
            session_id="sess-1",
            model_name="smoke-model",
            rc=default_runtime_constants(),
        ),
        llm_provider=llm,
        tool_registry=InMemoryToolRegistry(),
        event_stream=InMemoryEventStream(),
        hook_manager=InMemoryHookManager(),
        skill_store=InMemorySkillStore(),
        blob_store=InMemoryBlobStore(),
    )
    engine.history.append(
        Message(role=MessageRole.user, content_blocks=[TextBlock(text="Say hello.")])
    )

    async for event in query(engine):
        print(event.type)
    print("final state:", engine.state)


asyncio.run(main())

Swap InMemoryLLMProvider for an adapter over a real model client and the same code answers real prompts. Getting started walks through what each event means and what to replace next.

Import location matters. QueryEngine, QueryEngineConfig, and query come from protocore.runtime.*; they are not top-level re-exports. The contract types (Message, StopReason, RuntimeConstants, …) are.

Documentation

Document What it covers
Documentation hub start here — reading order and a map
Getting started install plus a runnable example
Architecture the deep reference
Contracts the protocol boundary and the type system
Tools the lean tool surface and the permission gate
Runtime constants the configuration model
Extending the core adapters, hooks, toggles, prompt sections
Testing running the suite and the import-boundary guard
Glossary key terms

A full Russian mirror lives under docs/ru/.

Development

uv sync --extra dev
uv run pytest .            # 2973 tests
uv run ruff check .
uv run mypy --strict
uv run bandit -r protocore -q -c pyproject.toml

All four gates run on every pull request across Python 3.12, 3.13, and 3.14. Coverage is enforced at 90%.

The guard worth knowing about is tests/test_core_import_boundary.py: it AST-parses every module in the package and fails if any of them imports a package that sits above the core — anything sharing the core's name with an underscore after it. That test is what keeps the rest of this README true.

Contributions are welcome; see CONTRIBUTING.md.

License

Mozilla Public License 2.0.

The MPL is a file-level copyleft. In practice that means: build whatever you like on top of Protocore and keep it closed — your adapters, your service, your product are yours. But if you modify a Protocore file itself, that file's source stays open under the same license, and the notices travel with it. See NOTICE for what that asks of you in concrete terms.

Security issues go to SECURITY.md, not to the public issue tracker.

Download files

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

Source Distribution

protocore-2.0.0a3.tar.gz (1.3 MB view details)

Uploaded Source

Built Distribution

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

protocore-2.0.0a3-py3-none-any.whl (721.7 kB view details)

Uploaded Python 3

File details

Details for the file protocore-2.0.0a3.tar.gz.

File metadata

  • Download URL: protocore-2.0.0a3.tar.gz
  • Upload date:
  • Size: 1.3 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for protocore-2.0.0a3.tar.gz
Algorithm Hash digest
SHA256 97a5108f435544f0127a2a2c24165029cb90312552ad0d117f0f2e2eeab117cf
MD5 7bf9cdda3b22eb0710adeb7549bdc1dc
BLAKE2b-256 e518d3a1c30ea7a3c2035d9be0cfadfddde3196df6fa76b9c1d19123a43592a8

See more details on using hashes here.

Provenance

The following attestation bundles were made for protocore-2.0.0a3.tar.gz:

Publisher: publish.yml on ascorblack-labs/protocore-community

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

File details

Details for the file protocore-2.0.0a3-py3-none-any.whl.

File metadata

  • Download URL: protocore-2.0.0a3-py3-none-any.whl
  • Upload date:
  • Size: 721.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for protocore-2.0.0a3-py3-none-any.whl
Algorithm Hash digest
SHA256 734d5fd1e8a879147f32e674413956b0f528f5d806f573b0947dcd1f73f2cd2e
MD5 cbd9ae13be3c498753c6eac5f3fd2e0a
BLAKE2b-256 73a353a569ac1d1b94b9c6251eee8c12d35fb2db1d09ca44e6d67c4b7a593db2

See more details on using hashes here.

Provenance

The following attestation bundles were made for protocore-2.0.0a3-py3-none-any.whl:

Publisher: publish.yml on ascorblack-labs/protocore-community

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

Release history Release notifications | RSS feed

This release

2.0.0a3 This release

2 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