Skip to content
| Marketplace
Sign in
Visual Studio Code>Machine Learning>SilentSpecNew to Visual Studio Code? Get it now.
SilentSpec

SilentSpec

bharadwajmadduri

| (0) | Free
Auto-generates unit tests on file save using AI — silent, surgical, zero friction
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

SilentSpec

Stop rewriting tests every time AI runs.

SilentSpec generates only the tests you're missing — and never touches the ones you wrote.

VS Code Marketplace License

✔ Save a file → tests appear beside it
✔ Add a function → only that function gets tested
✔ Your hand-written tests are never touched

SilentSpec Demo

Before / After

Three exported functions, no tests:

// src/math.ts
export function add(a: number, b: number): number {
  return a + b;
}
export function multiply(a: number, b: number): number {
  return a * b;
}
export function clamp(n: number, min: number, max: number): number {
  return Math.min(Math.max(n, min), max);
}

After first save — spec file created automatically:

// src/math.spec.ts  (created beside source)
// @auto-generated by SilentSpec | 2026-04-05
// Functions covered: add, multiply, clamp
// <SS-IMPORTS-START>
import { add, multiply, clamp } from "./math";
// <SS-IMPORTS-END>
// <SS-HELPERS-START>
// <SS-HELPERS-END>
// <SS-USER-TESTS>
// Add your own tests here — SilentSpec will never modify this section
// </SS-USER-TESTS>
// <SS-GENERATED-START v="1" covered="add,multiply,clamp" pending="">
describe("add", () => {
  it("should add two positive numbers", () => {
    expect(add(2, 3)).toBe(5);
  });
  it("should handle negative numbers", () => {
    expect(add(-1, 1)).toBe(0);
  });
});
describe("multiply", () => {
  it("should multiply two numbers", () => {
    expect(multiply(3, 4)).toBe(12);
  });
  it("should return 0 when either operand is 0", () => {
    expect(multiply(5, 0)).toBe(0);
  });
});
describe("clamp", () => {
  it("should clamp value above max", () => {
    expect(clamp(10, 0, 5)).toBe(5);
  });
  it("should clamp value below min", () => {
    expect(clamp(-5, 0, 10)).toBe(0);
  });
  it("should return value when within range", () => {
    expect(clamp(3, 0, 10)).toBe(3);
  });
});
// <SS-GENERATED-END>

You add a 4th function and save again. Only divide gets a new test — everything else is untouched.

// SS-GENERATED-START marker after second save:
// <SS-GENERATED-START v="1" covered="add,multiply,clamp,divide" pending="">
//
// ↑ divide added to covered list
// ↑ new describe("divide", ...) appended below existing tests
// ↑ existing describe blocks for add, multiply, clamp — unchanged

Why SilentSpec

Most AI test tools regenerate entire files on every run. They overwrite the tests you wrote by hand, and the output often doesn't compile on the first try. You end up maintaining generated tests instead of writing features.

SilentSpec is different:

  • Only generates what's missing. It tracks which exported functions already have tests and only calls the AI for uncovered ones.
  • Your tests are protected. Hand-written tests live in the SS-USER-TESTS zone — a section that is never modified after creation. This is enforced at write time, not in the prompt.
  • Tests are compiler-checked before writing. After generation, SilentSpec runs a TypeScript compiler pass. When compile errors are detected, broken tests are removed before writing. On first generation of a new spec file, the healer verifies against the existing project — full diagnostic repair activates on subsequent saves. Semantic correctness still requires human review.

How It Works

Save file
   │
   ▼
Pre-debounce checks (untitled / non-file / no workspace / disabled / paused /
                      test file / unsupported ext / too large)
   │
   ▼
2-second debounce
   │
   ▼
Post-debounce checks (formatter re-save / unmanaged spec)
   │
   ▼
AST analysis — extract exported functions only
   │
   ▼
Compare covered list against current exports → compute gaps
   │
   ▼
AI call → validate response → fix imports
   │
   ▼
Healer — TypeScript compiler analysis → remove broken tests
   │
   ▼
Write spec file — 4-zone structure, SS-USER-TESTS never touched

Generation is batched: up to 5 functions per AI call. GitHub Models is additionally capped at 2–3 functions to stay within the free tier's output token limit. The SSMarker comment in the spec file tracks which functions are covered across saves, so each run only calls the AI for what's actually missing.


Zone Architecture

Four zones keep system-managed content separate from your tests:

// @auto-generated by SilentSpec | 2026-04-05
// Source: src/utils/formatting.ts
// Functions covered: formatCurrency, formatDate, truncate

// <SS-IMPORTS-START>                         ← SYSTEM: replaced every run
import { formatCurrency, formatDate, truncate } from "../utils/formatting";
jest.mock("date-fns", () => ({ format: jest.fn(() => "2026-01-01") }));
// <SS-IMPORTS-END>

// <SS-HELPERS-START>                         ← SYSTEM: replaced every run
const fakeCurrency = (amount: number, code: string) =>
  ({ amount, code }) as unknown as CurrencyInput;
// <SS-HELPERS-END>

// <SS-USER-TESTS>                            ← YOUR TESTS: never modified
// Write integration tests, complex mocks, edge cases the AI misses.
// SilentSpec will never modify this section — it's yours.
describe("formatCurrency — edge cases I care about", () => {
  it("should use parentheses for negative values in accounting mode", () => {
    expect(formatCurrency(-100, "USD", { style: "accounting" })).toBe(
      "(100.00)",
    );
  });
});
// </SS-USER-TESTS>

// <SS-GENERATED-START v="1" covered="formatCurrency,formatDate,truncate" pending="">
// ← SYSTEM: AI-generated tests, replaced when coverage changes
describe("formatCurrency", () => {
  /* ... */
});
describe("formatDate", () => {
  /* ... */
});
describe("truncate", () => {
  /* ... */
});
// <SS-GENERATED-END>

System zones (SS-IMPORTS, SS-HELPERS, SS-GENERATED) are fully replaced on each run. The SS-USER-TESTS zone is written once and never touched again.


Quick Start

1. Install

Search for SilentSpec in the VS Code Extensions panel, or install from the Marketplace.

2. Open a project

Open any TypeScript or JavaScript project folder. SilentSpec activates automatically.

3. Save a file

Save any .ts, .tsx, .js, or .jsx file that exports functions. A spec file appears in your existing __tests__ directory if one is present, or beside the source file otherwise.

Provider Setup

Provider Setting value Credential Notes
GitHub Models (default) github GitHub Personal Access Token Free, ~50 requests/day. No credit card.
Ollama (local) ollama None Auto-detected on activation. No internet required.
Claude claude Anthropic API key ~$0.003/generation. Best output quality.
OpenAI openai OpenAI API key ~$0.003/generation.

Set your provider: VS Code Settings → search silentspec.provider.

Set your API key: Command Palette (Cmd/Ctrl+Shift+P) → SilentSpec: Set API Key.

Ollama users: install Ollama from ollama.com, run ollama pull deepseek-coder:6.7b, then start Ollama before launching VS Code. SilentSpec detects it on activation and uses it automatically when no provider is explicitly set.


Supported Languages & Frameworks

Languages

TypeScript TSX JavaScript JSX

Frameworks (auto-detected from package.json)

Jest Vitest Mocha Jasmine

Framework is detected by walking up from the saved file to the nearest package.json that declares a known test framework. Monorepo sub-packages are detected independently.


Provider Comparison

Provider Default Model Free? Credential Rate Limit Approx Cost
GitHub Models gpt-4o Yes GitHub PAT ~50 req/day Free
Ollama auto (deepseek-coder:6.7b preferred) Yes None None (local) Free
Claude claude-sonnet-4-6 No Anthropic API key Per plan ~$0.003/generation
OpenAI gpt-4o No OpenAI API key Per plan ~$0.003/generation

Ollama model selection: SilentSpec prefers deepseek-coder:6.7b → deepseek-coder → codellama → llama3.2 in order of preference, picking the first installed model. Override with silentspec.model.


Configuration
Setting Type Default Description
silentspec.enabled boolean true Enable or disable all automatic test generation.
silentspec.provider string enum "github" AI provider: github, claude, openai, ollama.
silentspec.model string "" Model override. Leave empty to use the provider default.
silentspec.supportedExtensions string[] [".ts",".tsx",".js",".jsx"] File extensions that trigger generation.
silentspec.openSpecOnCreate boolean true Open the spec file in a split panel when first created.
silentspec.aiTimeoutSeconds number 60 Timeout for AI provider calls in seconds. Increase for slow connections or large files.
silentspec.maxFunctionsPerRun number 5 Max functions per AI call. GitHub Models is additionally capped at 2–3 functions to stay within the free tier's output token limit. Recommended: 3–5 for free-tier providers, up to 8 for paid.
Commands

All commands are available via the Command Palette (Cmd/Ctrl+Shift+P):

Command Title Description
silentspec.togglePause SilentSpec: Toggle Pause Pause or resume automatic generation. Status bar reflects current state.
silentspec.setApiKey SilentSpec: Set API Key Store your API key or GitHub token in encrypted SecretStorage.
silentspec.generateNow SilentSpec: Generate Tests for Current File Saves the active file, which enters the normal generation pipeline including the 2-second debounce.
silentspec.findGaps SilentSpec: Find Gaps in Current File Scan for uncovered exported functions and generate missing tests.
silentspec.showStats SilentSpec: Show Impact Report Display local generation statistics.
silentspec.openLog SilentSpec: Open Output Log Open the SilentSpec output channel with detailed generation logs.
silentspec.rebuildMarker SilentSpec: Rebuild Marker Recompute the SSMarker from existing spec content. Use if the marker gets out of sync.
silentspec.explainFailure SilentSpec: Explain Failure Show a human-readable explanation of the last generation failure.

File System Impact

Files Created

  • Spec files — .spec.ts (or .tsx / .js / .jsx) placed using a 5-pass algorithm: existing spec in adjacent __tests__ or test subfolder → existing spec in same directory as source → existing spec in root test directory (lookup only — never creates here) → new file in established adjacent test directory → new file beside the source as fallback. Collision detection uses the // Source: header to verify ownership before claiming an existing spec file.
  • globalStorageUri/stats.json — local telemetry, in a VS Code-managed directory.

Files Modified

  • Existing SilentSpec-managed spec files — system zones (SS-IMPORTS, SS-HELPERS, SS-GENERATED) are updated on each run; SS-USER-TESTS is never modified.
  • tsconfig.json — only if you explicitly click "Fix tsconfig automatically" in the preflight warning notification. This adds the detected framework to compilerOptions.types.

SilentSpec never modifies source files, node_modules, package.json, or any file that does not have SilentSpec zone markers. It never modifies unmanaged test files.

Preflight auto-install: when @types/jest (or equivalent) is missing, SilentSpec attempts a silent install before the first generation. This modifies node_modules and the lock file, but not your source code. If the install fails, SilentSpec continues in safe mode and shows a notification with the manual install command.

On Uninstall

Generated spec files remain on disk — they are yours. VS Code cleans up globalStorageUri automatically. No orphaned processes, no background tasks.


Offline & Air-Gapped Use

The Ollama provider works fully offline. Framework detection, AST analysis, zone parsing, and the healer all run locally using the TypeScript compiler API — no network required for these steps. Only the AI generation step requires a provider connection.

Cloud providers (GitHub Models, Claude, OpenAI) require internet access for every generation call.


Known Limitations

  • Ollama must be running before VS Code starts. The health check runs once on activation. If Ollama starts later in the session, set silentspec.provider: "ollama" explicitly or restart VS Code.
  • Files over 1,500 lines or 200,000 characters are skipped. This is a deliberate gate to avoid excessive token usage and slow healer runs on very large files.
  • Only exported functions and classes are detected. Non-exported functions, export default object literals, and TypeScript namespace exports are not currently analyzed by the AST gate.
  • Remote SSH, Dev Containers, and WSL have limited support. SilentSpec uses Node fs and child_process directly. A warning is shown on activation in remote environments.
  • silentspec.findGaps runs in full healer mode regardless of preflight result. If @types are missing, some healer diagnostics may be incomplete.
  • Generated tests require review for semantic correctness. The healer removes tests that don't compile, but cannot verify that a test correctly describes your function's intended behavior.
  • First-generation healer limitation. On the very first save for a new spec file, the healer's pre-check runs against the existing (clean) project and may short-circuit. Full diagnostic repair activates on subsequent saves once the spec file exists on disk.
  • testsHealedSuccessfully is always 0 in the impact report. The healer tracks test removal but not repair — this counter is reserved for a future healer repair feature.
  • GitHub Models free tier is limited to approximately 50 requests per day. Each save that triggers generation uses one request per batch call.

Privacy, Data & Security

Source Code Transmission

SilentSpec sends your source code to the configured AI provider on every save that triggers generation. This is fundamental to how it works — there is no way to generate tests without sending code.

Content transmitted includes: source file content (up to 8,000 characters, with function signatures provided for code beyond that window), exported function signatures, import statements, local dependency signatures for files imported by the source, a sample from the nearest existing test file in your project (up to the first 30 lines, used to match your project’s test style), and the filename (not path) of the generated spec file. SilentSpec does not store, cache, or log transmitted code.

For Ollama, all processing is local — no data leaves your machine. For cloud providers, data is subject to their privacy policies:

  • OpenAI: https://openai.com/policies/privacy-policy
  • Anthropic: https://www.anthropic.com/privacy
  • GitHub (Models): https://docs.github.com/en/site-policy/privacy-policies

By using a cloud provider, you accept their data processing terms. Review your provider's policy before using SilentSpec on proprietary or sensitive code.

API Key Storage

API keys and tokens are stored using VS Code's SecretStorage API (context.secrets), which VS Code encrypts using the OS keychain — Keychain on macOS, Credential Manager on Windows, libsecret on Linux.

Keys are stored under these identifiers: silentspec.githubToken, silentspec.claudeApiKey, silentspec.openaiApiKey. They never appear in settings.json, output logs, or telemetry. All error messages pass through redactSecrets() before being logged, which strips Bearer tokens, sk-* API keys, ghp_* GitHub tokens, and key-* prefixed tokens from any log output.

Network Requests — Complete Disclosure

SilentSpec makes exactly the following network requests:

Request When Endpoint
Ollama health check Once on VS Code activation http://localhost:11434/api/tags
Ollama generation On save (Ollama provider) http://localhost:11434/api/generate
GitHub Models generation On save (GitHub Models provider) https://models.inference.ai.azure.com/chat/completions
Claude generation On save (Claude provider) https://api.anthropic.com/v1/messages
OpenAI generation On save (OpenAI provider) https://api.openai.com/v1/chat/completions

SilentSpec makes no other network requests. There is no analytics, telemetry transmission, update check, crash reporting, or any external service beyond the AI providers listed above.

Local Telemetry

SilentSpec records generation statistics locally in globalStorageUri/stats.json (a VS Code-managed directory). These stats are never transmitted anywhere.

Fields stored: totalGenerations, successfulGenerations, failedGenerations, functionsCovered (count), estimatedHoursSaved (computed from counts), testsHealed, testsHealedSuccessfully, lastProvider (name string), lastGeneratedAt (ISO timestamp), failureBreakdown (counts per category), functionAttempts (per-function attempt and success counts — function names as identifiers only, no source code).

There are no fetch, HTTP, or WebSocket imports in src/telemetry.ts. The only I/O is fs.promises.writeFile to the local stats file. View your stats with SilentSpec: Show Impact Report.

What SilentSpec Never Stores or Transmits
  • No file paths in telemetry
  • No prompt text stored after generation
  • No generated test content in telemetry
  • No API keys in logs (redactSecrets verified on all provider error paths)
  • Function names stored as identifiers only — no code bodies in telemetry
  • No cookies, browser fingerprinting, or user identification of any kind
Enterprise & Sensitive Code Guidance
  • Use Ollama for fully local, air-gapped generation — no code leaves your machine
  • Review your organization's policy on third-party AI API usage before enabling cloud providers
  • All cloud provider calls use HTTPS transport
  • There is no dry-run or preview mode — generation always sends source code to the configured provider
  • Disable SilentSpec for specific repositories by setting silentspec.enabled: false in workspace settings (.vscode/settings.json)

Troubleshooting

Nothing happened when I saved. Open SilentSpec: Open Output Log — every save records its exact skip reason. Common causes: silentspec.enabled is false, the file exceeds 1,500 lines, the file has no exported functions, or no API key is set.

Tests don't compile. The healer removes obviously broken tests but cannot catch all semantic errors. Check the output log for Healer: lines. If healer is in safe mode (logged explicitly), install the missing @types package and re-save to enable full healing. Safe mode performs import fixes only and skips deep type-matching to avoid false positives. On the very first generation for a new file, the healer may short-circuit if the project was already compiling cleanly — re-save to trigger full diagnostic repair.

Status bar stuck on "Generating…". The AI provider call may have timed out or stalled. Check the log for timeout or network error messages. Try increasing silentspec.aiTimeoutSeconds or switching providers.

Wrong provider showing in the status bar. If Ollama was running when VS Code started and silentspec.provider is not explicitly set, SilentSpec uses Ollama automatically. Set silentspec.provider: "github" (or your preferred provider) in settings to override this.

How do I reset my stats? Delete stats.json from VS Code's global storage directory. On macOS the path is typically ~/Library/Application Support/Code/User/globalStorage/bharadwajmadduri.silent-spec/stats.json. The exact path appears in the output log on first activation.

Spec file has duplicate zone markers. This can happen if a generation was interrupted mid-write. Delete the spec file and re-save the source file to regenerate it from scratch.


Contributing

npm install
npm run compile   # type-check + lint + build
npm test          # run the test suite

Report bugs and feature requests at github.com/BHARADWAJ-MADDURI/silent-spec/issues.


License

Apache License 2.0 — Copyright 2026 Bharadwaj Madduri.

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2026 Microsoft