Req Link
Preview. Req Link is an early release. Features and file formats may still change.
Req Link is a VS Code extension for working from requirements. You write requirements in Markdown, link them to the functions that implement them, and read code as natural-language explanations that also say whether the code really meets its requirements.
Features
- Requirements tree: every requirement in
specs/**/*.req.md in the sidebar, with its status: implemented, not implemented, needs update, or deletion candidate.
- Requirement ⇄ code links:
// @req R1 above a function links it to requirement R1. Click a requirement to jump to its implementation.
- Explanation view: a natural-language view of a code file, written by an LLM. It also judges whether each function meets the requirements tagged on it, and flags a Gap when it does not. It works like the Markdown preview.
- Code generation: generate or update the code for requirements that are not implemented or need an update. You review the diff, and nothing is written until you click Apply.
- Inbox sorting: sort the loose notes in
TODO.md into requirements files by domain.
- OpenSpec and docs: show OpenSpec specs and docs bullets in the tree (read-only), and import them into requirements files.
- CI check:
req-link check fails a build when requirements and code have drifted apart.
- Choice of LLM: Claude Code CLI, the Claude API, GitHub Copilot (through VS Code's Language Model API), or the OpenAI API and compatible APIs.
What you need
VS Code 1.90 or later.
One of these LLM providers, for explanations, code generation, and the AI import and sorting. The requirements tree, IDs, links, saved explanations, and req-link check work without one.
Provider (reqLink.llm.provider) |
What you need |
claude-cli (default) |
The Claude Code CLI, signed in. No API key is needed. Req Link finds claude on your PATH or the copy bundled with the Claude Code extension |
anthropic |
An Anthropic API key |
vscode-lm |
GitHub Copilot (or another extension that provides models to VS Code's Language Model API), signed in |
openai |
An OpenAI API key, or the URL of an OpenAI-compatible API such as a local Ollama server |
A language extension that reports document symbols for your code. JavaScript and TypeScript are built into VS Code. Python needs the Python extension (Pylance).
Quick start
- Open a folder in VS Code, and trust it when asked. Nothing is ever sent to an LLM from an untrusted workspace.
- Run Req Link: Initialize from the Command Palette, or click "Initialize Req Link" in the Requirements view. It creates
specs/app/main.req.md, README.md, and TODO.md.
- Write a few requirements as bullets with IDs, such as
- [R1] Can add a task.
- Press ✨ on the requirements file in the tree to generate code. Review the diff and click Apply.
- Click a requirement in the tree to open the explanation of its implementation, then click Generate explanations.
The first time Req Link sends anything in a workspace, it shows what will be sent and where, and asks for your consent. The Get Started with Req Link walkthrough (Help → Welcome) covers the same steps.
To use a provider other than the Claude Code CLI, set reqLink.llm.provider first. See LLM providers.
Privacy
Req Link has no server of its own and collects no telemetry. It sends code only to the LLM provider you choose, and only when you start an action that needs the LLM.
What is sent, and when
| Action you start |
Files sent in full |
| Generate explanations in the explanation view |
The code file, and the requirements files whose requirements are tagged in it |
| ✨ Generate code |
The requirements file, its implementation file, and README.md |
✨ Sort inbox (TODO.md) |
TODO.md, README.md, and every requirements file |
| ✨ Import into requirements files (AI) |
The OpenSpec or docs files being imported, README.md, and every requirements file |
Nothing is sent when you open the tree, the preview, or a saved explanation, or when you run req-link check. "Import (No AI)" does not use the LLM.
Where it goes
| Provider |
Destination |
claude-cli |
Anthropic, through the Claude Code CLI on your machine and your Claude Code account. The CLI runs in an empty folder with --setting-sources "", so it does not read your workspace's CLAUDE.md or settings |
anthropic |
The Anthropic API (api.anthropic.com), with your API key |
vscode-lm |
The model provider behind the VS Code language model you selected, for example GitHub Copilot |
openai |
The OpenAI API, or the OpenAI-compatible API set in reqLink.openai.baseUrl |
The provider's own terms and data policies apply to what it receives.
Safeguards
Every request goes through the same gate (src/llm/guard.js) before anything is sent:
- Nothing is sent from an untrusted workspace (Restricted Mode). The requirements tree and saved explanations can still be viewed, but nothing can be generated.
- Files matching
.reqlinkignore are never sent, and neither are files outside every workspace folder. Put one glob pattern per line in .reqlinkignore at the workspace root (# starts a comment). If an action needs an ignored file, nothing is sent.
- Consent per workspace. The first time in each workspace, Req Link lists what it sends and where, and asks for your consent. It asks again when the destination (provider or base URL) changes. Revoke consent with Req Link: Revoke Permission to Send Code to the LLM.
API keys are kept in VS Code's secret storage, never in settings files. reqLink.claudeCli.path and reqLink.openai.baseUrl are honored only in user settings, so a cloned repository's .vscode/settings.json cannot point them at another executable or server.
What stays on your machine
.reqlink/state.json: hashes of requirement text at the time you marked it implemented.
.reqlink/explain/**.json: saved explanations. You can commit them to share them with your team.
Using Req Link
| Action |
What it does |
Ctrl+Shift+V (Cmd+Shift+V on macOS) |
In a code file: open its explanation in place. In an explanation: go back to the code |
Ctrl+K V (Cmd+K V on macOS) |
Open the explanation beside the code. It follows the active code file and highlights the function at the cursor |
| ✨ on a requirements file or requirement in the tree, or "Generate code" in the preview |
Has the LLM write or update the code for requirements that are not implemented or need an update, shows the diff, and applies it only when you click "Apply" |
| "Generate explanations" in the explanation view |
Has the LLM write explanations only for functions that are missing one or whose explanation is stale |
| ✓ in the requirements tree |
Records the requirement as "implemented with this text" (if the text changes afterwards, it becomes "needs update"). A requirement whose latest explanation says the code doesn't meet it is skipped unless you confirm (see Evidence) |
Starting from an empty folder
Run Req Link: Initialize (or click "Initialize Req Link" in the empty requirements tree). It creates:
specs/app/main.req.md: a starter requirements file (implemented in src/app/main.*), opened right away
README.md: the overview, with a "Cross-cutting requirements" section for constraints shared by all files
TODO.md: the inbox
Existing files are never overwritten: an existing README.md only gets the cross-cutting section appended when it has none, and the starter file is skipped when specs/ already holds a requirements file. The Get Started with Req Link walkthrough (Help → Welcome, or "Get Started" in the empty tree) guides you through it: write requirements → generate code → read the explanation.
Writing requirements
<!-- specs/tasks/manage.req.md → implemented in src/tasks/manage.* -->
# Creating and editing tasks
- [R1] Can add a task
- [NF1] Titles are at most 100 characters
Requirements files are read as Markdown. Every item of a top-level list, bulleted (-, *, +) or numbered (1.), is a requirement, and a requirement may wrap over several lines. Bullets nested under a requirement are notes on it, not requirements of their own. Lists inside code blocks are ignored.
// @req R1
// @req NF1
add(title) { ... }
- Put the overview and cross-cutting requirements in
README.md at the workspace root, and requirements as they come to mind in TODO.md (the inbox)
.reqlink/state.json: hashes of requirement text at acceptance time (for detecting "needs update")
- Multi-root workspaces: each workspace folder is its own project. Its requirements files,
@req tags, README.md, TODO.md, .reqlink/state.json and explanation cache are read and written in that folder only, so the same ID (say R1) in two folders means two different requirements. With more than one folder, the tree's top level has one node per folder
.reqlink/explain/**.json: the explanation cache. Only functions whose code or requirement text changed are regenerated. Can be committed to git and shared with the team
IDs
R + number for functional requirements, NF + number for non-functional ones (R1, NF2). Other prefixes such as AUTH-1 also work
- IDs are unique across the whole workspace. Duplicates are reported as errors in the Problems panel
- A bullet without an ID gets a quick fix (💡) that assigns the next free number. "Req Link: Assign Missing IDs" numbers every bullet in the file at once. Bullets under a heading containing "non-functional" get
NF, the rest get R
File layout
- One requirements file = one source file.
specs/<domain>/<name>.req.md is implemented in src/<domain>/<name>.<ext>. Split folders by business domain, not by technical layer
- One requirement = one or more functions, linked with
@req. Put // @req <ID> (or # @req <ID>) in the comment right above each function that implements it
- A function that satisfies several requirements carries several
@req lines, typically one functional requirement plus the non-functional ones it enforces
- Shared code stays in the same file without a tag. Helpers, constants and data structures used by several requirements are not linked to any one requirement
- When a file grows too large, split the requirements file (into a new domain or a new name), not just the code, so the 1:1 mapping holds
- The file extension follows the existing implementation; for a new file, the most common language among existing implementations (JavaScript if there are none)
Code generation (below) follows these rules, and the requirements tree judges status by them.
Languages
Functions are found from the document symbols a language extension reports, so the language needs one: TypeScript and JavaScript are built into VS Code, and Python needs the Python extension (Pylance). sample/ has a JavaScript, a TypeScript (src/tags/labels.ts) and a Python (src/stats/summary.py) implementation.
- Tags use the language's line comment:
// @req R1 in JavaScript and TypeScript, # @req R1 in Python
- Put the tag above a function's decorators (
@logged, @staticmethod). A tag between the decorators and the function works too. The explanation shows the decorators as part of the function
- Nested functions and callbacks are part of the function they are in, not functions of their own
- A TypeScript function's overload signatures and its implementation are one function; a tag above the first signature reaches it. Python's
@overload stubs are not reported by Pylance, so tag the implementing def
- Not treated as functions: arrow functions and function expressions stored in a variable or class field, getters and setters (in Python,
@property methods: Pylance reports only the last def of a getter/setter pair), and interface method signatures. A tag on one of them goes to the enclosing class, or to no function at the top level
Generating code from requirements
Press ✨ on a requirements file (or a single requirement) in the tree, in the editor title, or use "Generate code" in the preview.
- The targets are the requirements that are not implemented or need an update (bullets without an ID are skipped; assign IDs first). Nothing is generated while an ID in the file is duplicated, here or in another requirements file
- Claude gets the requirements file,
README.md (cross-cutting constraints) and the current implementation file, and writes the whole file back following the file-layout rules above
- A diff opens next to the current file, with a summary and the assumptions Claude made. Warnings appear if a target ended up without an
@req tag, or a tag names an ID that is in no requirements file
- Nothing is written until you click Apply. If the file changed while generating, nothing is applied
- Applying records the tagged requirements as implemented (same as ✓, including the gap check), so the tree turns green without another click
- After applying, a notification offers to generate explanations for the changed file, so the verdicts are redone against the new code. It is only an offer; nothing is sent unless you click it
Only the implementation file for that requirements file is ever written; the LLM cannot choose another path.
Sorting the inbox (TODO.md) into requirements files
Press ✨ on TODO.md in the tree (or in the editor title of TODO.md), or run "Req Link: Sort Inbox (TODO.md) into Requirements Files".
- Claude gets the
TODO.md bullets, every requirements file (path, headings and requirement texts) and README.md, and proposes a place for each bullet: under a heading of an existing specs/...req.md, or a new specs/<domain>/<name>.req.md split by business domain (the file-layout rules above)
- Proposals whose path is not a
.req.md file under specs/ are rejected; those bullets stay in TODO.md. So are proposals that go through a symbolic link, that name a file that exists but is not a scanned requirements file, or whose heading matches more than one section (nested headings are given to Claude as paths like Login > Functional). A path that differs from one existing file only in letter case means that file (an exact match wins; a case-only match to several files is rejected)
- A checklist shows each bullet with its target file and heading; uncheck the ones to leave in the inbox
- The approved bullets are added after the last requirement under their heading (new files start with a
# Heading), each with a fresh ID that is unique across the workspace (NF under a non-functional heading, R otherwise), and are removed from TODO.md
- Everything is applied as one workspace edit, and the changed files are saved. Undo (Ctrl+Z) in
TODO.md or a changed requirements file offers to undo it in all files, which also deletes the new files; the undone files are left unsaved. If TODO.md or a target file changed while sorting, nothing is applied
A bullet moves with its indented continuation lines. Ticked checkboxes (- [x] ...) and bullets that already have an ID (- [R9] ..., also - [ ] [R9] ...) stay in TODO.md: an existing ID may already be referenced by @req in code, so it is not renumbered, and it is not reused either because it could clash with an ID in use. Move those by hand. - [ ] is dropped from the moved text. Requirements files and README.md that match .reqlinkignore are not sent and are not offered as targets. In a multi-root workspace, notes go only into requirements files of the folder that holds that TODO.md
Evidence: gap verdicts
When the explanation view explains a function, Claude also judges each requirement tagged on it: ok (met), gap (not met / diverges) or unclear. The latest of these verdicts is evidence for the requirements tree:
- A requirement whose fresh explanation says
gap shows Gap in the tree and the preview (red icon, with Claude's note in the tooltip and under the requirement). Its status is unchanged: Gap is shown on top of "implemented" or "needs update"
- If several functions implement the requirement, one
gap among them is enough
- Mark as implemented (✓ in the tree, "Fixed — mark as implemented" in the preview) and the acceptance after Apply skip such a requirement and show the note, with an explicit Accept anyway to record it regardless. The other requirements are recorded as usual
- Only fresh explanations count. When the function's code or the requirement text changes, the explanation becomes stale and no longer blocks anything; a missing explanation doesn't block either. Regenerate the explanation to get a new verdict
unclear verdicts are shown in the explanation view only and never block
Checking requirements in CI
req-link check runs on plain Node.js (no VS Code) and fails when requirements need work, so a PR that changes requirements without updating the code fails in CI.
node bin/req-link.js check [folder] # from a clone of this repository
npx --yes github:replay9zz/req-link check # from anywhere
It reads specs/**/*.req.md, the @req tags in code, .reqlink/state.json and the saved explanations in .reqlink/explain/ of the folder (default: the current directory), prints one line per requirement that needs attention and exits with 1 (0 when there is nothing, 2 on a usage error or a broken state.json):
R3 specs/tasks/manage.req.md:5 needs update
R5 specs/tasks/view.req.md:4 not implemented
R9 src/tasks/manage.js:28 deletion candidate
R2 specs/tasks/manage.req.md:4 gap (TaskStore.remove: Removed tasks cannot be restored)
| Reason |
Meaning |
not implemented |
The requirement has an ID but no @req in the code |
needs update |
The requirement text changed after it was marked as implemented |
deletion candidate |
An @req names an ID that is in no requirements file (the line points at the code) |
gap |
A fresh saved explanation says the code does not meet the requirement (see Evidence) |
The editor decides freshness from the function range a language extension reports. The CLI has no language server, so it guesses the function's range from the text (braces, or indentation for Python, with or without the decorators above it) and counts a verdict only when the guess gives exactly the saved hash. A function it cannot find therefore counts as stale: a gap may be missed, but a stale verdict never fails the check. Commit .reqlink/explain/ for gap checks to work in CI. Requirements without an ID and the read-only OpenSpec / docs sources are not checked.
--format github prints the problems as GitHub Actions error annotations on the files, and --format markdown prints a report for a PR comment.
GitHub Actions example
name: Requirements
on: pull_request
permissions:
contents: read
pull-requests: write # only for the PR comment step
jobs:
req-link:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 22
# Pin a commit (github:replay9zz/req-link#<sha>) for reproducible runs
- name: Check requirements
run: npx --yes github:replay9zz/req-link check --format github
- name: Comment the report on the PR
if: failure()
env:
GH_TOKEN: ${{ github.token }}
run: |
npx --yes github:replay9zz/req-link check --format markdown > req-link.md || true
gh pr comment ${{ github.event.pull_request.number }} --body-file req-link.md
A project that keeps requirements elsewhere can still see them in the requirements tree, without moving anything into specs/. Req Link only reads these files; it never edits them, and they have no implementation status or code generation.
- OpenSpec: each
### Requirement: in openspec/specs/<capability>/spec.md, with its SHALL statement and scenario names in the tooltip. Changes in progress (openspec/changes/<change>/specs/**/spec.md) are listed per change, marked ADDED / MODIFIED / REMOVED. Archived changes are not shown
- Docs: every bullet in the Markdown files under
docs/, grouped under the nearest heading. Bullets inside code blocks are skipped
Click a requirement to open its line, or a file to open its Markdown preview.
Importing them into requirements files by domain
When you are ready to move to Req Link, import them once into domain-split .req.md files. Use the buttons on the OpenSpec / Docs sections, a change, or a single file (or the commands from the palette for everything):
- ✨ Import into Requirements Files by Domain (AI): works like "Sort inbox". The LLM proposes a domain and file for each requirement (
specs/<domain>/<name>.req.md), preferring the requirements files you already have
- Import (One Domain per Source, No AI): each OpenSpec capability or docs file becomes a domain (
openspec/specs/reminders → specs/reminders/reminders.req.md, docs/billing/refunds.md → specs/billing/refunds.req.md), and each docs heading a section
Either way you pick what to import from the list first. Imported requirements get new IDs, start as not implemented, and keep where they came from as a comment, e.g. - [R7] The system SHALL ... <!-- from: openspec/specs/reminders/spec.md › Due-date reminder; scenarios: ... -->. The comment is not part of the requirement text. Running the import again skips what was already imported.
For OpenSpec, the current specs are imported together with the ADDED and MODIFIED requirements of changes in progress; a MODIFIED one replaces the spec's version, and REMOVED ones are left out. The original files are never changed; after the import, the .req.md files are the source of truth.
Turn these sections off with reqLink.sources.openspec and reqLink.sources.docs (see Settings).
Settings
| Setting |
Default |
Description |
reqLink.openCodeAs |
explanation |
Whether opening an implementation from the tree shows the explanation (explanation) or the code (code) |
reqLink.sources.openspec |
true |
Show OpenSpec requirements in the tree |
reqLink.sources.docs |
["docs/**/*.md"] |
Markdown files whose bullets are shown in the tree. An empty list turns this off |
reqLink.layout |
requirementsLeft |
Fixed editor columns so requirements and code don't swap sides: requirementsLeft (requirements left, code and explanations right), requirementsRight, or auto (open beside the current editor) |
reqLink.llm.provider |
claude-cli |
claude-cli (Claude Code CLI), anthropic (Claude API with an Anthropic API key), vscode-lm (VS Code's Language Model API, e.g. GitHub Copilot) or openai (OpenAI API or any OpenAI-compatible API) |
reqLink.explanationLanguage |
(empty) |
Language of generated explanations: a language tag (en, ja ...) or a name (Japanese). Empty means VS Code's display language. Saved explanations keep their language until regenerated |
reqLink.claudeCli.path |
(auto) |
Path to the claude executable (only honored in user settings) |
reqLink.claudeCli.model |
(default) |
sonnet / haiku / opus, etc. |
reqLink.anthropic.model |
claude-opus-5-5 |
Model for the anthropic provider, e.g. claude-sonnet-5-5 or claude-haiku-5-5 |
reqLink.vscodeLm.vendor |
copilot |
Vendor of the VS Code language model for the vscode-lm provider. Empty means any vendor |
reqLink.vscodeLm.family |
(empty) |
Model family for the vscode-lm provider, e.g. gpt-5-mini. Empty uses the first model the vendor offers |
reqLink.openai.model |
gpt-5-mini |
Model for the openai provider. It must support Structured Outputs (JSON Schema) |
reqLink.openai.baseUrl |
https://api.openai.com/v1 |
Base URL of an OpenAI-compatible API, e.g. http://localhost:11434/v1 for Ollama (only honored in user settings) |
UI and explanation language
The UI follows VS Code's display language. English is the default and Japanese is included
(package.nls.ja.json for commands and settings, l10n/bundle.l10n.ja.json for everything else).
Explanations are written in reqLink.explanationLanguage, or in VS Code's display language when it is empty.
LLM providers
Explanations, code generation, inbox sorting, and the AI import use the provider set in reqLink.llm.provider. Every provider goes through the same privacy safeguards.
- Cancel: every AI action shows a progress notification with a Cancel button. Cancel stops the running call (the
claude process is killed, or the API request is aborted, whichever provider is set) and nothing from it is applied
- Large files: a file up to about 40,000 characters is explained in one call with the whole file as context. A larger file is split by function into several calls (up to about 30,000 characters of code and 20 functions each, plus the beginning of the file for context). Each call's explanations are saved as soon as it returns, so cancelling or a failure part-way keeps the ones already done. A single function too long for one call is sent cut off, and its explanation says so
- Failures from the Claude Code CLI or an OpenAI-compatible API, such as not being logged in or a rejected key, a reached usage limit, rate limiting, an overloaded service or a request that is too large are reported with what to do next
Claude Code CLI (default)
Req Link runs claude -p with your Claude Code login, so no API key is needed. claude is looked up on PATH, then in the copy bundled with the Claude Code extension; set reqLink.claudeCli.path in your user settings to use another one. The CLI runs in an empty folder with --setting-sources "", so it doesn't load the workspace's CLAUDE.md or settings (loading them can bloat the input to hundreds of thousands of tokens).
Using the Claude API without Claude Code
- Set
reqLink.llm.provider to anthropic in your settings
- Run "Req Link: Set Anthropic API Key" (you are also asked for it on the first generation). The key is kept in VS Code's secret storage, never in settings files. Without it, the
ANTHROPIC_API_KEY environment variable is used
- Optionally change
reqLink.anthropic.model
Answers are forced into the expected JSON with structured outputs (output_config.format). If the model declines a request for safety reasons, the API retries it on a fallback model (fallbacks: "default"). No cost is shown for this provider.
Using GitHub Copilot (VS Code's Language Model API)
- Install GitHub Copilot and sign in
- Set
reqLink.llm.provider to vscode-lm in your settings. VS Code asks once whether Req Link may use the language model
- Optionally pick a model with
reqLink.vscodeLm.family, or another extension's models with reqLink.vscodeLm.vendor
This API has no structured outputs, so the JSON Schema is put in the prompt and the answer is parsed and checked for the required fields. Usage counts against your Copilot plan; no cost is shown.
Using ChatGPT (OpenAI) or another OpenAI-compatible API
- Set
reqLink.llm.provider to openai in your settings
- Run "Req Link: Set OpenAI API Key". The key is kept in VS Code's secret storage, never in settings files. Without it, the
OPENAI_API_KEY environment variable is used
- Optionally change
reqLink.openai.model, or point reqLink.openai.baseUrl at another OpenAI-compatible API
Answers are forced into the expected JSON with Structured Outputs (response_format: json_schema, strict: true), so the model and API must support it. No cost is shown for this provider, since prices differ per model and provider.
Development
Open this repository in VS Code and press F5. A development window opens with sample/, which has requirements and JavaScript, TypeScript, and Python implementations to try.
npm ci
node --test test/*.test.js # unit tests
npx --yes @vscode/vsce@3 package # build req-link-<version>.vsix
npx --yes @vscode/vsce@3 ls # list the files that go into the .vsix
| File |
Role |
src/parser.js |
Reading requirements files and @req tags |
src/scaffold.js / src/init.js |
"Req Link: Initialize": what it creates / writing it into the workspace folder. The Get Started walkthrough is in package.json and media/walkthrough/ |
src/status.js |
Requirement status (not implemented / needs update / candidate for deletion) |
bin/req-link.js, src/cli.js / src/check.js |
req-link check for CI: arguments and output / scanning a folder without VS Code |
src/evidence.js / src/acceptance.js |
Gap verdicts from fresh explanations and which requirements ✓ may record / the "Accept anyway" prompt |
src/model.js |
Workspace scanning, state.json |
src/roots.js |
Per-folder model (statuses, orphans, acceptance records) and the tree's top level for multi-root workspaces |
src/codeIndex.js |
Per-file index of @req tags in code; only changed files are read again |
src/symbols.js |
Functions from a language extension's document symbols and which function a tag belongs to, with the per-language differences. test/fixtures/symbols/ holds symbols recorded from the real TypeScript and Python language servers (record.js re-records them) |
src/tree.js / src/preview.js |
Requirements tree / requirements preview |
src/explain*.js |
Explanation view, prompt, cache |
src/generate.js / src/generateCode.js |
Code generation: target file, prompt and checks / diff and apply |
src/triage.js / src/triageInbox.js |
Sorting the inbox: prompt, checks and edit plan / checklist and apply |
src/ids.js / src/idTools.js |
Requirement IDs: numbering and duplicates / quick fix and Problems panel |
src/importReqs.js, src/importExternal.js |
Importing OpenSpec / docs requirements into .req.md files (with or without the LLM) |
src/external.js |
Reading OpenSpec specs and docs bullets for the read-only sections of the tree |
src/l10n.js, l10n/, package.nls*.json |
UI translations. Wrap new UI text in t('...') (a string literal with {0} placeholders) and add its Japanese to l10n/bundle.l10n.ja.json; test/l10n.test.js fails otherwise |
src/llm/ |
LLM entry point (index.js), providers (claudeCli.js, anthropic.js, vscodeLm.js, openai.js) the pre-send gate (guard.js), and cancellation and failure messages (errors.js) |
License
Copyright (C) 2026 replay9zz. Licensed under the GNU GPL v3 or later.
Req Link is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. See LICENSE for the full text.