Skip to content
Testing
Skill

/verify-setup

One-time setup for /verify and /break. Sniffs the repo, confirms boot/seed/health with you, writes .verify/setup.json, captures auth if the app needs login, and builds .verify/profile.json, a model of how the app runs.

BOOST
From plugin
opslane-verify
1153 skills3 commands
Install
$ npx -y skills add opslane/verify --skill verify-setup --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/verify-setup

Context preview

The summary Claude sees to decide when to auto-load this skill.

One-time setup for /verify and /break. Sniffs the repo, confirms boot/seed/health with you, writes .verify/setup.json, captures auth if the app needs login, and builds .verify/profile.json, a model of how the app runs.

SKILL.md

verify-setup.SKILL.md
name: verify-setup
description: One-time setup for /verify and /break. Sniffs the repo, confirms boot/seed/health with you, writes .verify/setup.json, captures auth if the app needs login, and builds .verify/profile.json, a model of how the app runs.

/verify-setup

Run once per repo. Later `/verify` runs read `.verify/setup.json` and ask nothing.

**Hard rule: never ask for or store passwords, API keys, or connection strings.** The one exception is captured browser session state (`.verify/auth.json`, written by the auth step below): it holds reusable cookies for the app under test, is gitignored, and deleting the file revokes it. Treat it like a logged-in browser profile, not a secret store. No production connection strings, no cloud keys. The most this file may reference is one of the repo's own local `.env` files, chosen by the user. If a user pastes a secret, refuse to write it and tell them to keep it in their environment.

1. Ignore rules

grep -qxF ".verify/" .gitignore 2>/dev/null || echo ".verify/" >> .gitignore

`.verify/setup.json` is the one file meant to be shared. After writing it, offer: "Commit `.verify/setup.json` so your team skips this interview? (y/n)" — on yes, `git add -f .verify/setup.json` and commit it.

Write the recipe, not the resolved values

The contract must work in every checkout and worktree of the repo, or the interview repeats forever. Two rules:

  • **Ports and hosts go through environment variables.** When the repo

documents per-worktree port variables (an AGENTS.md export block, a `.env.example`), write `http://localhost:${INGESTION_PORT:-8082}` — the repo's own variable name with the repo's default — never the number the current worktree happens to use. URL fields (`base_url`, `health_url`) support exactly `${VAR}` and `${VAR:-default}` — no nesting, no command substitution — expanded identically by the scripts and the engine at run time. Probes and boot are shell programs and expand everything the shell does, for free.

  • **Nothing run-scoped.** A probe that names a specific run's container

(`verify-20260901-042757-worker-1`) is dead the moment that run ends. Key probes to the compose service via the current run's project instead:

  docker ps --filter "label=com.docker.compose.project=$(jq -r .project .verify/run-env.json)" \
    --filter "label=com.docker.compose.service=worker" --format '{{.State}}' | grep -q running

Before offering the commit, re-read the drafted contract and reject your own draft if any field contains a resolved port number that has a documented variable, or any name containing a run id.

2. Sniff the repo

VERIFY_SCRIPTS="${VERIFY_SCRIPTS:-$CLAUDE_PLUGIN_ROOT/scripts}"
bash "$VERIFY_SCRIPTS/sniff.sh" > /tmp/verify-sniff.json
cat /tmp/verify-sniff.json

3. Confirm, one question per unknown

Use AskUserQuestion. Every option must come from the sniff output; the user corrects rather than authors. A single unambiguous candidate is taken silently and shown in the final summary.

  • Boot: options = each `.boot[]` candidate (label with its `cmd`), plus

"it's already running (breaks isolation — not recommended)" which selects `"mode": "external"`. **The chosen candidate's `mode` and `compose_file` are copied into the contract — never mix a process boot with a compose teardown.** For `"process"` mode, `health_url` is required — do not write the contract until the user supplies the URL to poll. For `"compose"` mode, write `teardown: "docker compose -f <file> down -v"` — a throwaway stack that keeps its volumes is not throwaway.

  • Seed: options = `.seed[]`, plus "no seeding" and "I have a data file to load"

(if chosen, ask for the path and put it in `seed_data_files`; it is a plain file the user produced themselves — how they made it is outside verify).

  • Env file: options = `.env_files[]`, plus "none". The chosen file is sourced

by the environment manager before boot, seeds, and probes.

  • Base URL: default `http://localhost:3000`, or the value in the env file if

it names one.

  • How do API requests authenticate? A) a header whose value lives in an env

var — name the header (for example, `X-API-Key`) and the env var name; or B) no auth. The value itself is never written anywhere: the contract stores only the header name and the env var name.

  • Probes: for each of `worker`, `sink`, `storage`, ask "is there a one-line

command that proves your <part> is alive? (leave blank to skip)". Explain: a part with no probe still runs its criteria, but a failure on it will be reported as possibly environmental rather than blamed on the change. (`api`, `browser`, and `db` have built-in probes; don't ask about them.)

If `.has_stack` is false: plain-command mode. Write the contract with `"mode": "none"` and empty boot/teardown/health, and say: "No runnable stack found; /verify will run criteria as plain commands."

4. Write the contract

Write `.verify/setup.json`. The shape (this example is load-bearing — a test parses it):

{
  "mode": "compose",
  "compose_file": "compose.yaml",
  "boot": "docker compose -f compose.yaml up -d --wait",
  "teardown": "docker compose -f compose.yaml down -v",
  "seed": ["scripts/seed-e2e.sql"],
  "seed_data_files": [],
  "health_url": "",
  "base_url": "http://localhost:${APP_PORT:-3000}",
  "auth": {"header": "", "value_env": ""},
  "env_file": ".env.example",
  "observe": {"db_url_env": "DATABASE_URL"},
  "probes": {"worker": "", "sink": "", "storage": ""}
}

Valid modes: `"compose"`, `"process"` (health_url required), `"external"`, `"none"`.

Show the written file and the summary of silently-taken single candidates.

5. Capture authentication, if needed

Keep authentication as Playwright storage state. It contains no password entry flow or credential capture by Verify; the user logs in directly in the browser.

Check whether the selected base URL is running:

VERIFY_
Read more
Ships withopslane-verify

Don't trust your agent. Verify it. Coding agents write more code than anyone can read, and reviewing the diff does not run it. So the agent says done and the tests are green, and both of those came from the agent.

Get the whole plugin
Stats
115
Stars
4
Forks
Active
Maintenance
TypeScript
Language
MIT
License
9d ago
Last commit
7mo ago
Created
3h ago
Added

Repo: opslane/verify

Other skills on opslane-verify.

break
Skill

break

Try to break a change the way the real world will - network faults, restarts, two things at once, users doing things out of order…