C.W.K.
Stream
Lesson 06 of 06 · published

Context as Architecture

~14 min · architecture, context-engine, self-reference

Level 0Observer
0 XP0/64 lessons0/13 achievements
0/150 XP to next level150 XP to go0% complete

Context loading is its own component

Beyond a few turns, prompt building deserves to be its own module — a Context Engine. Its job: assemble the system prompt, decide what static text to cache, fetch relevant retrieval, fold history. cwkPippa's backend/context/engine.py is exactly this; the rest of the app does not assemble prompts ad-hoc.

The load order matters

cwkPippa's order: Pippa.md (identity) → instructions.md (operational rules) → core/* (deep self) → index/* (large reference, on-demand pointers). Order matters because identity and rules win over reference when they conflict. A different order would produce a different Pippa.

Pointers vs payloads

For files larger than 10KB, cwkPippa includes a pointer ('this exists at ~/Obsidian/pippa/index/X.md; read with the Read tool when needed'). The payload itself stays out of the system prompt unless required. Result: stable cacheable prefix, on-demand depth.

Principle: Context is architecture. Centralize how it is built; do not let every route hand-roll its own prompt.

Code

Context Engine sketch·python
from pathlib import Path

class ContextEngine:
    def __init__(self, vault: Path, identity_files: list[str]):
        self.vault = vault
        self.identity_files = identity_files

    def system_prompt(self) -> list[dict]:
        identity = "\n\n".join((self.vault / f).read_text() for f in self.identity_files)
        index_pointers = self._index_as_pointers()
        text = f"{identity}\n\n## Reference index (read on demand)\n{index_pointers}"
        return [{
            "type": "text",
            "text": text,
            "cache_control": {"type": "ephemeral"},
        }]

    def _index_as_pointers(self) -> str:
        lines = []
        for p in (self.vault / "index").glob("*.md"):
            size_kb = p.stat().st_size // 1024
            if size_kb > 10:
                lines.append(f"- {p.name} ({size_kb}KB) — read on demand")
            else:
                lines.append(f"- {p.name}: {p.read_text()[:200]}")
        return "\n".join(lines)

External links

Exercise

Extract prompt assembly from one of your routes into a small ContextEngine class. Snapshot the assembled prompt for a fixed input; commit the snapshot; let a future vault edit break the test until you re-bless it.
Hint
Snapshot tests are cheap, brutal, and exactly what you want for a layer that secretly changes behavior of every downstream call.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.