CHAPTER 09 · Memory Outside the Weights · 3 / 5
Code MVP: a memory loader
"""
chapter 09: memory outside the weights.
Load layered project memory (AGENTS.md / CLAUDE.md up the tree, plus
path-scoped rules) into the project_instructions slot of Chapter 3's
PromptBuilder. 'More specific wins': files closer to cwd come last.
"""
import os
MAX_BYTES = 32 * 1024 # Codex's default AGENTS.md size cap
class MemoryLoader:
def __init__(self, project_root: str, instruction_names=("AGENTS.md", "CLAUDE.md")):
self.root = os.path.abspath(project_root)
self.names = instruction_names
def _dirs_from_root_to(self, cwd: str) -> list:
"""Every directory from project root down to cwd, root first."""
cwd = os.path.abspath(cwd)
parts, cur, chain = os.path.relpath(cwd, self.root).split(os.sep), self.root, [self.root]
for p in parts:
if p in (".", ""):
continue
cur = os.path.join(cur, p)
chain.append(cur)
return chain
def load_instructions(self, cwd: str = None) -> str:
cwd = cwd or self.root
chunks, budget = [], MAX_BYTES
# General first (root), specific last (cwd): later overrides earlier.
for d in self._dirs_from_root_to(cwd):
for name in self.names:
path = os.path.join(d, name)
if os.path.exists(path):
text = open(path, encoding="utf-8").read()[:budget]
budget -= len(text)
rel = os.path.relpath(path, self.root)
chunks.append(f"# from {rel}\n{text}")
return "\n\n".join(chunks)
def load_rules(self, touched_paths: list) -> str:
"""Path-scoped rules: include a rule only if a touched file matches."""
rules_dir = os.path.join(self.root, ".rules")
if not os.path.isdir(rules_dir):
return ""
active = []
for fn in sorted(os.listdir(rules_dir)):
# Convention: a rule file named 'backend.md' applies to backend/*.
scope = fn.rsplit(".", 1)[0]
if any(scope in p for p in touched_paths):
active.append(open(os.path.join(rules_dir, fn), encoding="utf-8").read())
return "\n\n".join(active)
if __name__ == "__main__":
# Build a tiny demo project tree.
os.makedirs("/tmp/demo_proj/backend", exist_ok=True)
open("/tmp/demo_proj/AGENTS.md", "w").write("Run tests with `pytest -q`.")
open("/tmp/demo_proj/backend/AGENTS.md", "w").write("Backend uses async SQLAlchemy.")
os.makedirs("/tmp/demo_proj/.rules", exist_ok=True)
open("/tmp/demo_proj/.rules/backend.md", "w").write("Never log raw SQL with secrets.")
loader = MemoryLoader("/tmp/demo_proj")
print("--- instructions for backend/ ---")
print(loader.load_instructions("/tmp/demo_proj/backend"))
print("--- active rules when editing backend/api.py ---")
print(loader.load_rules(["backend/api.py"]))
Run it and you will see the root instruction and the backend-specific instruction concatenated (general first, specific last), plus the backend rule activated only because a backend file was touched. Feed load_instructions() into PromptBuilder(project_instructions=...) and your agent now knows your project.