Skip to content
| Marketplace
Sign in
Visual Studio Code>Other>Spec LensNew to Visual Studio Code? Get it now.
Spec Lens

Spec Lens

Sinj Menaruchi

|
10 installs
| (1) | Free
Spec-driven development for any repo: reverse specs from code, app map, spec authoring.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

Spec Lens

VSCode extension for spec-driven development on any repo (brownfield-first):

  1. Reverse Spec — generate specs from existing code
  2. Draft Spec — author new specs with LLM assist
  3. App Map — interactive app launch (named with the file it starts in, e.g. lib/main.dart) → app init → router → screens → navigation → API-call map

See SPEC.md in the repository for the full implementation plan. Work is phased; current status is tracked in CHANGELOG.md. docs/FAQ.md answers the common questions — when the LLM is called, what lives in .speclens/, and how the cache works.

Supported frameworks

The analyzer picks the first matching framework adapter (all analysis is static and local — zero LLM calls):

Framework Detected by Graph contents
Flutter/Dart pubspec.yaml with flutter: screens (GoRouter/Navigator), navigations, Dio/Retrofit/http calls, models, state deps, main() startup steps
Angular angular.json or @angular/core dep routed @Components, routerLink/router.navigate edges, HttpClient calls, main.ts startup steps
React / Next.js react/next in package.json App & Pages Router pages, React Router routes, <Link>/router.push/navigate edges, fetch/axios calls, Next API routes as server endpoints, entry-module startup steps
Go go.mod server endpoints (net/http incl. 1.22 patterns, gin, echo, chi, gorilla/mux, fiber) with request/response structs, outgoing HTTP calls
Java pom.xml / build.gradle Spring MVC & JAX-RS endpoints with @RequestBody/return-type models, RestTemplate/WebClient/Feign outgoing calls

Backend workspaces (Go, Java) have no screens — the App Map is empty but the API list and API specs work on the endpoint surface.

Monorepos: detection scans subdirectories (two levels deep) too, so a repo with web/ (React) + server/ (Go) analyzes both and merges them into one graph. A frontend call and the backend endpoint that implements it become one node.

LLM providers

Configured via specLens.llm.provider:

Provider Setup
vscode-lm (default) None — uses your Copilot models via the VSCode Language Model API
anthropic Run Spec Lens: Set API Key
ollama Local Ollama; set specLens.ollama.baseUrl if not on :11434
custom Any OpenAI-compatible endpoint: specLens.custom.baseUrl (+ headers / API key)

Pick the model with Spec Lens: Select LLM Model — it lists what is actually available on this machine (live Copilot models for vscode-lm, installed Ollama tags) rather than the static dropdown in Settings, and writes the choice to user settings.

Semantic search embeddings (specLens.embeddings.provider) support ollama and custom only; with none search is lexical-only.

All LLM responses are cached by content hash under .speclens/cache/ in the target repo — identical inputs never call the LLM twice.

Using it

Run Spec Lens: Get Started — it initializes .speclens/, analyzes the workspace and opens the App Map in one go. (Opening a supported repo that has never been initialized offers this automatically, and a 5-step walkthrough lives on VSCode's Welcome page.) After that you mostly do not touch the command palette — the extension comes to the code you have open:

  • CodeLens on screen classes — each screen shows its linked spec and that spec's status, with Show in Map next to it, or Generate spec when the screen has none. Lenses read specs from disk, so scrolling never costs an LLM call.
  • CodeLens on the widgets a screen is built from — the _OrderSummary three hundred lines into a screen file gets its own Generate component spec, right on the declaration.
  • Problems panel — a static lint runs as you open or save a spec: requirements that name no trigger or result, umbrella words that hide the conditions they stand for, missing acceptance criteria, approved specs with open questions still in them.

Commands

  • Spec Lens: Get Started — initialize + analyze + open the App Map, in one command
  • Spec Lens: Initialize — create .speclens/ (specs/, cache/, README) in the workspace
  • Spec Lens: Analyze Workspace — build the app graph (screens, navigation, API calls)
  • Spec Lens: Open App Map — the interactive map
  • Spec Lens: Open Component List — the widgets a screen is built from, and their specs
  • Spec Lens: Search — QuickPick over screens, endpoints, specs, files
  • Spec Lens: New Spec — author a spec for code that does not exist yet
  • Spec Lens: New Component Spec — design a widget first: its props, states and mockup
  • Spec Lens: Generate Specs for All Screens — bulk reverse-spec (confirms the call count first)
  • Spec Lens: Approve Spec — mark the open spec approved
  • Spec Lens: Set API Key — store the key in VSCode SecretStorage
  • Spec Lens: Select LLM Model — pick specLens.llm.model from the models this machine actually has
  • Spec Lens: Test LLM Provider — one-shot round-trip against the configured provider

What a spec looks like

Specs are markdown + frontmatter under .speclens/specs/. A spec makes a claim or records that nobody decided, and the section says which: ## Requirements is what the code (or the author) settles, ## Open Questions is what nobody has decided yet. Requirements read WHEN <trigger> THE SYSTEM SHALL <result> and are numbered on write (R1, AC-1), so a review can name a line instead of quoting it. They sit in a | ID | Requirement | Component | table, split into feature blocks the spec names itself — ### F1 — Load products, ### F2 — Cart — so "does the cart work?" is one block to read rather than a whole list to scan, with the fetch, the taps and the errors of that one feature together instead of scattered.

A screen spec draws the screen as well as describing it: ## Component Tree is the widgets nested as the build method nests them (each with the C<n> handle the tables point at), ## Navigation is one row per way out, and ## Implementation Notes says where in the source each behavior lives. ## Acceptance Criteria is a table too, and its Covers column names the requirements each scenario proves — a requirement nothing covers is one nobody has said how to verify. ## Non-Goals keeps generation inside the fence; ## Technical Requirements holds the how — the library, endpoint or budget this feature is fixed to, plus the non-functional bar — and is what "Generate code" reads and cannot guess.

There are four kinds, each in its own folder under .speclens/:

Kind Folder Subject
REQ- specs/ one screen
API- apis/ one endpoint
LIB- modules/ one shared helper/util file (or the app's startup)
UI- components/ one widget/component a screen is built from

A component spec keys on the file and the declaration in it, because one file routinely holds a widget and the smaller ones it composes. It can be generated from a declaration already on disk, or designed before one exists — New Component Spec takes a path, a name, a brief and/or a mockup, plus the props and states you have already decided. It is written for the programmer placing the widget, not for a product owner: ## Props is a table (Prop | Type | Required | Default | Notes, callbacks included) and ## States is a table of every state, variant and mode with the condition that selects each one — loading, empty, error, disabled, the variants a screen spec flattens away — with the count in its heading. ## Behavior is <trigger> → <result> lines grouped into Rendering / Interaction / Edge Cases, and ## Composition, ## Design Tokens and ## Accessibility are written only when there is something real for them. The list offers the widgets that own a file but were never extracted for sharing. A widget two or more screens place is design-system code and is left out; so is one written inside somebody else's file — a screen's, or the exported component the file is named for — because that is part of its composition, and its spec documents it. Extract a sub-widget into a file and it gets a row.

Repo-wide rules no single spec should repeat — architecture, state management, error handling, testing — live in .speclens/constitution.md and ride along with every "Generate code" prompt.

Development

npm install
npm run typecheck
npm test          # vitest: cache + provider tests against mock servers
npm run build     # esbuild bundle → dist/extension.js

Launch with F5 (Extension Development Host) after npm run build.

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