VISP is a harness for AI coding agents. It runs an actor–critic loop around the agent's work: the agent (the actor) writes a short brief and builds one usable slice at a time inside an authorized file scope, VISP executes the checks the brief declares, and an independent reviewer (the critic) judges the result against the original request. Findings come back to the agent as the next repair step.
VISP works as a CLI (visp) and as an MCP server (visp serve --mcp). Both use the same workflow services.
What VISP records as evidence is what it executed itself: check commands, browser journeys and their screenshots, and the reviewer's attributed judgments. The agent's own claims are never evidence.
Requires Node.js 22.16 or later and a Git repository.
npm install -g @visporg/visp-coder@betaThe package installs three executables: visp, visp-migrate (backed-up upgrades of saved history) and visp-runner (optional experiment runner).
Set up a project for your coding host (claude-code, codex, cursor, copilot, opencode or generic):
visp init --harness codex
visp install --harness codex --dry-run # preview what will be written
visp install --harness codexTo take VISP out again, run visp uninstall --dry-run, then visp uninstall (add --harness <host> for a host other than the configured one). It reverses install: it removes the generated instruction files, VISP.commands.md, the VISP block in AGENTS.md or CLAUDE.md, the hook scripts, the visp MCP entry and VISP's Claude Code hook entries (editing only those entries, with the previous text saved under .visp/state/backups/), the Git pre-commit hook (restoring the hook install set aside as pre-commit.local) and an unedited CI workflow. A file or hook entry you edited is reported and kept; --force removes it too (saving an edited Git hook under .visp/state/backups/ first). It refuses while a slice is authorized, with or without --force: finish the slice with visp done. It also refuses a --harness other than the installed one. Feature history and project state under .visp/, visp.yml and the .gitignore entries from init stay; delete them by hand with rm -rf .visp visp.yml if you want them gone.
init writes visp.yml and .visp/. install writes the host's instruction files and VISP.commands.md, registers the MCP server for Claude Code, Codex, Cursor, Copilot and OpenCode, and installs a Git pre-commit scope check. Generic hosts need their MCP server entry configured manually. Claude Code also gets edit, shell, prompt and Stop hooks in .claude/settings.json; Codex gets prompt, shell and Stop hooks in .codex/hooks.json. Open Codex and trust project hooks with /hooks before relying on them, including before headless codex exec runs. Cursor, Copilot, OpenCode and generic hosts have no VISP host hooks, so use visp done and the Git hook as their local checks. The MCP and hook entries use the installed CLI path, and generated scripts under .visp/hooks/ are local to each checkout, so run visp install in every clone before coding. Until then the committed Claude Code hooks do nothing, except that an edit is refused while a slice is authorized in that checkout. Commit the setup before starting feature work. visp doctor checks the installation. When switching VISP builds, use visp install --replace-runtime and restart MCP and host processes using the old build; --force only replaces edited files.
visp feature "Add a retry button to the failed-save banner"
visp work --check "npm test" # one slice for the whole request, checked by your tests
# ...implement...
visp done # run checks; independent review
visp next # findings or the next step
visp accept # check the assembled product
visp pr # reviewer document for the pull requestRun visp done, verify, accept and next with the coding host's maximum shell timeout (at least 10 minutes when supported). VISP prints check progress to stderr and saves each completed execution, so an interrupted run can resume current passing checks. Review polling uses the time remaining in a 100-second CLI or 50-second MCP call budget; long checks can still require a longer host timeout.
In practice the coding agent runs these commands itself. Claude Code and trusted Codex hooks can send it back when it stops early; other hosts rely on instructions and explicit visp next calls.
When supplying the original request explicitly, use --source-brief - with a quoted heredoc as shown in the workflow guide, so shell characters in the request stay literal.
visp feature "<request>"starts a feature and preserves the request with credential patterns and local paths masked. Under Claude Code and Codex, VISP takes it from the user's recorded prompt, so a paraphrase cannot replace it.visp work --check "<test command>"(the light path) works the whole request as one slice checked by that command. For several independently usable parts, write a brief instead:visp briefreads or updates.visp/features/<id>/brief.yaml(outcomes, behavior examples, decisions, checks and slices), andvisp workauthorizes one slice at a time.workdelivers the relevant outcomes, source excerpts, graph context, findings and memory, allows edits only inside the slice's scope, and refuses a slice with a functional outcome that no declared check exercises.- Independent tests. With
critic.launch: codex-execandcritic.harness: codex, orcritic.launch: claude-execandcritic.harness: claude-code, an independent tester started byvisp featurewrites acceptance tests from the request alone while the worker proceeds (new projects by default). VISP pins them only if they fail before implementation, and the worker cannot quietly change them. - Implement within the authorized files.
visp doneruns the slice's checks (plus anyworkflow.validationCommands, and the pinned tests on the last slice). If every check passes andcodex-execorclaude-execis configured, VISP runs the independent reviewer and returns its findings as the next repair step.visp nextreports the next action; fix the findings and runvisp doneagain. Required findings reopen the slice.visp acceptreruns the checks against the assembled product and requires a current assessment of every mandatory outcome. Once the review budget (three reviews by default) is spent with findings open,visp nexthands off tovisp prinstead, so the loop always ends.visp prprints the reviewer document: the request, outcomes, checks and their executed results, the independent tests, review findings, intent changes and the next step.
A check blocked by the host sandbox (for example, network sockets denied to a test server) is recorded as an environment failure, not a product failure. Rerun the same command with the host's sandbox escalation; do not change the product to work around it.
A slice needs an outcome, a bounded write scope and at least one runnable check for its functional outcomes. Checks are argument vectors or command strings run without a shell, or browser journeys that VISP drives in an isolated Chrome/Chromium:
outcomes:
- id: O001
kind: functional
statement: Starting the game switches it to the playing state.
priority: must
checks:
- id: C001
command: [node, --test, test/game.test.mjs]
outcomes: [O001]
files: [src/game.js, test/game.test.mjs]
verifierFiles: [test/game.test.mjs]
environment: node
- id: C002
command:
kind: browser-journey
journey:
url: http://localhost:3000/
viewport: { width: 390, height: 844 }
actions:
- { kind: click, selector: '#start', capture: true }
- kind: wait-for
selector: '#game'
attribute: { name: data-state, value: playing }
timeoutMs: 5000
capture: true
outcomes: [O001]
files: [index.html, src/game.js]
environment: browser
slices:
- id: T001
goal: Start a game from the title screen.
outcomes: [O001]
scope:
allowed: [index.html, src/game.js, test/game.test.mjs]
checks: [C001, C002]Adapt the selectors, URL and files to the real application. HTTP(S) journeys need the app to be running already. See the workflow guide for every brief field and product review for browser journeys.
The request and redacted check output are saved in the committed feature trail; visp pr includes the request in text intended for publication. Review that trail before committing. Raw command logs stay in ignored .visp/session/check-output/; redaction is best effort, and authored command definitions or screenshots can still contain private data.
| Command | Purpose |
|---|---|
visp init --harness <host> |
Create visp.yml and .visp/ |
visp install |
Install host instructions, MCP registration and scope hooks |
visp uninstall |
Remove what install wrote and still recognizes as VISP's (--dry-run previews; .visp/ and visp.yml stay) |
visp feature "<request>" |
Start a feature from the original request |
visp brief |
Read (--template) or update (--patch -, --from -) the brief |
visp work [--task <id>] |
Authorize a slice and deliver its context; --inspect reads without authorizing |
visp verify |
Run the slice's checks without closing it |
visp done |
Run checks, start independent review, close the slice when resolved |
visp next / visp status |
Read-only: next action / outcomes, progress and open findings |
visp capture --from - |
Run an ad hoc browser journey; --replay <run-id> reruns a recorded one |
visp review |
Prepare or submit a review session against current evidence |
visp critic |
Configure and run the independent reviewer; critic feedback asks the user |
visp reproduce |
Link a failed execution to an open finding before repair |
visp observations |
List an outcome's captured output and image paths |
visp accept |
Check the assembled product against its mandatory outcomes |
visp pr |
Print the reviewer document |
visp ui |
Open a live, read-only dashboard of the work in your browser |
visp index / visp query |
Build and query the repository graph |
visp learn / visp recall |
Record and recall project notes |
visp rules / visp rules remove <id> |
List or remove the rules the user stated for all later work |
visp skill |
Propose, admit and retire project skills |
visp guard |
Check changed files against the authorized scope (used by hooks and CI) |
visp trail prune |
Remove local captures and candidates no longer referenced by retained history |
visp doctor |
Check the setup; --settings explains effective configuration |
CLI text output is compact. --json prints the full result envelope. MCP tools reply with compact text plus the complete result in structuredContent; pass detail: true for full text.
Library callers should obtain a LoadedWorkspaceState with loadWorkspace() before calling the exported product and observation services. The older WorkspaceState shape without files remains supported by resolveFeature() only.
The critic is a separate model session that receives the original request, current source, check results and screenshots, but not the actor's verdicts or history. It returns an assessment of each outcome and up to three findings. With critic.launch: codex-exec (written by visp init --harness codex), VISP launches a read-only codex exec reviewer itself; the independent tester also runs when critic.harness: codex. This needs the Codex CLI signed in, whichever host does the coding. With critic.launch: claude-exec and critic.harness: claude-code, VISP launches a read-only claude -p reviewer instead, and the tester runs as a claude -p session too (new projects only). With launch: host (the default), the coding host delegates the review to its own subagent using the packet VISP prepares. See the critic guide.
On VISP's own benchmark (bench/: four tasks with hidden checks, Claude Haiku 4.5 as the coding agent, three runs per arm), VISP matched or beat every other arm on every task, most clearly on the larger ones: 35–37 of 38 on a spreadsheet engine against 26–35 for bare coding, Spec Kit and BMAD, and 56–63 of 63 over three rounds on extending an existing codebase against 41–59. It took about as long as Spec Kit (5–18 minutes) and longer than bare coding. With a stronger coding agent the gap was small. The runs are few and the tasks are VISP's own; see the research summary for every number and its limits.
- Workflow: briefs, slices, checks, scope and the check gate
- Product review: browser journeys, capture and review sessions
- Critic: independent review setup, launch modes and budgets
- Dashboard:
visp ui, the live local view of checks, reviews and questions - Configuration:
visp.yml, the repository graph and.visp/ - Migration: upgrading saved history and the 0.5 removals
- Runner: the optional
visp-runnerexperiment runner - Internals: state integrity, learning records and prompt design
- Research summary: what VISP's own experiments have shown
- Contributing, code of conduct, security policy and changelog
Apache License 2.0. Copyright 2026 Dineth Keshawa Jayathilaka; see NOTICE.