Skip to main content

astromesh-okf

Let your agents navigate knowledge instead of retrieving chunks.

PyPI Python CI License: Apache-2.0 OKF v0.2

Leer en español

The Open Knowledge Format (OKF) is a plain-files format for curated knowledge: a bundle is a directory of Markdown concepts, each with YAML frontmatter (type, title, tags, status, who verified it, when it goes stale) and Markdown links to other concepts. astromesh-okf gives an AI agent three tools to walk such a bundle like a person would: read the index, search by type or tag, open a concept and follow its links, with the trust and freshness signals of the spec intact. It works with LangChain/LangGraph, CrewAI, Google ADK, OpenAI Agents SDK, PydanticAI, LlamaIndex, smolagents, Microsoft Agent Framework and any MCP client, and its core depends only on PyYAML.

sequenceDiagram
    participant U as User
    participant A as Agent
    participant K as OKF bundle
    U->>A: Can I get a refund after 3 weeks on the Team plan?
    A->>K: kb_index("/")
    K-->>A: policies/ and products/
    A->>K: kb_find(type="Policy")
    K-->>A: policies/refunds, trust human-reviewed
    A->>K: kb_read("policies/refunds")
    K-->>A: body plus links resolved to ids
    A->>K: kb_read("policies/refunds-2024")
    K-->>A: warning DEPRECATED, do not use for new work
    A-->>U: Yes, within 30 days. Source policies/refunds

(The diagram renders on GitHub.)

Quickstart (30 seconds)

pip install 'astromesh-okf[langchain]' langchain langchain-openai
from langchain.agents import create_agent

from astromesh_okf import Bundle
from astromesh_okf.integrations.langchain import okf_tools

agent = create_agent(
    "openai:gpt-4.1-mini",
    okf_tools("./my-bundle"),
    system_prompt="Answer using the knowledge base tools. Bundle index:\n"
    + Bundle("./my-bundle").index("/"),
)
result = agent.invoke({"messages": [("user", "Can I get a refund after 3 weeks?")]})
print(result["messages"][-1].content)

create_agent runs on LangGraph underneath, so the same tools work in a hand-built LangGraph graph (ToolNode).

No framework, no model: the tools are plain methods that return strings.

from astromesh_okf import OKFTools

kb = OKFTools("./my-bundle")
print(kb.kb_index("/"))
print(kb.kb_find(type="Policy"))
print(kb.kb_read("policies/refunds"))

No bundle yet? Try the one in this repo: astromesh-okf index examples/bundles/support (see examples/).

Why navigate instead of RAG

Navigation wins when the knowledge is curated, linked and typed: policies, metric definitions, runbooks, a data catalog. The model reads whole concepts rather than fragments, follows the links the authors wrote, sees who verified each concept and whether it is stale or deprecated, and can cite the concept id it answered from. Nothing is embedded or indexed ahead of time: every call reads the files, so an edit to the bundle is visible on the next tool call.

RAG wins on huge, unstructured corpora: thousands of documents with no structure to follow. kb_find is a plain scan: it parses every concept file on each call, which is fine for hundreds to a few thousand concepts and the wrong tool beyond that.

They combine. Give the agent a retriever for the long tail and the OKF tools for the curated core; with prefix you can mount several bundles in one agent.

What we learned building this in Astromesh

This library is the OKF reader of the Astromesh agent runtime (core 0.68.0, where spec.knowledge.bundle gives an agent these same three tools), extracted so that any framework can use it. These are the decisions that came out of running it.

Signals are annotated, never used to hide content. OKF §5.3 makes trust a signal for the reader, not a filter. A deprecated or unverified concept is still readable; it comes back with trust, stale, status and human-readable warnings. The one exception is search: kb_find skips deprecated concepts unless include_deprecated is true, because a search result is a recommendation and a retired policy should not be one.

Links come back already resolved. Models get relative paths wrong (../policies/x.md read from products/ is a classic). kb_read returns every body link as a concept id you can pass straight back to kb_read, marks external URLs, flags directories, says whether the target exists, and drops links that point outside the bundle.

The root index belongs in the system prompt. It does not change between questions, so putting Bundle(path).index("/") in the system prompt saves a tool call on every conversation and keeps the prompt prefix stable for prompt caching.

Tools never raise. Depending on the framework, a raised exception either ends the agent run or reaches the model as a traceback. Every error comes back as a JSON message the model can act on, and a missing concept comes with suggestions: {"error": "concept not found: policies/refund (did you mean: policies/refunds, policies/refunds-2024?)"}.

Models invent arguments. We saw limit="2", tags="finance" instead of a list and include_deprecated="false" as a string; strict-schema frameworks send null for every optional argument. Where the framework passes arguments straight through (plain functions and OKFTools, LlamaIndex, smolagents, Google ADK), the tool layer coerces them: numbers are parsed (with a default when they are not), a string tag becomes a list, "true"/"1"/"yes" mean true and any other string means false, and null means the default. LangChain, CrewAI, OpenAI Agents, Agent Framework, PydanticAI and MCP validate arguments against the schema first: they parse "2" and "false" themselves, reject what does not fit (limit="many", tags="finance") and report the error to the model so it can retry. Either way the agent loop does not crash.

Path confinement must resolve symlinks before checking. A concept id is a path from the model, so it is untrusted input. The path is resolved (following symlinks) and only then checked against the bundle root, and .md is appended before resolving: otherwise x.md as a symlink to /etc/passwd would be checked as x and read anyway.

Be tolerant, the spec says so. Per OKF §11 only two things make a concept invalid: frontmatter that does not parse (or is not a mapping) and a missing type. Unknown fields go to extra, an unreadable stale_after is ignored with a log warning, and v0.1 bundles read too. Indexes and search skip invalid concepts and count them (skipped_invalid); they are never fatal.

Verified against the real thing. Google's four sample bundles (acme_retail 9 concepts, crypto_bitcoin 9, ga4 9, stackoverflow 26) are indexed, searched and read end to end with zero concepts skipped, on every CI run (scripts/check_google_samples.py).

Small details that matter. The tool signatures use typing.Optional because Google ADK's schema builder rejects X | None. Tools return strings because that is what most frameworks expect back. Importing astromesh_okf imports no framework at all.

Frameworks

Framework Extra Import Example
LangChain / LangGraph langchain from astromesh_okf.integrations.langchain import okf_tools langgraph_agent.py
CrewAI crewai from astromesh_okf.integrations.crewai import okf_tools crewai_crew.py
Google ADK adk from astromesh_okf.integrations.adk import okf_tools adk_agent.py
OpenAI Agents SDK openai-agents from astromesh_okf.integrations.openai_agents import okf_tools openai_agents_agent.py
PydanticAI (Python 3.11+) pydantic-ai from astromesh_okf.integrations.pydantic_ai import okf_tools pydantic_ai_agent.py
LlamaIndex llamaindex from astromesh_okf.integrations.llamaindex import okf_tools llamaindex_agent.py
smolagents smolagents from astromesh_okf.integrations.smolagents import okf_tools smolagents_agent.py
Microsoft Agent Framework agent-framework from astromesh_okf.integrations.agent_framework import okf_tools agent_framework_agent.py
MCP (Claude Desktop, Claude Code, Cursor, any MCP client) mcp astromesh-okf mcp ./my-bundle examples/mcp/
Anything that takes Python functions none OKFTools("./my-bundle").functions() plain_python.py

Install with pip install 'astromesh-okf[<extra>]'. Every okf_tools(bundle, prefix="") returns the framework's own tool objects; the snippets below assume SYSTEM = "Answer using the knowledge base tools. Bundle index:\n" + Bundle("./my-bundle").index("/"). Model packages are separate: see docs/integrations.md.

CrewAI

from crewai import Agent
from astromesh_okf.integrations.crewai import okf_tools

agent = Agent(
    role="Support agent",
    goal="Answer from the bundle",
    backstory=SYSTEM,
    tools=okf_tools("./my-bundle"),
)

Google ADK

from google.adk.agents import Agent
from astromesh_okf.integrations.adk import okf_tools

agent = Agent(
    name="support", model="gemini-2.5-flash", instruction=SYSTEM, tools=okf_tools("./my-bundle")
)

OpenAI Agents SDK

from agents import Agent, Runner
from astromesh_okf.integrations.openai_agents import okf_tools

agent = Agent(name="support", instructions=SYSTEM, tools=okf_tools("./my-bundle"))
print(Runner.run_sync(agent, "Can I get a refund?").final_output)

PydanticAI

from pydantic_ai import Agent
from astromesh_okf.integrations.pydantic_ai import okf_tools

agent = Agent("openai:gpt-4.1-mini", tools=okf_tools("./my-bundle"), system_prompt=SYSTEM)
print(agent.run_sync("Can I get a refund?").output)

LlamaIndex

from llama_index.core.agent.workflow import FunctionAgent
from llama_index.llms.openai import OpenAI
from astromesh_okf.integrations.llamaindex import okf_tools

agent = FunctionAgent(
    tools=okf_tools("./my-bundle"), llm=OpenAI(model="gpt-4.1-mini"), system_prompt=SYSTEM
)


async def main():
    print(await agent.run("Can I get a refund?"))

smolagents

from smolagents import OpenAIModel, ToolCallingAgent
from astromesh_okf.integrations.smolagents import okf_tools

agent = ToolCallingAgent(
    tools=okf_tools("./my-bundle"), model=OpenAIModel("gpt-4.1-mini"), instructions=SYSTEM
)
print(agent.run("Can I get a refund?"))

Microsoft Agent Framework

from agent_framework import Agent
from agent_framework.openai import OpenAIChatCompletionClient
from astromesh_okf.integrations.agent_framework import okf_tools

agent = Agent(
    OpenAIChatCompletionClient(model="gpt-4.1-mini"), SYSTEM, tools=okf_tools("./my-bundle")
)

MCP — Claude Desktop (claude_desktop_config.json) or Cursor (.cursor/mcp.json):

{ "mcpServers": { "okf-support": { "command": "uvx", "args": ["--from", "astromesh-okf[mcp]", "astromesh-okf", "mcp", "/absolute/path/to/bundle"] } } }

Claude Code:

claude mcp add okf-support -- uvx --from 'astromesh-okf[mcp]' astromesh-okf mcp /absolute/path/to/bundle

Plain functions — named, typed, with Google-style docstrings written for the model:

from astromesh_okf import OKFTools

kb_index, kb_read, kb_find = OKFTools("./my-bundle").functions()

The three tools

Tool Arguments Returns
kb_index path="/" Markdown index of a directory
kb_read concept_id (required; a leading / and .md are accepted) JSON concept
kb_find text, type, tags, include_deprecated=False, limit=20 JSON search results

kb_index returns the directory's own index.md (frontmatter stripped) or, if it has none, a synthesized one in the OKF §8 format: subdirectories, then concepts as * [Title](/id) - description [Type, status, stale].

kb_read returns:

{
  "id": "policies/refunds", "type": "Policy", "title": "Refund policy",
  "description": "Customers can ask for a full refund within 30 days of purchase.",
  "status": "stable", "trust": "human-reviewed", "stale": false,
  "tags": ["support", "refunds"], "warnings": [],
  "extra": {
    "generated": {"by": "human:support-lead", "at": "2026-09-01T12:00:00+00:00"},
    "verified": {"by": "human:support-lead", "at": "2026-09-01T12:00:00+00:00"}
  },
  "body": "# Rule\n\nA full refund is available within 30 days...",
  "links": [{"id": "products/plans", "exists": true}, {"id": "policies/refunds-2024", "exists": true}]
}

Links are {"id", "exists"}, {"id", "dir": true, "exists"} for directories, or {"url", "external": true}.

kb_find matches type exactly (case-insensitive), requires all tags, and looks for text in title, description, tags and body, ranking header matches before body matches. limit is clamped to 1–100. It returns {"results": [{"id", "type", "title", "description", "status", "trust", "stale"}, ...], "skipped_invalid": 0}.

Errors come back as {"error": "..."}, never as an exception:

Message When
outside bundle: <input> the path resolves outside the bundle root (symlinks included)
concept not found: <id> + (did you mean: a, b?) no such concept; up to three close ids
not a concept: <id> a directory, index.md/log.md, or a non-Markdown file
not a directory: <path> kb_index on a path that is not an existing directory
invalid concept <id>: <reason> missing frontmatter, unterminated frontmatter, unparseable frontmatter (...), frontmatter is not a mapping, missing type, not UTF-8, unreadable (...)
invalid index: <path> an index.md that is not UTF-8 or cannot be read
bundle read failed: <detail> any other I/O error (permissions, a file removed mid-read)

Several bundles, one agent: prefix renames the tools.

tools = okf_tools("./support-kb", prefix="support_") + okf_tools("./finance-kb", prefix="finance_")
# support_kb_index, support_kb_read, support_kb_find, finance_kb_index, ...

Full reference: docs/tools.md.

Trust and freshness

Field How it is computed
trust from verified (one event or a list): human-reviewed if any by starts with human:, machine-confirmed if there is any other by, otherwise unverified
stale true once now is at or past stale_after (date, datetime or ISO string; no timezone means UTC)
status the frontmatter status, lowercased; stable when absent
warnings DEPRECATED: kept for history; do not use for new work. / STALE since <date>: may no longer be accurate. / DRAFT: not reviewed; may be incomplete.

Tell the agent what to do with them, for example:

Prefer concepts with trust human-reviewed. If a concept you rely on has warnings, say so in your answer. Never present a deprecated concept as current; follow its links to the one that replaces it. Cite the concept id you answered from.

CLI

astromesh-okf index ./my-bundle [path]          # print a directory index
astromesh-okf read  ./my-bundle policies/refunds  # one concept as JSON
astromesh-okf find  ./my-bundle --type Policy --tag refunds --text refund [--include-deprecated] [--limit 5]
astromesh-okf mcp   ./my-bundle [--prefix acme_]  # MCP server over stdio (needs the [mcp] extra)

Security

  • Read-only. Nothing writes to the bundle.
  • Confined to the bundle root. Every path is resolved, symlinks included, before it is checked: ../ escapes and symlinks pointing out are refused, body links that leave the bundle are dropped, and a leading / means the bundle root, not the filesystem root.
  • Only .md concepts are read; index.md and log.md are reserved, and search skips hidden files and dot-directories.
  • Nothing is executed. Scripts that sit next to concepts (for example the code behind OKF Attested Computations) are not concepts: kb_read refuses them and nothing runs them.
  • Bundle content is untrusted input to the model, like any tool result. A concept can carry a prompt injection. Mount only bundles you trust, and treat what the agent does with them like anything else it reads.
  • okflib (Google Cloud): store, query and validate bundles, with a CLI. Use it to write or validate bundles.
  • okf-agent-tools: tools for LangChain, PydanticAI and ADK.
  • okft: a linter for bundles plus an MCP server.
  • deep-wiki-agent: writer and reader agents for bundles, built on deepagents.

Pick astromesh-okf when you want trust-aware, never-raising navigation that behaves the same across many frameworks and MCP. Pick okflib (or okft) to validate or write bundles; they combine fine with this library.

Roadmap: not yet

  • Writing or editing bundles.
  • Validation / linting (use okflib or okft).
  • Remote bundles (git, tarball, HTTP): today a bundle is a local directory.
  • Async-native tools: today the tools are synchronous.

Contributing

Issues and pull requests are welcome. See CONTRIBUTING.md for setup, tests and how to add a framework adapter. Docs: concepts, tools, integrations, FAQ.

License

Apache-2.0.


Built by the Astromesh team — Monaccode.

Metadata

Release files for astromesh-okf 0.1.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 astromesh-okf 0.1.0
File Size Uploaded Provenance
astromesh_okf-0.1.0.tar.gz 51.3 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for astromesh-okf 0.1.0
File Interpreter ABI Platform
astromesh_okf-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 80.3 kB

Release files / astromesh_okf-0.1.0.tar.gz

Download URL astromesh_okf-0.1.0.tar.gz
Size 51.3 kB
Tags Source
SHA-256 checksum
How to use checksums
acb932dc0a6969a77b52588e3572c147b0b69f5136860818c1b83474b503c7cf
BLAKE2b-256 checksum
How to use checksums
a533ccf8f70e6cd22021dff6e11cba7c34b3d25d504675a1a417f18bc7c37730
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 14, 2026.

Transparency log

Release files / astromesh_okf-0.1.0-py3-none-any.whl

Download URL astromesh_okf-0.1.0-py3-none-any.whl
Size 29.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8be5fa9d80cbd331decc02f2f28b3b614d79f5fc7d7967ed15cb1f0aa20b2bab
BLAKE2b-256 checksum
How to use checksums
e99dcf840f718086009198c763516beec46abaf5d2346ea2afde34c9c6be94b3
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 14, 2026.

Transparency log

Security for astromesh-okf 0.1.0

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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for astromesh_okf-0.1.0.tar.gz

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 14, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

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