Forq VSCode Extension
Forq turns VSCode into a control panel for building software with Claude
Code, driven by an issue board. Move an issue to todo and Forq
automatically spawns a Claude Code session for it in an isolated git
worktree — when the agent finishes, it moves the issue to in review for you
to approve. It works fully offline by default, and can optionally sync the
board with Linear.
The issue board
The issue board lives in the sidebar and is the heart of Forq: it turns a list
of work into running agents. It works in one of two modes, chosen per-workspace:
- Local (default, offline): issues live in a plain JSON file in the
workspace,
.forq/issues.json. No account, no network. The Claude agent
reads and writes this same file directly (the generated CLAUDE.md documents
the format), so the board, you, and the agent all share one source of truth.
- Linear (optional): issues live in Linear, in a Team/Project you pick.
The board mirrors Linear, and agents manage issues through Linear's own MCP
server. Linear is authoritative; the local file becomes a read-only cache.
When Start Polling is on, any issue assigned to agent that enters the
todo state launches a Claude Code session in an isolated worktree. The agent
works the issue end to end; when it's done it moves the issue to in review for
a human to mark done (which closes the session). Because each issue runs in its
own worktree, several agents can work in parallel without stepping on each other.
Getting started (offline)
- Open a project folder in VSCode.
- Initialize → the extension sets up a local
.forq/ folder (an empty
issues file plus a small meta file) and opens Claude, which first asks you
about your idea, then scaffolds the project (framework, CLAUDE.md, README,
and the initial issues).
- Start Polling → issues moved to todo spin up Claude sessions
automatically.
Each workspace is one project — there is no cross-project list. A workspace
counts as initialized once its issues file (.forq/issues.json) exists; the
project's own description lives in its tracked README.md. The .forq/ folder
holds local-only board state and is gitignored.
Licensing
Forq is a paid extension. On a fresh install it is locked — the
sidebar shows an Enter License Key button and a $(lock) Activate Forq
item in the status bar. Paste the license key from your Dodo
Payments purchase email (Command Palette → Forq: Enter License Key,
or click the status-bar item) to unlock it.
- Activation binds the key to this machine, and is re-checked at most once a
week with a long offline grace window — so once activated you can work offline.
- Manage or move a license with Forq: Manage License (replace the key,
or remove it from this machine to free an activation for another device).
Syncing with Linear
- Connect Linear → a browser tab opens for OAuth consent (Authorization
Code + PKCE). Approve, then pick a Team and a Project.
- The board now reflects that Linear project. Create/move issues here or in
Linear's own app — Linear wins on conflict.
- Add Linear MCP → registers Linear's MCP with the Claude CLI
(
claude mcp add --transport http linear https://mcp.linear.app/mcp) so
agents manage issues directly in Linear. Run /mcp in a Claude session the
first time to authorize it.
Switch back anytime with Use Local; disconnect entirely with Disconnect
Linear.
How issues map to Linear (labels)
An issue's status maps to a Linear workflow state (backlog / unstarted /
started / "In Review" / completed / canceled). Its type, mode, and
assigned_to fields are stored as labels — but only the non-default
value of each field carries a label. The default value carries no label, which
keeps a typical feature / agent issue label-free.
| Field |
Default (no label) |
Override label |
type |
feature |
Bug — Linear's own seeded label, reused for bug-type issues. |
assigned_to |
agent |
Human — marks the issue as human-assigned (agents skip it). |
mode |
whatever forq.defaultMode is set to (ships as auto) |
mode:auto / mode:plan — added only when the mode differs from your default. |
Using the labels correctly:
- Set a field from Linear's app by adding or removing the matching label. Add
Bug to make an issue a bug; remove it to make it a feature. Add Human to
take an issue off the agents; remove it to hand it back. Add mode:plan (or
mode:auto) to override the run mode.
- The extension creates the labels it needs.
Human and mode:* are created
on first use; Bug is Linear's built-in label. You don't have to pre-create
any of them.
mode: labels are relative to your default. Because the unlabeled mode is
forq.defaultMode, changing that setting flips which issues need a
mode: label. If you want every issue's mode to be explicit in Linear, that's
expected — the extension writes a mode: label only when it has to.
- Don't hand-edit a
mode: label to a value other than auto or plan — an
unrecognized mode: label is ignored and the issue falls back to your default.
- Legacy labels still work. Older paired labels (
type:bug, type:feature,
assignee:agent, assignee:human) are still read correctly and are cleaned up
automatically the next time you edit the issue from the extension.
- Other labels are left alone. Any labels you add for your own organization
are preserved on every edit; the extension only manages the ones above.
One-click sessions
Alongside the board, Forq gives you launcher buttons that drive the Claude Code
CLI directly — no terminal commands to memorize. They live in the Forq view
in the activity bar, with a terminal toggle pinned to the status bar:
| Button |
What it does |
| Claude |
Open a Claude Code session as an editor tab — it sits next to your files and can be split and dragged like any editor. |
| Claude (Worktree) |
Prompt for a name, then open Claude Code in a fresh, isolated git worktree. |
| Claude (Resume) |
Reopen a previous Claude Code session and pick up where you left off. |
| Terminal |
Open a plain terminal as an editor tab. |
| Terminal (status bar) |
Toggle the integrated terminal panel from the bottom bar. |
Because every session opens as an editor tab, you can run several Claude Code
agents side by side — one per worktree — and arrange them like panes.
Settings
| Setting |
Purpose |
forq.showTerminalButton |
Show the Terminal toggle in the status bar (bottom bar). Default true; set false to remove it. Works regardless of license. |
forq.stateFilter |
Comma-separated issue statuses that trigger a session. Default "todo". |
forq.pollIntervalMs |
Poll interval in ms (Linear mode). Default 20000. |
forq.autoStart |
Start polling automatically on VSCode launch. |
forq.claudeCommand |
Path to the claude binary. Default claude. |
forq.terminalLocation |
editor (default) or panel. |
Mode and the Linear Team/Project mapping are stored per-workspace and set via the
Connect Linear / Use Local commands, not settings.
Commands
| Command |
What it does |
Enter License Key |
Activate Forq on this machine with your Dodo Payments key. |
Manage License |
Replace the key, or remove the license from this machine. |
New Idea |
Create a new local idea to build. |
Initialize |
Scaffold this workspace; Claude asks about your idea, then sets it up. |
New Issue |
Add an issue (a title is generated from the description). |
Connect Linear |
OAuth to Linear and pick a Team/Project to sync with. |
Use Local (Offline) Mode |
Switch the board back to the local file. |
Add Linear MCP |
Register Linear's MCP server with the Claude CLI. |
Disconnect Linear |
Clear the Linear token and mapping; revert to local. |
Start Polling / Stop Polling |
Begin/stop launching sessions for todo issues. |
Poll Now |
One-shot poll cycle. |
List Sessions |
Quick-pick of open Claude terminals. |
Open Claude / (Worktree) / (Resume) / Terminal |
The one-click launchers above. |
Show Output |
Reveal the Forq output channel. |
Caveats
- The OAuth callback binds one of ports 54322–54325 on
127.0.0.1. If all four
are in use, Connect Linear fails — free one and retry.
claude must be on PATH (or set forq.claudeCommand).
- In Linear mode, a team needs the usual workflow states (backlog / unstarted /
started / completed / canceled); an "In Review" state is used when present,
otherwise the started state is reused.