# How no-mistakes Intent Detection Works: Extracting Developer Intent from AI Transcripts

> Discover how the no-mistakes intent detection system extracts developer intent from AI transcripts. Learn its five-stage pipeline for session discovery, code matching, and prompt generation.

- Repository: [Kun Chen/no-mistakes](https://github.com/kunchenguid/no-mistakes)
- Tags: deep-dive
- Published: 2026-07-02

---

**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`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/intent/reader_claude.go) and [`internal/intent/reader_codex.go`](https://github.com/kunchenguid/no-mistakes/blob/main/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`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/intent/matcher.go), the matcher extracts file paths mentioned in each transcript using regex patterns defined in [`regex.go`](https://github.com/kunchenguid/no-mistakes/blob/main/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`](https://github.com/kunchenguid/no-mistakes/blob/main/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`](https://github.com/kunchenguid/no-mistakes/blob/main/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`](https://github.com/kunchenguid/no-mistakes/blob/main/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`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/intent.go) file orchestrates the entire flow by constructing an `ExtractParams` struct and invoking `intent.Extract`.

```go
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:

```go
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`](https://github.com/kunchenguid/no-mistakes/blob/main/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`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/intent/matcher.go) | File-overlap scoring logic and threshold filtering |
| [`internal/intent/disambiguator.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/intent/disambiguator.go) | Multi-candidate resolution via LLM prompting |
| [`internal/intent/summarizer.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/intent/summarizer.go) | Plain-text prompt generation with safety constraints |
| [`internal/intent/cache.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/intent/cache.go) | Session-to-summary caching layer |
| [`internal/pipeline/steps/intent.go`](https://github.com/kunchenguid/no-mistakes/blob/main/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.go`](https://github.com/kunchenguid/no-mistakes/blob/main/matcher.go) ensures 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.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/intent/cache.go) prevents 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`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/intent/reader_claude.go), [`reader_codex.go`](https://github.com/kunchenguid/no-mistakes/blob/main/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`](https://github.com/kunchenguid/no-mistakes/blob/main/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`](https://github.com/kunchenguid/no-mistakes/blob/main/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`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/intent/cache.go) stores session-to-summary mappings to avoid redundant LLM calls across multiple pipeline runs.