Skip to content

Prompt router #4

@egonelbre

Description

@egonelbre

@StevenACoffman mentioned in #3 that there isn't a prompt router.

When there's a large collection of rules then running every one of them could be really inefficient.

There are a few ideas how this could work.

Two-pass triage via the summary using categories

The summary pass already runs first. Add a categories field to the summary response (e.g. ["http",
"concurrency", "sql"]). After the summary, only run passes whose category matches. Cheap — one
extra field in an existing LLM call, no additional requests.

Two-pass triage via the summary using rules

The summary pass already runs first. Instead of adding category fields to the summary response
just give it the full list of rules available and let it decide what could be relevant.

Keyword/AST-based filtering (no LLM)

Before running passes, scan the function's imports and body for signals:

  • Imports net/http → run http pass
  • Contains go func or sync.Mutex → run concurrency pass
  • Contains sql. or Query → run correctness SQL checks
  • Is a _test.go file → run testing pass
  • Is main() or init() → run layout pass

Fast, deterministic, zero cost. Misses some things but catches the obvious cases. Can be combined
with other approaches as a pre-filter.

Since dreamlint is designed for in-depth passes, it's not great to skip rules.

Tag-based opt-in per pass

Add a match field to the pass schema:

pass: testing: {
    match: {files: "*_test.go"}
    inline_prompt: _prompt
}
pass: concurrency: {
    match: {imports: ["sync", "sync/atomic"]}
    inline_prompt: _prompt
}
pass: http: {
    match: {imports: ["net/http"]}
    inline_prompt: _prompt
}

Each pass declares what makes it relevant. The router checks before dispatching.
User-configurable, no LLM cost, predictable.

The drawback is that sometimes these packages end up being used indirectly.

Hierarchical: coarse then fine

Combine approaches — AST filter first (free), then LLM triage on the remaining ambiguous cases.
For example: if a function clearly has no concurrency primitives, skip the concurrency pass
without asking. If it's unclear, let the summary categorize it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions