# How to Optimize the Document+Lint Housekeeping Pass in no-mistakes

> Optimize the document+lint housekeeping pass in no-mistakes with early change detection, lazy prompt construction, and direct context passing. Improve efficiency now.

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

---

**The document+lint housekeeping pass in no-mistakes can be optimized through early change detection, lazy prompt construction, and direct context passing, despite already consolidating documentation and linting into a single agent invocation.**

The `no-mistakes` repository merges documentation and linting responsibilities into a unified housekeeping step whenever users omit a separate `lint` command configuration. While this consolidation eliminates redundant agent calls, the implementation in [`internal/pipeline/steps/document.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/document.go) and [`internal/pipeline/steps/lint.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/lint.go) still contains measurable overhead in prompt building, diff calculation, and JSON serialization that can be eliminated.

## How the Combined Pass Works Currently

The housekeeping architecture relies on a single agent invocation to perform both documentation updates and lint analysis, with results categorized and stored for retrieval by subsequent steps.

### Single Agent Invocation Architecture

According to [`internal/pipeline/steps/document.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/document.go) (lines 100–117), the `DocumentStep` evaluates a `combinedLint` flag to determine whether to bundle linting duties into the current execution. When active, the step constructs a unified prompt via `buildPrompt` (lines 194–202) that instructs the agent to handle both documentation generation and lint analysis within one request.

The `LintStep` then retrieves its specific results from this combined pass through `lintOutcomeFromHousekeeping` (lines 23–31 in [`internal/pipeline/steps/lint.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/lint.go)), which parses the shared output rather than executing a separate agent call.

### Stash-Based Result Categorization

Findings are separated using `splitHousekeepingFindings` (lines 292–300 in document.go), which partitions the agent's output into `"documentation"` and `"lint"` categories based on constants defined in [`internal/types/findings.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/types/findings.go) (lines 22–40). This categorization allows the `LintStep` to consume only relevant findings while maintaining the single-invocation contract verified by [`housekeeping_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/housekeeping_test.go) (lines 336–340).

## 5 Ways to Optimize the Housekeeping Pass

Despite the existing consolidation, five specific optimizations can reduce token usage, CPU cycles, and wall-clock time.

### 1. Skip Lint Duty for Non-Source Changes

The combined prompt currently includes lint instructions even when changes only affect Markdown files or other lint-irrelevant paths. By scanning the Git diff for source extensions (`.go`, `.js`, `.ts`, `.cpp`) before building the prompt, you can bypass lint duty entirely when no compilable files changed.

```go
func (s *DocumentStep) hasSourceChanges(baseSHA string) bool {
    // Very cheap diff: look for .go, .js, .ts, .cpp etc.
    diff, _ := exec.Command("git", "diff", "--name-only", baseSHA, "HEAD").Output()
    for _, f := range strings.Split(string(diff), "\n") {
        if strings.HasSuffix(f, ".go") || strings.HasSuffix(f, ".js") {
            return true
        }
    }
    return false
}

```

This check prevents unnecessary token usage for lint instructions that will never produce findings.

### 2. Build the Prompt Lazily

The `lintDutySection` function (lines 285–292 in document.go) currently appends the lint duty section to the prompt unconditionally. By making this injection conditional on the `combinedLint` boolean, you reduce context window consumption when linting is disabled.

```go
func lintDutySection(combinedLint bool) string {
    if !combinedLint {
        return ""
    }
    return fmt.Sprintf("\n%s\n", lintDutyPrompt())
}

```

This lazy construction improves the agent's ability to focus on documentation when linting is not required.

### 3. Pass Findings Directly via StepContext

Currently, `splitHousekeepingFindings` serializes results to JSON for the stash, and `lintOutcomeFromHousekeeping` deserializes them later. Eliminate this round-trip by passing the `[]Finding` slice directly through the step context.

```go
// In DocumentStep.Execute after the agent finishes:
sctx.HousekeepingLintResult = stash // stash is already a []Finding
return documentApprovalOutcome(summary), nil

```

This change removes JSON marshalling overhead and eliminates a potential source of deserialization bugs while preserving the contract between steps.

### 4. Cache Git Diff Results

The combined pass executes a fresh Git diff to determine what documentation needs updating. Cache the diff output when the same commit SHA has already been examined in the current run to prevent duplicate I/O on large repositories where multiple steps request identical diffs.

### 5. Parallelize Logical Duties via Batch API

While maintaining the single-invocation contract, you can split the agent request into two parallel sub-prompts sent concurrently to the same model using the model's batch API. This leverages parallel processing capabilities within the agent to reduce wall-clock time while still producing a single consolidated result.

## Key Source Files and Functions

| File | Relevant Sections | Optimization Target |
|------|------------------|---------------------|
| [`internal/pipeline/steps/document.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/document.go) | Lines 100–117 (`combinedLint`), 194–202 (`buildPrompt`), 285–292 (`lintDutySection`), 292–300 (`splitHousekeepingFindings`) | Prompt construction, result splitting |
| [`internal/pipeline/steps/lint.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/lint.go) | Lines 23–31 (`lintOutcomeFromHousekeeping`) | Result retrieval |
| [`internal/pipeline/steps/housekeeping_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/housekeeping_test.go) | Lines 336–340 | Single invocation contract verification |
| [`internal/types/findings.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/types/findings.go) | Lines 22–40 (category constants) | Finding type definitions |

## Summary

- **Early change detection** scans file extensions to skip lint duty when changes only affect documentation files, saving tokens
- **Lazy prompt construction** conditionally injects the `lintDutySection` only when `combinedLint` is true, reducing context size
- **Direct context passing** stores lint findings in `sctx.HousekeepingLintResult` to eliminate JSON serialization overhead
- **Diff caching** prevents redundant Git operations when multiple steps query the same commit SHA
- **Parallel sub-prompts** leverage the model's batch API to process documentation and lint duties concurrently while maintaining the single-call contract

## Frequently Asked Questions

### What is the document+lint housekeeping pass in no-mistakes?

The document+lint housekeeping pass is a unified execution step in [`internal/pipeline/steps/document.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/document.go) that handles both documentation generation and lint analysis within a single agent invocation. It activates when users have not configured a separate `lint` command, storing results in a categorized stash that `LintStep` later retrieves without triggering additional agent calls.

### How does no-mistakes currently combine documentation and linting?

The `DocumentStep` evaluates the `combinedLint` flag (lines 100–117 in document.go) to determine whether to bundle duties. It constructs a unified prompt via `buildPrompt` (lines 194–202) containing both documentation and lint instructions. The `LintStep` then extracts its specific findings via `lintOutcomeFromHousekeeping` (lines 23–31 in lint.go) from the shared stash populated by `splitHousekeepingFindings` (lines 292–300).

### Can the combined pass be optimized without breaking the single-invocation contract?

Yes. Optimizations such as lazy prompt construction, direct context passing via `sctx.HousekeepingLintResult`, and pre-checking file changes all preserve the single agent call while reducing latency. You can also use the model's batch API to send parallel sub-prompts concurrently, maintaining the contract while improving wall-clock performance.

### Where are the finding categories defined for the housekeeping pass?

The category constants `"documentation"` and `"lint"` are defined in [`internal/types/findings.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/types/findings.go) (lines 22–40). These constants enable the `splitHousekeepingFindings` function in document.go to route results correctly between the documentation and lint steps without mixing the two duty types.