ADR-0008: References-as-Files for Lazy Instructional Payloads¶
- Date: 2026-05-06
- Authors: Matteo Rizzo
- Status: Accepted
- Approval State: Approved (Approved by: Matteo Rizzo on 2026-05-06)
- Implementation State: Completed
1. Context and Problem Statement¶
Every skill ships instructional content the LLM uses to reason about how to call its tools: domain-specific guidance ("when querying Neo4j, prefer Cypher templates from cypher_templates.py"), error-recovery hints ("if Azure search returns empty, retry with the broader query template"), and operational notes ("environment variables that gate behavior"). Some of this lives in the skill's instructions: str attribute (which is short — a paragraph or two) and is always present in the agent's system prompt. The rest is voluminous and only relevant some of the time.
If we inline every skill's full guidance into instructions, the agent's system prompt becomes enormous — agents that import 8 skills carry 8 × multi-page guidance into every turn, blowing context budget on text the LLM may never need. If we omit the guidance entirely, the LLM has to guess how to use the tools.
The right design is a third path: keep instructions short, and ship the long-form guidance as files the LLM can load on demand through a tool call.
2. Decision Drivers (Forces)¶
- System-prompt thrift: The default per-skill prompt overhead should be a paragraph, not a page.
- Discoverability: The LLM must know what reference files exist for a given skill before deciding to load them.
- Versionability: Guidance evolves with the skill's implementation. The references should be source-controlled artifacts, not strings in code.
- Multi-format: Some references are markdown prose; some are config samples (
azure_search_config.md); some are code (scripts/sandbox_runner.py). The mechanism should be format-agnostic. - Cacheability: Loading a reference twice in one turn should hit a cache.
- Path safety: The LLM must not be able to load arbitrary files — only the references the skill author allowlisted.
3. Considered Options¶
- Option 1: Inline all guidance in
instructions. - Option 2: References-as-files plus a
load_skill_instructions(skill_name, reference)tool (chosen). - Option 3: A "fetch URL" tool for the LLM to pull guidance from a docs server.
- Option 4: RAG over the docs site.
4. Decision Outcome¶
Chosen option: Option 2 (references-as-files via the discovery skill), because it keeps long-form guidance versioned alongside the code that needs it, gates load to an allowlist, and incurs zero context cost until the LLM chooses to load.
Each skill subpackage ships a references/ directory:
mirai_shared_skills/
├── agentic_rag/
│ ├── skill.py
│ └── references/
│ └── azure_search_config.md
├── auth_gates/
│ ├── skill.py
│ └── references/
│ └── error_codes.md
├── browser/
│ ├── skill.py
│ └── references/
│ └── selectors.md
└── ...
The skill's SkillDescriptor enumerates its references via a tuple of paths:
SkillDescriptor(
name="agentic-rag",
references=("mirai_shared_skills/agentic_rag/references/azure_search_config.md",),
...
)
SkillDiscoverySkill exposes load_skill_instructions(skill_name: str, reference: str) which:
- Looks up the descriptor by
skill_name. - Verifies the requested
referenceis in the descriptor's allowlisted paths (rejects path traversal). - Loads and returns the file contents (markdown, code, or otherwise).
- Caches the result for the duration of the agent's turn.
The skill's short instructions field tells the LLM what references exist and when to load them:
class AgenticRAGSkill(BaseSkill):
instructions = """
Multi-source retrieval over graph + vector + web. For Azure-specific
configuration patterns, load reference 'azure_search_config.md' via
`load_skill_instructions`.
"""
4.1. Validation / Compliance¶
SkillDescriptor.referencesis atuple[str, ...]— immutable, hashable, type-checked.load_skill_instructionsraises a typed error on path-traversal attempts (any reference not in the allowlist).- Reference files are linted as part of the docs build (markdown validity for
.md; syntax check for.py).
5. Pros and Cons of the Options¶
Option 1: Inline everything¶
- Pros: No mechanism — the LLM always has the guidance.
- Cons: System-prompt bloat scales with skill count; pays context cost for guidance the LLM never reads.
Option 2 (chosen): References-as-files via discovery skill¶
- Pros:
- Short default prompt; rich guidance available on demand.
- Versioned alongside code.
- Allowlist prevents path traversal.
- Multi-format (markdown, code, config samples).
- Cons:
- Two-step process for the LLM (discover, then load) — but the prompt design makes this explicit.
Option 3: Fetch URL tool¶
- Pros: Guidance can live anywhere on the web.
- Cons: Network dependency; auth surface; outage risk; SSRF risk.
Option 4: RAG over docs site¶
- Pros: Search-driven discovery.
- Cons: Heavyweight for guidance the skill author already knows the LLM will need.
6. Consequences¶
- Positive Consequences:
- Skill prompts stay small. Eight skills add eight short paragraphs to the system prompt, not eight pages.
- Long-form guidance is git-versioned and discoverable in the codebase.
- The LLM gets the guidance only when it asks for it — context spend follows usage.
- Reference paths in
SkillDescriptorare searchable:find-skillsreturns them in its discovery payload, so the LLM sees what's available before loading. - Negative Consequences / Trade-offs:
- Authors must remember to wire new reference files into the descriptor's
referencestuple. PRs adding areferences/*.mdwithout updating the descriptor are caught by a registry-completeness test. - Risks & Mitigations:
- Risk: The LLM doesn't load the right reference and blunders. Mitigation: the short
instructionsfield names the relevant reference explicitly for known recovery patterns. - Risk: A reference is renamed in Git but the descriptor still points at the old name. Mitigation:
load_skill_instructionsraises a typedReferenceNotFoundErrorwith the descriptor's listed paths; tests assert every listed path resolves.
7. Implementation Plan & Status Updates¶
- Target Milestone/Release: v0.1.0 (current).
- Implementation Notes:
- 2026-05-06: ADR formalizes the existing implementation in
mirai_shared_skills/discovery/skill.pyand thereferences/directories per subpackage. No code changes.
8. References / Related Documents¶
mirai_shared_skills/discovery/skill.py—SkillDiscoverySkill.load_skill_instructions.mirai_shared_skills/_registry.py—SkillDescriptor.references.- ADR-0004: In-Process Skill Descriptor Registry — the registry that holds descriptor.references.
- Example references in this repo:
mirai_shared_skills/agentic_rag/references/azure_search_config.md,mirai_shared_skills/auth_gates/references/error_codes.md.