Documentation Index
Fetch the complete documentation index at: https://reasonblocks.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
CodebaseMemory is a persistent findings store scoped to a codebase ID. It lets an agent store observations during a run — bug locations, behavioral notes, architectural patterns — and retrieve them semantically on future runs. This turns isolated one-shot reviews into a growing knowledge base that gets more useful with every run.
Initialize CodebaseMemory
from reasonblocks.codebase_memory import CodebaseMemory
memory = CodebaseMemory(
codebase_id="pydantic/pydantic", # any stable identifier for the repo
api_key="rb_live_...",
)
The codebase_id is your key for the findings store — all findings stored under the same ID are searchable together. A common pattern is org/repo or repo@sha:abc123 when you want to scope findings to a specific commit.
Pass the same codebase_id to both CodebaseMemory and rb.middleware(codebase_id=...) to align findings retrieval with E1 pattern scoping.
Store and recall findings
Storing a finding
finding_id = memory.store(
content="BaseModel.validate raises ValidationError on extra=forbid when unknown fields are present",
file_path="pydantic/main.py",
finding_type="behavior", # bug | behavior | pattern | note
)
store returns the finding ID on success, or None if the transport fails. Content is truncated at 8,000 characters; file_path at 512.
Recalling findings
results = memory.recall("validator error handling", top_k=5)
for r in results:
print(r["file_path"], r["score"], r["content"])
recall returns a list of dicts ordered by descending relevance score. Each dict contains content, file_path, finding_type, score, and any metadata you attached at store time.
You can raise or lower score_threshold (default 0.25) to control how broadly the search matches:
# Require higher relevance
results = memory.recall("validator error handling", top_k=3, score_threshold=0.5)
format_recall combines recall with a human-readable renderer. Use it when you want to return findings directly to an LLM as a tool observation string:
digest = memory.format_recall(
"validator error handling",
top_k=5,
score_threshold=0.25,
max_len=300, # truncate each finding's content to this length
)
print(digest)
# Found 2 relevant prior findings:
#
# --- [behavior] pydantic/main.py (relevance 0.82) ---
# BaseModel.validate raises ValidationError on extra=forbid ...
Other operations
List all findings
all_findings = memory.list_all()
Returns every finding stored for the codebase, unfiltered. Useful for auditing the cache before a run.
Batch store
count = memory.store_many([
{"content": "...", "file_path": "pydantic/main.py", "finding_type": "bug"},
{"content": "...", "file_path": "pydantic/validators.py", "finding_type": "behavior"},
])
print(f"Stored {count} findings")
Each dict must have at least content; file_path, finding_type, and metadata are optional.
Check cache coverage
coverage_for tells you what fraction of a file list has at least one finding stored. Use it to decide whether the agent can answer from cache or needs extra tooling:
files_to_review = ["pydantic/main.py", "pydantic/validators.py", "pydantic/fields.py"]
coverage = memory.coverage_for(files_to_review)
if coverage < 0.5:
print("Cache is sparse — agent should do a full review")
else:
print(f"Cache covers {coverage:.0%} of files")
Invalidate stale findings
When files change, their cached findings may be stale. Call invalidate with a list of file paths to drop all findings for those files:
deleted = memory.invalidate(["pydantic/main.py", "pydantic/validators.py"])
print(f"Removed {deleted} stale findings")
Clear the entire cache
memory.clear() # drops all stored findings — irreversible
clear() deletes every finding for the codebase_id. This cannot be undone.
Combine with ImportGraph for blast-radius invalidation
When a file changes, you often want to invalidate not just that file’s findings but also every file that imports it. ImportGraph gives you that blast radius.
from reasonblocks.codebase_memory import CodebaseMemory
from reasonblocks.import_graph import ImportGraph
# Build the graph from your repo's Python source files
graph = ImportGraph()
graph.build_from_files({path: open(path).read() for path in py_files})
# A PR touched these files
changed_files = ["pydantic/main.py"]
# Expand to all affected files (direct importers, depth=1)
affected = graph.blast_radius(changed_files, depth=1)
# Invalidate findings for the whole affected set
deleted = memory.invalidate(list(affected))
print(f"Invalidated {deleted} findings across {len(affected)} files")
ImportGraph.build_from_files requires networkx. Install it with pip install networkx.
You can also print a human-readable impact summary for a specific file:
print(graph.format_impact("pydantic/main.py"))
# Impact analysis for pydantic/main.py:
# Imported by 12 files (dependents -- affected if this file breaks):
# <- pydantic/__init__.py
# <- pydantic/generics.py
# ...
# Imports 3 files (dependencies -- this file relies on):
# -> pydantic/fields.py
# ...
ReasonBlocks ships tool factories for each supported framework. Pick the one that matches your setup.
LangChain
OpenAI Agents
Anthropic Messages API
make_langchain_tools returns @tool-decorated functions compatible with create_agent and LangGraph.from langchain.agents import create_agent
from reasonblocks.codebase_memory import CodebaseMemory
from reasonblocks.import_graph import ImportGraph
from reasonblocks.integrations.langchain_tools import make_langchain_tools
memory = CodebaseMemory(codebase_id="my-org/my-repo", api_key="rb_live_...")
graph = ImportGraph().build_from_files(py_files)
rb_tools = make_langchain_tools(
memory,
graph,
recall_top_k=5,
recall_threshold=0.25,
enable_recall=True,
enable_store=True,
enable_impact=True,
)
agent = create_agent(
model="anthropic:claude-sonnet-4-20250514",
tools=[*rb_tools, search_codebase, read_file],
system_prompt="Call recall_findings before reading any file.",
middleware=[rb.middleware(codebase_id="my-org/my-repo")],
)
make_openai_tools returns function_tool-decorated callables for Agent(tools=[...]).from agents import Agent, Runner
from reasonblocks.codebase_memory import CodebaseMemory
from reasonblocks.integrations.openai_agents import make_openai_tools
memory = CodebaseMemory(codebase_id="my-org/my-repo", api_key="rb_live_...")
rb_tools = make_openai_tools(
memory,
recall_top_k=5,
recall_threshold=0.25,
enable_recall=True,
enable_store=True,
)
agent = Agent(
name="reviewer",
instructions="Call recall_findings before reading any file.",
tools=[*rb_tools],
)
make_claude_tools returns (tool_specs, dispatch) for the Anthropic Messages API’s tool-use format.import anthropic
from reasonblocks.codebase_memory import CodebaseMemory
from reasonblocks.integrations.claude_tools import make_claude_tools
client = anthropic.Anthropic()
memory = CodebaseMemory(codebase_id="my-org/my-repo", api_key="rb_live_...")
tool_specs, dispatch = make_claude_tools(memory)
resp = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=4096,
tools=tool_specs,
messages=[{"role": "user", "content": "Find any validator bugs."}],
)
# Handle tool_use blocks
for block in resp.content:
if block.type == "tool_use":
result = dispatch(block.name, block.input)
# ... send tool_result back in the next turn ...
For a full agentic loop without manual turn management, use run_messages_agent_loop:from reasonblocks.integrations.claude_tools import (
make_claude_tools,
run_messages_agent_loop,
)
tool_specs, dispatch = make_claude_tools(memory)
output = run_messages_agent_loop(
client,
model="claude-sonnet-4-20250514",
messages=[{"role": "user", "content": "Find any validator bugs."}],
tool_specs=tool_specs,
dispatch=dispatch,
system="Call recall_findings before reading any file.",
)
print(output["final_text"])