PostHog / PostHog/warlock

Add scanFiles(filePaths, llmProvider?) API for per-match content windowing

Open
#35 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
0
Forks
1
PR merge metrics
No merged PRs in 30d

Description

Why

Warlock today exposes `scan(content)` — single content blob in, matches out. Consumers that need to scan a directory of files (the wizard's skill-install scan, for example) end up building aggregation logic on top, which has two correctness pitfalls:

  1. Combined-buffer triage drops real attacks. If the consumer scans each file then concatenates everything into a `combined` string and passes `combined.slice(0, MAX_SCAN_LENGTH)` to `triageMatches`, matches whose evidence lives in files past the truncation cut are invisible to the triage LLM → biased toward `false_positive` → real violations get dropped.
  2. Per-file scan + cross-file aggregation is repeated boilerplate. Every consumer reinvents file reading, scan loops, match accumulation, and (incorrectly) triage windowing.

The wizard hit pitfall #1 in scanSkillFiles. The short-term fix on the wizard side is to triage per-file (each file's matches against that file's content), but the proper home for this abstraction is warlock.

Proposal

```ts
export interface ScanFilesOptions {
/** Per-file truncation cap (default: 100KB). /
maxScanLength?: number;
/
* Triage provider; omit to skip triage and return all flagged matches. */
llmProvider?: LLMProvider;
}

export async function scanFiles(
filePaths: string[],
options?: ScanFilesOptions,
): Promise<ScanMatch[]>;
```

Internals:

  • Read each file (parallel `fs.promises.readFile` is fine — disk I/O isn't the bottleneck).
  • Per-file: scan with the file's truncated content; collect matches via `matchesForContext`.
  • Per-file: triage with that file's content (not a combined buffer). Each match is judged against the evidence that produced it.
  • Aggregate triaged matches across all files; return.

Wizard caller would simplify to:

```ts
const matches = await warlock.scanFiles(files, { llmProvider });
```

…and the wizard's `scanSkillFiles` helper goes away.

Out of scope

  • Single-file content scanning (existing `scan(content)` stays as-is).
  • WASM init / cold-start optimization (separate concern).

🤖 Generated with Claude Code

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the existing scan(content) flow, especially matchesForContext and triageMatches. Add the scanFiles API with per-file reading, truncation, scanning, triage, and aggregation as described; done means matches from files beyond a combined-buffer cutoff are retained and triage uses each file's own content.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, backend
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
62/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.