Partially implemented. TermAl ships an instruction search/debugger workspace
tab backed by GET /api/instructions/search. The full provenance graph and
effective-stack model below remains future design work.
This brief describes a provenance and debugging surface for agent instruction
documents such as CLAUDE.md, AGENTS.md, GEMINI.md, and related
Markdown-based prompt files.
Related: Code Navigation MCP follows the same principle of returning compact, provenance-rich navigation context instead of forcing agents to read broad file sets.
The current instruction-file story is opaque.
When a user opens an instruction document, they can read what it says, but they cannot answer the harder debugging questions:
This is a real debugging workflow, not just documentation browsing. The user is effectively debugging a resolution system made of Markdown files, path scopes, agent-specific hierarchy rules, and local conventions.
Today TermAl already has:
.claude/commands/*.mdWhat is missing is an instruction-specific provenance model.
Add an Instruction Debugger that answers:
The debugger should expose three complementary views:
The graph is useful, but it is not the primary debugging surface. The primary surface is the trace and reverse root search.
The debugger should support reverse provenance queries:
This is closer to a gcroot-style query than a simple tree inspector.
The important output is not “who is the parent?” but:
By default, the debugger should prefer completeness over brevity. The user can collapse to shortest path or active-only path after the full root set is known.
The feature needs to distinguish between two related but different questions.
How did this Markdown file become part of the active instruction set?
Examples:
AGENTS.md.claude/commands/review-code.md was loaded because the user invoked
/review-code.claude/reviewers/How did this specific paragraph, heading section, or instruction block survive resolution and become effective?
Examples:
AGENTS.mdIf TermAl only models document provenance, the user still cannot debug why a specific instruction is active. The debugger needs both levels.
TermAl does not own the instruction semantics of every agent runtime. Some resolution steps are directly observable from local files; others are only inferable from known agent conventions.
The debugger should make that explicit.
Each discovered relation should carry a provenance quality:
observed - directly confirmed from local files or explicit runtime metadatadeclared - defined by a TermAl-managed convention such as command discoveryinferred - best-effort explanation based on known agent rulesThis prevents the UI from presenting guessed causality as hard truth.
Recommended entry points:
Instruction Debugger workspace tabWhy is this here? action when an instruction file is open in source viewDebug instructions action from the session pane for the current sessionThe trace view is the highest-value workflow.
Example:
AGENTS.md
-> activated for project root
-> subdirectory scope matched src/**
-> docs/agents/backend.md became active
-> instruction at docs/agents/backend.md:12 won precedence
-> overrides AGENTS.md:44
For each step, show:
observed, declared, inferred)The trace view should support:
full roots mode: show every reachable root and pathactive only mode: show only paths active in the current contextshortest path mode: collapse each root to its shortest explanation chainFor a selected session and optional file path, show:
This is the equivalent of a compiler include list or CSS cascade inspector.
The graph view is the overview and navigation layer.
Nodes:
Edges:
discoversincludesscopesactivatesoverridesreferencesGraph interactions:
The graph should not flatten all relations to file-to-file edges. Where possible, an edge should originate from a specific span or line range inside the source file so the user can answer “which line pulled that file in?”
The search view answers:
Search flow:
dependency injectionEach result should show:
Show all rootsShow graphExample:
Match: .claude/reviewers/rust.md:9
"Prefer dependency injection where ownership boundaries are unstable."
Roots:
- CLAUDE.md
-> reviewers.md:12
-> .claude/reviewers/rust.md:9
- AGENTS.md
-> docs/agents/backend.md:18
-> .claude/reviewers/rust.md:9
Every view should feed the same right-side inspector with:
Every debugger query should be evaluated against an explicit context:
struct InstructionResolutionContext {
session_id: String,
agent: Agent,
workdir: String,
target_path: Option<String>,
command_name: Option<String>,
project_id: Option<String>,
}
Without context, “is this active?” is not answerable.
The same file may be active for one session, inactive for another, and only conditionally active for a given command or subdirectory.
The debugger should distinguish between two classes of roots.
These are top-level entry points in the instruction system, for example:
CLAUDE.mdAGENTS.mdGEMINI.md.cursor/rulesThese are context anchors that explain why a structural root mattered for this resolution:
Claude/review-codesrc/api.rsBoth root classes matter. A structural root without activation context does not fully explain why the span is relevant, and activation context without the structural root does not show where the instruction came from.
struct InstructionDocument {
id: String,
path: String,
kind: InstructionDocumentKind,
title: Option<String>,
discovered_by: ProvenanceKind,
applies_to_agents: Vec<Agent>,
}
Examples of kind:
RootInstructionSubdirectoryInstructionCommandInstructionReviewerInstructionReferencedInstructionstruct InstructionSpan {
id: String,
document_id: String,
line_start: u32,
line_end: u32,
heading_path: Vec<String>,
text: String,
}
This is the unit the user actually debugs. A span is usually a paragraph, section, or command block, not a whole file.
struct ProvenanceEdge {
id: String,
from_id: String,
to_id: String,
relation: ProvenanceRelation,
condition: Option<String>,
matched: bool,
precedence: Option<i32>,
provenance_kind: ProvenanceKind,
detail: Option<String>,
}
Examples of relation:
DiscoversScopesActivatesIncludesOverridesReferencesstruct EffectiveInstruction {
span_id: String,
active: bool,
precedence_rank: i32,
overridden_span_ids: Vec<String>,
overridden_by_span_id: Option<String>,
explanation: Vec<String>,
}
struct InstructionRootPath {
match_span_id: String,
root_id: String,
activation_root_ids: Vec<String>,
edge_ids: Vec<String>,
active: bool,
shortest: bool,
}
This is the core result shape for phrase search and full-root trace queries.
Add agent-specific instruction adapters that know how to discover candidate documents and explain known hierarchy rules.
Examples:
ClaudeInstructionAdapterCodexInstructionAdapterGeminiInstructionAdapterCursorInstructionAdapterEach adapter should:
observed, declared, or inferredThis follows the same general adapter shape already used elsewhere in TermAl for agent-specific runtime differences.
Build a backend index keyed by workdir plus agent type.
The index should cache:
Invalidate when:
Given a resolution context:
The losing candidates matter. A debugger that only returns the winners cannot explain why something disappeared.
Given a selected span or phrase match:
The backend should not stop after finding the first parent or first root.
GET /api/instructions/graph?sessionId={id}&targetPath={path?}
Returns:
{
"documents": [],
"spans": [],
"edges": [],
"context": {},
"summary": {
"activeDocuments": 0,
"activeSpans": 0,
"inactiveSpans": 0,
"overrideEdges": 0
}
}
Purpose:
GET /api/instructions/effective?sessionId={id}&targetPath={path?}&commandName={name?}
Returns the ordered list of active and inactive candidate instruction spans for the current context.
GET /api/instructions/trace?sessionId={id}&spanId={id}
Returns the causal chain for one span, including:
GET /api/instructions/search?sessionId={id}&q={phrase}&targetPath={path?}&commandName={name?}
Returns:
{
"matches": [
{
"spanId": "span-1",
"path": ".claude/reviewers/rust.md",
"lineStart": 9,
"lineEnd": 9,
"text": "Prefer dependency injection where ownership boundaries are unstable.",
"active": true,
"rootCount": 2,
"activeRootCount": 1
}
],
"paths": [],
"roots": [],
"context": {}
}
Purpose:
gcroot-style explanation of how the phrase is reachableRecommended helper endpoint:
GET /api/instructions/source?sessionId={id}&path={file}
Purpose:
Add a new workspace tab kind:
instructionDebuggerThis should fit the existing generic workspace tab system rather than becoming a special overlay. The user should be able to keep the debugger open alongside a session, source editor, diff preview, filesystem, and git status.
Recommended layout for the debugger tab:
Recommended top-bar controls:
Trace | Effective | Graph | Search mode switchClicking any document or span should:
When the current source tab is an instruction file, TermAl should offer a contextual action:
Why is this here?Find roots for selected phraseThat action should open the debugger focused on the clicked line or nearest instruction span. If the user has a text selection, the debugger should open in Search mode seeded with that phrase.
The debugger should surface problems directly in the UI:
These are not secondary details. They are often the actual bug.
An Obsidian-style canvas is useful as a presentation layer, but it should be built on top of the native provenance model, not instead of it.
Recommended order:
.canvas / JSON CanvasThat keeps the feature grounded in debugging value instead of treating the graph as the product.
GET /api/instructions/graphGET /api/instructions/effectiveGET /api/instructions/traceGET /api/instructions/searchinstructionDebugger tab supportWhy is this here? action from source viewFind roots for selected phrase from source viewBackend:
Frontend:
Why is this here?dependency injection and see every
reachable root and path that explains that phrase.Instruction files are not passive notes. They are part of the execution environment for the agent.
If the user cannot explain where an instruction came from, they cannot trust the agent’s behavior, and they cannot safely evolve a hierarchical Markdown-based instruction system. The instruction debugger turns that opaque behavior into something inspectable, navigable, and debuggable.