@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.
@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:
Fast, deterministic, zero cost. Misses some things but catches the obvious cases. Can be combined
with other approaches as a pre-filter.
Since
dreamlintis 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:
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.