Skip to content
DocumentationReferencev1.2.1

Architecture

The local diagnostic pipeline, its stateful layers, and the boundaries between them.

Signalint is a local stdio MCP server. Engine adapters produce normalized diagnostics; the cache, clustering, and session layers transform or retain that data. There is no hosted API between your project and the MCP client.

THE CHECK PATH LOCAL · STDIO
MCP clientTool arguments in · tool result back
stdio
Canonical project boundary
01
Validate & resolve

Strict tool inputs. Canonical paths. Refuse project escapes.

02
Snapshot & select engines

Requested files, workspace plan, configuration and TypeScript source metadata.

Matching cache

Reuse stored normalized results when the engine's cache key matches.

content-hash state
Engine adapters

File-local misses.
TypeScript's configured program.

independent outcomes
03
Normalized diagnostics

Engine-independent issues. File checks filter displayed paths.

Optional external input

Caller-supplied LSP diagnostics and report normalizers. No built-in editor subscription.

04
Group rules & rank priorities

Repeated-rule clusters plus bounded, flat remaining records.

05
Snapshots & session history

Clone/freeze snapshots; require check IDs for detail/delta. Log events for recurrence and churn.

Check response · schema 1.4Clusters + remaining issues + active warnings
bothtextstructured
SEPARATE WRITE PATHPreview → explicit confirm → apply → check

Caller content. Path/hash preflight, optional baseline and adjacent replacements; in-memory best-effort rollback. Review transaction limits before enabling apply.

Result returns to the MCP client over stdio. Snapshots stay in the running server. Cache/session paths default to .signalint/ and can be redirected.
  1. The MCP client supplies tool arguments over stdio.
  2. Strict input validation resolves canonical paths and refuses project escapes.
  3. File snapshots, optional workspace planning and configured engine selection determine the work.
  4. Matching cached results are reused; engine adapters check file-local misses or the configured TypeScript program. These paths converge into normalized diagnostics.
  5. File checks filter displayed diagnostics to the requested paths; repeated rules are grouped and ranked.
  6. The server stores deep-cloned/frozen check snapshots for required-ID detail and delta; persistent session state records events and detects recurrence/churn.
  7. Check results use schema 1.4 with clusters and flat remaining records, then return to the client through both, text, or structured mode.
LayerSource modulesResponsibility
Entry pointssrc/index.ts, src/cli.tsStart the server or dispatch CLI commands
MCP serversrc/server/Register tools, validate arguments, route handlers, retain diagnostic snapshots, live buffers and prepared transactions
Project boundarysrc/projectPaths.tsCanonicalize requested paths and refuse escapes
Engine executionsrc/engines/, src/subprocess.ts, src/engineFanout.tsResolve tools, normalize output, enforce process limits, preserve independent outcomes
Incremental cachesrc/checkFiles.ts, src/cache/sqliteCache.tsSnapshot inputs and reuse matching diagnostics
Clusteringsrc/cluster/clusterEngine.tsGroup repeated rules, rank clusters, produce bounded summaries
Retained diagnosticssrc/diagnostics/In-memory snapshots/delta, LSP buffer and supplied external report normalizers
Workspace planningsrc/workspace/Opt-in pnpm discovery and dependency/reference planning
Hook adapterssrc/hooks/Host event parsing, verification policy and emitted configuration
Explicit transactionssrc/transactions/Caller-provided preview, path/hash preflight, optional explicit baseline, adjacent replacements and in-memory rollback journal
Session statesrc/memory/Record history, detect recurrence, rotate logs, aggregate metrics

Adapters are the modules that invoke diagnostic engines. Higher layers work with NormalizedIssue objects instead of shell output.

Oxlint, Biome, and ESLint are treated as file-local engines. Matching snapshots are reused; misses are submitted in batches.

TypeScript stays whole-program. Requested content snapshots and a source-file metadata fingerprint control invalidation, but the compiler receives its configured program. File-check results are then filtered to requested paths. The first project target selects a TypeScript config; file checks use a root runner with a separate hash probe. Normal configs use project mode; configs reporting references use build mode. See caching for the fingerprint and configuration-selection boundaries.

Enabled engine tasks run concurrently and settle independently. Normal engine-task failures preserve fulfilled tasks; config-loading or snapshot I/O failures can occur before that fan-out. The response marks each engine ok, disabled, or error; any error makes the top-level status error.

Subprocesses have deadlines, output budgets, and cancellation handling. Shutdown attempts process-tree termination before closing cache handles and the transport; termination failures are logged.

SQLite cache lock contention waits up to 5 seconds; this is not a guarantee that longer locks succeed. Session-memory updates are serialized through a promise queue within each process. This ordering is distinct from engine execution and does not make every project operation an operating-system transaction.

.signalint/
├── cache.sqlite # Diagnostic cache
├── cache/tsc/<project-id>/ # Normal project-mode TypeScript build info
├── session.jsonl # Check history and metrics
└── session.jsonl.1 # Rotated history backup, when present

SIGNALINT_STATE_DIR redirects supported cache/session/project-mode state. TypeScript build mode can write .tsbuildinfo files elsewhere at native/configured locations. Snapshots (50 / 30 minutes), the live buffer (10,000 entries), and prepared transactions (20 / 15 minutes) are in-memory stores, not this disk tree.

The cache defaults to 10,000 file-result rows with LRU eviction; identical-content paths can share a key. Session replay and log rotation are bounded. These are local artifacts, not source files; keep them out of Git.

ingest_diagnostics accepts supplied LSP-shaped batches; get_live_diagnostics merges them with the newest retained non-LSP snapshot and returns a full normalized array, not a 100-issue-bounded check. External-language adapter exports normalize reports but do not launch additional engines.

after_edit_check can compare a new scoped check to a retained baseline. Delta is heuristic and coverage-sensitive. Hook event adapters use a separate policy path with documented cluster/configuration gaps.

preview_diagnostic_fix stages full-file patches; only explicit apply_diagnostic_fix writes them. Apply preflight revalidates paths/content hashes and an optional supplied baseline before sequential adjacent replacements. The rollback journal is in memory, not an all-files atomic transaction or persistent crash recovery. Without an explicit baseline no delta is requested; post-verification failure still does not undo writes. See transactions.

Tool arguments are untrusted even when supplied by an authorized agent. Native check paths are checked lexically and after symlink/junction resolution. Apply also performs containment preflight in 1.2.1; neither path is a lock against adversarial external filesystem changes.

That boundary does not sandbox engine plugins, imports, or trusted configurations. Child engines run with your account’s permissions. See security.

Handlers no longer retain mutable latestIssues/latestCheckId state. get_issue_detail requires a check ID; the live view explicitly selects a retained non-LSP snapshot. Retrieved snapshot copies do not mutate stored data, but content-derived IDs can still repeat.

Both/structured modes mirror the structured object in the first JSON text block (except literal-pong). Structured mode adds a user-facing summary rather than removing diagnostic JSON. Thrown check-provider failures use classified tool errors; ordinary settled engine failures preserve per-engine diagnostic outcomes.