Brown Octopus
Brown Octopus manages the capability context exposed to an AI agent.
Given a user request, it identifies relevant capabilities, retrieves a bounded set of candidates, and maintains the active capability context for a conversation. It returns capability definitions to the host application. It does not call tools, own an LLM, manage credentials, or store conversation history.
Distribution: brown-octopus
Import: brown_octopus
Runtime: Octopus
Index facade: OctopusIndex
Install
Brown Octopus supports Python 3.12 and newer.
pip install brown-octopus
Or with uv:
uv add brown-octopus
Prepare the default runtime models explicitly:
brown-octopus setup-models
This prepares en_core_web_trf and Qwen/Qwen3-Embedding-0.6B.
Octopus.initialize() never downloads models or discovers capabilities
implicitly.
Check the installation:
brown-octopus doctor
brown-octopus inspect
Quick start
The normal lifecycle is:
CapabilitySource -> OctopusIndex.create() -> persisted index
|
v
Octopus.initialize() -> retrieve_result()
1. Configure a local MCP catalog
Create data/mcps.json:
{
"items": [
{
"id": "outlook",
"name": "Outlook Mail",
"url": "https://example.com/outlook/mcp"
}
]
}
The URL must be a reachable MCP server that the host is authorized to access.
2. Build the index
Create setup_index.py:
import asyncio
from pathlib import Path
from brown_octopus import OctopusIndex
from brown_octopus.sources import LocalMcpCatalogSource
async def main() -> None:
index = OctopusIndex.from_sources(
[LocalMcpCatalogSource(Path("data/mcps.json"))],
index_path="data/indexes/default",
)
report = await index.create()
print(f"Indexed {report.tool_count} capabilities")
if __name__ == "__main__":
asyncio.run(main())
Run it once after the catalog is configured:
python setup_index.py
create() creates and publishes a snapshot only when the index does not already
exist. It discovers capabilities, builds embeddings, and validates the
snapshot atomically. To deliberately rebuild an existing index, use
create(replace=True). It does not execute MCP tools.
3. Start the runtime
Create app.py:
import asyncio
from brown_octopus import Octopus
async def main() -> None:
octopus = Octopus(index_path="data/indexes/default")
await octopus.initialize()
result = octopus.retrieve_result(
"Reply to Tom's email",
session_id="conversation-123",
)
print(f"Turn: {result.turn}")
for capability in result.tools:
print(capability["name"])
if __name__ == "__main__":
asyncio.run(main())
Run it with python app.py. Pass result.tools to the agent or harness; the
host decides how to bind and execute the definitions.
Index and runtime
OctopusIndex owns index lifecycle:
create()creates the index only if it is missing;create(replace=True)deliberately rebuilds the index;update()synchronizes configured sources;add(source)adds a source and synchronizes;remove_source(source_id)removes a configured source and synchronizes;reset()removes the persisted index;runtime()returns the runtime facade.
Octopus owns runtime retrieval:
initialize()loads models and the current snapshot;retrieve()returns the active capability context;retrieve_result()returns the typed result contract;- session methods maintain conversation-specific capability state.
Sources are optional when opening an index:
index = OctopusIndex(index_path="data/indexes/new-index")
octopus = index.runtime()
await octopus.initialize()
result = octopus.retrieve_result("Reply to Tom's email")
assert result.tools == []
assert result.retrieved_tools == []
assert result.tool_ids == []
If the path has no snapshot, runtime initialization starts with an empty
capability universe. Configure a source and call create() or update() when
the host is ready to provision capabilities. Calling create() during every
startup is safe: an existing snapshot is left unchanged.
Updating capabilities
After changing a configured source:
report = await index.update()
print(report.added)
print(report.changed)
print(report.removed)
print(report.failed_sources)
update() is a synchronization operation, not an append-only operation. It
rediscovers the configured universe and publishes a complete replacement
snapshot:
new capability -> added
changed metadata -> changed
unchanged capability -> retained
authoritatively removed capability -> removed
temporarily failed source -> previous capabilities preserved
The host decides when updates happen. Brown Octopus has no refresh scheduler.
Add a source to an existing index:
from brown_octopus import McpServerSource
await index.add(
McpServerSource(
"https://example.com/word/mcp",
source_id="word",
)
)
remove_capability() remains temporarily for older applications but is
deprecated. Prefer changing the authoritative source or removing the source.
Retrieval results and filtering
result = octopus.retrieve_result(
"Send Sarah an email",
session_id="conversation-123",
)
The result provides:
result.retrieved_tools current-turn selection
result.tools final active context
result.tool_ids stable IDs for result.tools
result.session_id conversation identifier
result.turn current session turn
result.metadata timing and pipeline metadata
The simpler method is also available:
active_tools = octopus.retrieve(
"Search the web for the latest NVIDIA news",
session_id="conversation-123",
)
Restrict a turn before ranking with allowed_mcp_urls:
result = octopus.retrieve_result(
"Reply to an email",
session_id="conversation-123",
allowed_mcp_urls=["https://example.com/outlook/mcp"],
)
Sessions
One engine can serve many conversations:
first = octopus.retrieve_result("Search the web", session_id="conversation-a")
second = octopus.retrieve_result("Reply to Tom", session_id="conversation-b")
Each session has its own turn counter and active capability state. A session ID represents a conversation or workflow identity, not a user identity.
snapshot = octopus.get_session("conversation-a")
octopus.reset_session("conversation-a")
octopus.delete_session("conversation-b")
The default store is process-local. A persistent application can inject a
custom atomic SessionStore; see docs/production.md.
Capability sources
Built-in adapters include:
| Adapter | Use it for |
|---|---|
LocalMcpCatalogSource |
local JSON catalog of MCP servers |
McpServerSource |
one HTTP MCP server |
McpRegistrySource |
API returning MCP server records |
JsonCapabilitySource |
normalized capabilities from JSON |
ApiCapabilitySource |
normalized capabilities from an HTTP API |
custom CapabilitySource |
application-specific discovery |
Convenience constructor:
index = OctopusIndex.from_mcp_server(
"https://example.com/outlook/mcp",
source_id="outlook",
index_path="data/indexes/outlook",
)
Detailed source contracts, pagination, authentication, and field mapping are
documented in docs/production.md.
Embedding providers
The default provider is local Qwen. A compatible local model can be supplied:
from brown_octopus import LocalEmbeddingProvider, OctopusIndex
provider = LocalEmbeddingProvider(
model_name="sentence-transformers/all-MiniLM-L6-v2",
)
index = OctopusIndex.from_sources(
[source],
index_path="data/indexes/minilm",
embedding_provider=provider,
)
await index.create()
An HTTP provider can target a remote or self-hosted service:
from brown_octopus import HttpEmbeddingProvider, OctopusIndex
provider = HttpEmbeddingProvider(
url="http://localhost:11434/api/embed",
model="qwen3-embedding:0.6b",
)
index = OctopusIndex.from_sources(
[source],
index_path="data/indexes/http-embeddings",
embedding_provider=provider,
)
await index.create()
Use the same provider when loading that index. Provider dimensions are checked against index metadata.
CLI
brown-octopus --help
brown-octopus --version
brown-octopus version
brown-octopus setup-models
brown-octopus doctor
brown-octopus inspect
brown-octopus inspect --json
Help and version do not load models. doctor checks package, models, and the
configured index. inspect reports configuration and index metadata.
Runtime context limits
The default active-context policy is:
TTL: 8 turns
Active cap: 30 capabilities
These defaults preserve the validated behavior, but applications can tune them when their context budget requires it:
from brown_octopus import OctopusIndex
index = OctopusIndex(index_path="data/indexes/default")
await index.create()
octopus = index.runtime(
capability_ttl=3,
active_cap=20,
)
await octopus.initialize()
capability_ttl controls how many later turns a retrieved capability can
remain active without being retrieved again. active_cap limits the total
number of active capabilities in a session. These settings affect session
context management, not candidate ranking or the V3 selection algorithm.
The same values can be configured through environment variables:
OCTOPUS_CAPABILITY_TTL=3
OCTOPUS_ACTIVE_CAP=20
Architecture boundary
Brown Octopus owns capability discovery adapters, indexing, intent analysis, retrieval, selection, active capability context, and capability session state.
The host owns the LLM, conversation history, tool binding and execution, credentials, authentication, authorization, user identity, update timing, and session lifecycle policy.
Returned MCP metadata such as mcp_url and tool_name describes execution
context. Brown Octopus does not execute the capability.
Retrieval behavior
The default V3 pipeline is unchanged:
user request -> deterministic spaCy intent analysis
-> capability-oriented representation
-> dense embedding retrieval
-> Min-4 + Bounded Max Gap
-> active capability context
-> TTL 8 and active cap 30
The strategy is recall-oriented within bounded limits. It may expose extra plausible capabilities rather than aggressively pruning a capability that may be required. It does not guarantee perfect recall.
Development and research
uv sync
uv run brown-octopus setup-models
uv run pytest -q -m "not external" tests
uv build
Product code, tests, examples, and research/evaluation history are kept
separate. Evaluation material under evals/ and docs/research/ is retained
for reproducibility and is not required at runtime.
See docs/production.md for the complete integration
reference.
License
See LICENSE.
Metadata
Release files for brown-octopus 0.5.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| brown_octopus-0.5.3.tar.gz | 46.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| brown_octopus-0.5.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 102.3 kB
Release files / brown_octopus-0.5.3.tar.gz
| Download URL | brown_octopus-0.5.3.tar.gz |
|---|---|
| Size | 46.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b4072a2e2ff2a977ac509ac07f80eb2ff933defba0a79bb610b56cf3db63efe9
|
|
BLAKE2b-256 checksum How to use checksums |
6c7a166aa829538313e91280c0f247590715d275eed21937c051d3cf6556877a
|
| 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 Oct 6, 2026.
Transparency logRelease files / brown_octopus-0.5.3-py3-none-any.whl
| Download URL | brown_octopus-0.5.3-py3-none-any.whl |
|---|---|
| Size | 56.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d17f3ed1464ed8c25db572c098470ee6713fbacb896cb0aff004290e28a9493e
|
|
BLAKE2b-256 checksum How to use checksums |
063ddec25e9dbfee7e85c213396df645f7ea9e6949c90fa8603ebdf0e496d849
|
| 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 Oct 6, 2026.
Transparency log