How no-mistakes Intent Detection Works: Extracting Developer Intent from AI Transcripts
The no-mistakes intent detection system extracts developer intent from AI assistant transcripts through a five-stage pipeline that discovers sessions, matches them to code changes, and generates plain-text prompts for downstream LLM consumption.
The no-mistakes repository provides a deterministic pipeline for converting AI assistant conversation transcripts into structured, actionable prompts. Located in the internal/intent package, this no-mistakes intent detection system bridges the gap between informal developer conversations with tools like Claude, Codex, and Copilot and the structured inputs required for automated code review and fixing.
The Five-Stage Intent Extraction Pipeline
The pipeline lives entirely in internal/intent and processes transcripts through discrete, auditable stages. Each stage is implemented as a separate component with clear responsibilities.
Stage 1: Discover – Scanning Agent Transcripts
The Discover stage uses agent-specific Readers to scan local transcript stores for sessions within a defined time window. Each reader implements the Reader interface and targets a specific AI assistant.
In internal/intent/reader_claude.go and internal/intent/reader_codex.go (alongside similar files for Opencode, Pi, and Copilot), the Discover method scans directories like ~/.no-mistakes/agents/claude/… for sessions falling between BaseTime and HeadTime, plus an optional SlackDays buffer. The readers return a slice of Session structs containing the raw transcript text and metadata.
Stage 2: Match – File Overlap Scoring
The Match stage computes relevance between discovered sessions and the current Pull Request diff. In internal/intent/matcher.go, the matcher extracts file paths mentioned in each transcript using regex patterns defined in regex.go, then calculates a file-overlap score against the PR's DiffFiles.
Sessions exceeding the ExtractParams.Threshold (typically 0.6) proceed to the next stage. Sessions below this threshold are discarded, preventing irrelevant conversations from polluting downstream prompts.
Stage 3: Disambiguate – Resolving Multiple Candidates (Optional)
When multiple sessions pass the matching threshold, the Disambiguator (implemented in internal/intent/disambiguator.go) constructs a secondary prompt asking an LLM to select the most relevant session. The prompt includes candidate session IDs, the diff file list, and transcript file paths.
This stage only executes when ExtractParams includes a configured Disambiguator. The chosen session ID is then passed to the summarization stage, ensuring the pipeline extracts intent from the correct conversation context.
Stage 4: Summarise – Generating the Plain-Text Prompt
The Summarizer in internal/intent/summarizer.go converts the selected transcript into a safe, structured prompt via NewAgentSummarizer. The BuildPrompt method constructs a prompt that explicitly:
- Requests a one-sentence plain-text summary
- Forbids Markdown formatting
- Includes only user-provided intent (never raw tool output)
- Appends an "untrusted data" disclaimer
The resulting summary is stored in Result.Summary and returned to the caller. This plain-text constraint ensures downstream steps can safely feed the output into other LLM prompts without injection risks.
Stage 5: Cache – Avoiding Duplicate LLM Calls
Before any summarization, the system checks internal/intent/cache.go. The Cache interface (implemented via NewDBCache) stores previous SessionID to Summary mappings. If a transcript has been processed before, the cached Summary returns immediately, eliminating redundant LLM calls and reducing API costs.
Pipeline Orchestration in intent.go
The internal/pipeline/steps/intent.go file orchestrates the entire flow by constructing an ExtractParams struct and invoking intent.Extract.
params := intent.ExtractParams{
HomeDir: homeDir,
OriginCWD: repoPath,
DiffFiles: diffFiles,
BaseTime: baseTime,
HeadTime: headTime,
SlackDays: 3,
Threshold: 0.6,
Readers: []intent.Reader{
intent.NewClaudeReader(),
intent.NewCodexReader(),
intent.NewOpencodeReader(),
intent.NewPiReader(),
intent.NewCopilotReader(),
},
Cache: intent.NewDBCache(sctx.DB),
Summarizer: intent.NewAgentSummarizer(sctx.Agent, sctx.WorkDir),
Disambiguator: intent.NewAgentDisambiguator(sctx.Agent, sctx.WorkDir),
}
res, err := intent.Extract(ctx, params)
if err != nil && err != intent.ErrNoMatch {
return fmt.Errorf("intent extraction failed: %w", err)
}
if res != nil {
db.SetRunIntent(runID, res.Summary, res.AgentName, res.SessionID, res.Score)
}
The Extract function returns a Result struct containing Summary, AgentName, SessionID, and a confidence Score, or returns intent.ErrNoMatch when no relevant transcript exists.
Extending the System with Custom Readers
Developers can implement custom readers for additional AI assistants by satisfying the Reader interface:
type MyAgentReader struct{}
func (r *MyAgentReader) Name() string { return "my-agent" }
func (r *MyAgentReader) Discover(ctx context.Context, opts intent.DiscoverOpts) ([]*intent.Session, error) {
// Scan transcript directory for files between opts.WindowStart and opts.WindowEnd
// Return []*intent.Session with raw transcript content
}
Key Implementation Files
| File | Role |
|---|---|
internal/intent/intent.go |
Public API: Extract, Result, ExtractParams, ErrNoMatch |
internal/intent/reader_*.go |
Agent-specific transcript discovery (Claude, Codex, Opencode, Pi, Copilot) |
internal/intent/matcher.go |
File-overlap scoring logic and threshold filtering |
internal/intent/disambiguator.go |
Multi-candidate resolution via LLM prompting |
internal/intent/summarizer.go |
Plain-text prompt generation with safety constraints |
internal/intent/cache.go |
Session-to-summary caching layer |
internal/pipeline/steps/intent.go |
Pipeline orchestration and wiring |
Summary
- The no-mistakes intent detection pipeline extracts developer intent from AI assistant transcripts through five deterministic stages: Discover, Match, Disambiguate, Summarise, and Cache.
- File-overlap scoring in
matcher.goensures only relevant sessions (exceeding the 0.6 threshold) proceed to summarization. - The Summarizer enforces plain-text output with explicit Markdown prohibition and security disclaimers, making the output safe for downstream LLM consumption.
- Caching via
internal/intent/cache.goprevents redundant LLM calls by storing previously extracted summaries. - The system supports Claude, Codex, Opencode, Pi, and Copilot through modular reader implementations in
internal/intent/reader_*.go.
Frequently Asked Questions
What AI assistants does no-mistakes support for intent detection?
The system supports Claude, Codex, Opencode, Pi, and Copilot through dedicated reader implementations in internal/intent/reader_claude.go, reader_codex.go, and similar files. Each reader implements the Reader interface to scan agent-specific transcript directories. You can extend support for additional assistants by implementing the Discover method to return []*intent.Session structs containing transcript text and timestamps.
How does the matcher determine which transcript session is relevant?
The matcher in internal/intent/matcher.go extracts file paths mentioned in each transcript using regex patterns, then computes a file-overlap score against the current PR diff. Sessions scoring above the Threshold parameter (typically 0.6) are considered relevant. This ensures the pipeline only selects conversations that actually reference the code being modified.
What format does the generated prompt use?
The Summarizer in internal/intent/summarizer.go generates strictly plain-text prompts. The output explicitly forbids Markdown formatting, limits content to one sentence, and includes an "untrusted data" disclaimer. This constraint prevents prompt injection attacks and ensures safe consumption by downstream LLM steps.
Where is the extracted intent stored for later use?
The extracted Summary is stored on the run record via db.SetRunIntent(), which persists the summary text, agent name, session ID, and confidence score to the database. Additionally, the Cache implementation in internal/intent/cache.go stores session-to-summary mappings to avoid redundant LLM calls across multiple pipeline runs.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →