Skip to content

Command reference

The complete skillsvault command set. Every command returns through a single dispatcher that prints any error and sets the exit code; the one exception is gate, whose exit code is the protocol the harness hook reads.

skillsvault <command> [flags]

Exit codes at a glance

Most commands exit 0 on success, 1 on error. try exits 0 even when it shows a block — it is a demonstration, not a gate. scan exits 0 even when it flags something unless you pass --fail-on-flag. gate is special: 0 for allow and warn, 2 for block. A Ctrl-C interrupt exits 130 (128 + SIGINT). An unknown command exits 1.

login

Sign in and authorize this machine via the browser device-code flow. Mints an agent key for you — no key needed up front. See Install & connect.

skillsvault login [--url <base>] [--headless] [--machine <name>] [--import-scan [--with-content]]
skillsvault login --key <agent-key> --org <slug> [--url <base>] [--machine <name>]
FlagDefaultMeaning
--urlhttps://skillsvault.iocontrol-plane base URL (see below)
--machinehostnamemachine name recorded in the fleet
--headlessoffprint the URL + code instead of opening a browser
--import-scanoffafter connecting, upload this machine's scan — metadata only; see Importing a scan
--with-contentoffwith --import-scan: also upload the files of unmanaged skills, subagents and commands, so the console can import them
--key—agent key: connect without the browser, exactly like configure
--org—org slug; required with --key

The control-plane URL is resolved as: --url flag, then the SKILLSVAULT_URL environment variable, then the URL this machine is already configured for, then https://skillsvault.io. For local development: SKILLSVAULT_URL=http://localhost:3000 skillsvault login.

Once authorized, login syncs the bundle straight away (CLI 0.4.0 and later) — there is no separate sync step — and prints the next step: skillsvault try, then skillsvault install-hook, when your org already bans a skill; otherwise skillsvault pull --all and a link to the dashboard. configure does the same.

✓ authorized · org acme
✓ bundle v1750848000 verified & synced · 4 skills · 3 active policies
  → next: skillsvault try — watch a banned skill get blocked here
  → then: skillsvault install-hook — enforce it in Claude Code

If that first sync fails, the machine stays connected and the hint is → next: skillsvault sync.

Exit: 0 authorized · 1 denied / expired / timed out, --with-content without --import-scan, or (with --import-scan) the upload was refused — the machine stays connected · 130 Ctrl-C.

logout

Remove this machine's local config (org + agent key) and, unless told otherwise, the synced bundle. Idempotent — running it when nothing is configured is a no-op.

skillsvault logout [--keep-bundle]

--keep-bundle clears credentials but leaves ~/.skillsvault/bundle.json in place. Exit: 0 / 1.

configure

Connect non-interactively with an org slug and an agent key (CI, headless). Pins the signing key, then syncs and prints the next step exactly like login. login --key <key> --org <slug> is the same command.

skillsvault configure --org <slug> --key <agent-key> [--url <base>] [--machine <name>] [--import-scan [--with-content]]
FlagDefaultMeaning
--org— (required)organisation slug
--key— (required)agent key (skillsvault_ak_…)
--urlhttps://skillsvault.iocontrol-plane base URL — same resolution as login (--url > SKILLSVAULT_URL > saved config > default)
--machinehostnamemachine name
--import-scanoffupload this machine's scan after connecting — as for login
--with-contentoffwith --import-scan: include the files of unmanaged skills

Exit: 0 / 1 (missing --org/--key is an error, as is --with-content without --import-scan).

sync

Pull and verify the signed policy bundle, then store it locally. A bundle whose Ed25519 signature does not verify against the pinned key is rejected and the last-good bundle is kept.

skillsvault sync [--harness <h>] [--quiet]
✓ bundle v1750848000 verified & synced · 4 skills · 3 active policies
  → next: skillsvault pull

login, configure and try all sync for you, and from CLI 0.6.0 the gate refreshes a bundle older than an hour in the background (as sync --quiet, which prints nothing on success); run sync on its own to pick up a policy change straight away. --harness (default claude_code) is the harness this machine reports as in the fleet. sync also tells the control plane this machine is alive and what its hook covers, and prints an upgrade hint on stderr when a newer CLI is out.

sync also sends any audit events a gate had to queue while the control plane was unreachable (~/.skillsvault/audit-spool.jsonl, CLI 0.6.0 and later), and says so on stderr: ✓ delivered 3 audit events queued while the control plane was unreachable. pull, try and login do the same. See The runtime gate.

It also reports which invocation paths this machine's Claude Code hook gates. If the hook covers only some of them (the "Skill"-only config from before 0.5.1), it prints one line to stderr naming what isn't gated and the settings file to paste install-hook's output into. detect prints the same line.

Exit: 0 / 1 (network error, non-200 status, bad envelope, or signature failure).

try

The first-run demonstration: see a skill your org banned get blocked on this machine. try syncs the bundle (exactly as sync does), picks a skill, gates it exactly as gate does — local evaluation, the decision printed, then the audit event shipped (or queued, if the control plane doesn't answer within 1.5 seconds).

skillsvault try [--skill <ns/skill>]
FlagDefaultMeaning
--skilla banned skillthe skill to try; otherwise the first skill in the bundle whose status is banned, preferring one whose name contains demo
✓ bundle v1750848000 verified & synced · 4 skills · 3 active policies

▸ skillsvault try gating acme/demo-banned as an agent on this machine would…

⛔ BLOCKED  acme/demo-banned@1.0.0
   Skill version is banned by the organisation.

This is what your agents will see.
  audit: https://skillsvault.io/acme/audit
  → skillsvault install-hook — enforce it in Claude Code

Without --skill, try picks a skill the gate blocks — banned, or (from CLI 0.6.7) covered by a Block policy — preferring one named "demo". When nothing is blocked yet, try says so and links the console's skills page (/<org>/skills), where you can ban one and run try again.

Exit: 0 — even when the skill is blocked. try is a demonstration, not a gate; use gate (exit 2 on block) wherever an exit code must veto something. 1 on error (not configured, sync failed).

pull

Install the org's approved skills into a harness; a banned skill already present in the folder pull installs into for that harness is removed (the governance action). Copies elsewhere on disk — a project's own skills folder, say, or an agent this pull didn't install into — aren't deleted (they may be someone's edits); from CLI 0.6.7, pull names each one at the end of its output so it can be removed. Writes SKILL.md plus any bundled scripts//references//assets/ files, rejecting unsafe paths (absolute or ..). Reports the installed inventory back to the fleet via a heartbeat.

skillsvault pull [--harness <h>] [--all] [--dir <skills dir>]
FlagDefaultMeaning
--harnessclaude_codetarget a single harness by key
--alloffinstall into every detected harness on the machine
--dir—override the skills directory (e.g. for tests / unknown harnesses)
  ✓ acme/hubspot-crm-entry@1.3.0
  ✓ acme/code-reviewer@1.0.0 (subagent)
  ⛔ removed banned acme/teamleader-crm-entry

✓ pulled into /Users/me/.claude/skills
  2 installed · 1 banned removed (1 banned total)

With --all, each detected harness gets its own ▶ <harness> <skills dir> heading and summary line.

pull also records, in ~/.skillsvault/names.json, the name Claude Code will invoke each installed subagent or skill by when its frontmatter name differs from its file name — the gate uses it to recognise the artifact. Run pull after upgrading the CLI so that file is written.

Each harness gets its artifacts exactly where it reads them — see Harness coverage. A subagent or command goes only to a harness that loads that kind as markdown; elsewhere it is skipped with a note. A harness with no Agent Skills support (Aider) is skipped by --all and refused by --harness. Every skill folder pull writes carries a .skillsvault-pulled marker; copies older CLI versions left in directories a harness doesn't read are removed when pull can prove it wrote them, and nothing else there is touched.

With --all and no harness detected, it errors and suggests --harness or --dir. Exit: 0 / 1.

publish

Publish a skill folder to the org registry, creating a new immutable, current version. Reads SKILL.md (required) and an optional skillsvault.json manifest. The registry stores the SKILL.md frontmatter description as the skill's description; the manifest's description is used only when the frontmatter has none. Bundles every file under scripts/, references/, and assets/.

skillsvault publish <path> [--name <org/skill>] [--version <semver>]
InputSourceNotes
pathfirst non-flag dir arg, else .folder containing SKILL.md
name--name, else skillsvault.json.namerequired; namespace/skill-name
version--version, else skillsvault.json.versiondefaults to 1.0.0
intent / targets / descriptionskillsvault.jsonmatcher inputs
✓ published acme/hubspot-crm-entry@1.3.0 (2 bundled files)

Publishing needs the owner, admin or governance officer role. A member's publish is recorded as a submission for review instead; nothing is published until a reviewer approves it:

✓ submitted acme/hubspot-crm-entry@1.3.0 for review
  Not published yet: an owner, admin or governance officer approves it.
  https://skillsvault.io/acme/requests/…

(CLIs before 0.6.5 print this as publish refused (202): Not published yet: submitted for review… and exit 1; the submission is recorded either way.)

Exit: 0 (published or submitted) / 1 (no SKILL.md, missing name, or a refusal from the registry). See Authoring & publishing.

detect

List the AI agents/harnesses found on this machine and how each is governed. Claude Code, the harness with a vetoing hook, is labelled from the hook actually installed — read from .claude/settings.json and .claude/settings.local.json in the current directory and ~/.claude/settings.json, as sync reports it (CLI 0.6.0 and later):

LabelMeaning
enforced (hook)a hook runs skillsvault gate for skills, subagents and typed /commands
partially enforced (hook misses …)a hook runs the gate but not for every path — typically the "Skill"-only config from before 0.5.1
not enforced (no gate hook)nothing runs the gate: skills are distributed, nothing vetoes them

Every other harness is distribution only.

skillsvault detect
skillsvault detect — AI agents found on this machine

  • claude_code    /Users/me/.claude/skills  not enforced (no gate hook)
  • cursor         /Users/me/.cursor/skills  distribution only
  • aider          no Agent Skills support — pull skips it

→ skillsvault pull --all  installs approved skills into all of the above

detect prints one line to stderr naming the fix when Claude Code's hook covers only some invocation paths (as sync does) or when Claude Code is installed with no gate hook at all:

⚠ no skillsvault gate hook is installed — Claude Code runs every skill unchecked; run skillsvault install-hook and paste its output into .claude/settings.json

Exit: 0. See Harness coverage.

scan

Inventory every skill, subagent, command and rule file your AI agents already have, with simple local risk flags. Available from CLI 0.3.0. Needs no account, no config, and no network — it is safe to run on any machine before you sign up.

skillsvault scan [--dir <path>] [--json] [--quiet] [--fail-on-flag]
FlagDefaultMeaning
--dir—also scan this directory (folders with SKILL.md are skills, other files are rules)
--jsonoffmachine-readable output (schema below)
--quietoffprint only flagged items — no header, summary, or call to action
--fail-on-flagoffexit 1 if anything is flagged (for CI)

Where it looks. Every location each harness skillsvault knows reads from (Harness coverage) — the same table pull installs from — both globally under $HOME and per project under the current directory: skill directories, the subagent and command directories where the harness has them, and rule/instruction files (.cursor/rules, .clinerules, GEMINI.md, .github/copilot-instructions.md, …), where each file is a rule. A directory several harnesses share (~/.agents/skills) is listed once.

What it reports per item: name, path, kind (skill / subagent / command / rule), whether a skill has a SKILL.md, whether its frontmatter carries name + description (commands need only description), and whether it is managed — it carries a skillsvault.json manifest, it carries the marker pull writes into every skill folder it installs, or it resolves to an artifact of the same kind in this machine's synced bundle.

Risk flags. Each flag is a narrow, explainable heuristic with a one-line reason — a prompt to look, never a verdict. Only risk flags mark an item as flagged; info flags are shown for context because they are common in perfectly legitimate skills.

  • pipe-to-shell (risk) — a download piped into a shell: curl … | sh, wget … | bash, sh -c "$(curl …)", bash <(curl …).
  • powerful-tools (risk) — allowed-tools (or a subagent's tools) grants Bash, Write, or WebFetch.
  • secret-paths (risk) — references ~/.ssh / SSH key names, a .env file, or a credentials file (.aws/credentials, .git-credentials, credentials.json, .netrc, .docker/config.json).
  • base64-blob (risk) — a base64 run longer than 1 KB.
  • scripts (info) — bundles executable scripts (.sh, .py, .js, …, anything under scripts/, or anything with the executable bit).
  • external-urls (info) — links to external domains (loopback and example.* ignored).
skillsvault scan — what your AI agents already have (local only, nothing sent)

▶ claude_code · global ~/.claude
  ✓ code-review    skill     managed
  ⚠ deploy-helper  skill     unmanaged  flagged
      ! pipe-to-shell  downloads and pipes into a shell (curl|sh) in SKILL.md
      ! powerful-tools allowed-tools grants Bash, Write
      ! secret-paths   references ~/.ssh (scripts/setup.sh)
      · scripts        bundles 1 script(s): setup.sh
      · external-urls  links to 1 external domain(s): get.example-tools.io
  • linked-skill   skill     unmanaged  symlink outside scanned dir — not read
  • ship           command   unmanaged

▶ cursor · project ./.cursor
  • style.mdc      rule      unmanaged

3 skills, 1 command, 1 rule file across 2 agents · 4 unmanaged · 1 flagged
Govern these → skillsvault login --import-scan

The summary counts each kind separately (CLI 0.6.0 and later). With nothing found it says so for the 17 agents skillsvault supports — Aider, which has no skill discovery, and the shared .agents/skills location aren't counted as agents. The last line appears only when this machine is not yet connected to an org: it connects the machine and brings this inventory with it (see Importing a scan). Colour follows the usual rules (NO_COLOR, TERM=dumb, --no-color, or a non-terminal stdout turn it off).

Safety guarantees. scan itself sends nothing over the network (only login --import-scan does, and only what is listed below), reads at most 256 KB of any file, and never follows a symlink that resolves outside the directory being scanned — such an entry is listed with symlink_escape: true and not read.

--json schema

schema_version is bumped on any breaking change; new fields may be added without a bump. Flag ids and severity values are part of the contract.

{
  "schema_version": 1,
  "cli_version": "0.6.5",
  "configured": false,
  "summary": { "items": 5, "harnesses": 2, "unmanaged": 4, "flagged": 1 },
  "groups": [
    {
      "harness": "claude_code",
      "scope": "global",
      "root": "/Users/me/.claude",
      "items": [
        {
          "name": "deploy-helper",
          "kind": "skill",
          "path": "/Users/me/.claude/skills/deploy-helper",
          "has_skill_md": true,
          "frontmatter_valid": true,
          "has_manifest": false,
          "managed": false,
          "symlink_escape": false,
          "flagged": true,
          "flags": [
            { "id": "powerful-tools", "severity": "risk", "reason": "allowed-tools grants Bash, Write" }
          ]
        }
      ]
    }
  ],
  "errors": []
}
FieldMeaning
scopeglobal (under $HOME), project (under the current directory), or dir (from --dir, harness custom)
kindskill, subagent, command, or rule
managed_bypresent when managed is true: manifest, pull (installed by skillsvault pull) or bundle
flaggedthe item has at least one risk flag
errorsunreadable directories, reported without failing the scan

Exit: 0 — even with flagged items — unless --dir is missing or output cannot be written (1). With --fail-on-flag, 1 when summary.flagged > 0.

Importing a scan (--import-scan)

Available from CLI 0.5.0. skillsvault login --import-scan (or configure --import-scan) connects the machine, then runs the same scan and uploads it, so your org's console shows what this machine's agents already have — under Harnesses → Skills found on your machines — instead of an empty fleet. Without the flag, login and configure upload nothing about local skills.

What is uploaded, by default — metadata only:

  • per item: harness, scope (global / project), name, kind, managed or not (and how), whether it is flagged, each flag's id, severity and one-line reason, and a sha256 content hash (the same hash the registry gives a published version with identical content);
  • the path as scan shows it — ~/… for an item under your home directory, ./… for one under the directory you ran the command in. Never an absolute path, and only items inside the harness skill directories (--dir locations are never uploaded);
  • the machine name and CLI version.

With --with-content it also uploads the files of unmanaged skills, subagents and commands — SKILL.md and the folder's text files, through the same 256 KB read cap and symlink boundary as scan. Managed items, rule files and anything a symlink points outside the scanned directory never carry content. The CLI says which of the two it is sending before it sends it.

Caps. At most 500 items per upload (the output says when more were found); content at most 512 KB and 100 files per item and 2.5 MB per upload — an item over a cap is listed without its content. Each upload replaces the machine's previous one.

▸ import-scan uploading this machine's scan (metadata only: names, kinds, risk flags and content hashes — no file contents)
✓ imported 5 items · 4 unmanaged · 1 flagged
  → review them: https://skillsvault.io/acme/harnesses

In the console, every org member sees each machine's items with their unmanaged / flagged badges and flag reasons. A writer (owner, admin, governance officer) can, for each unmanaged item:

  • Import into registry — when its content was uploaded: creates <your-namespace>/<name> at 0.1.0. Otherwise the console shows the command to run on that machine, e.g. skillsvault publish ~/.claude/skills/deploy-helper --name acme/deploy-helper.
  • Ban this name — creates an active Specific skill policy with action Block for <your-namespace>/<name>, with the flag reason as its explanation. It ships in the next bundle.

A machine attributed to one member cannot have its scan replaced by another member's key (409).

gate

Evaluate a skill against the synced bundle and emit allow / warn / block. Full behaviour, including hook mode, is on The runtime gate.

skillsvault gate [--skill <name>] [--harness <h>] [--machine <name>] [--quiet]
FlagDefaultMeaning
--skill—skill to evaluate; if omitted, read from the hook payload on stdin
--harnessclaude_codeharness label recorded in the audit event
--machineconfig machinemachine-name override for the audit event
--quietoffonly emit on warn / block

--skill takes any name the harness might send — acme/deploy, deploy, /deploy, acme:deploy — resolved as described on The runtime gate.

Exit: 0 allow · 0 warn · 2 block · 1 when the machine has no bundle (or isn't configured and has none). The decision needs only the bundle, so a machine signed out with logout --keep-bundle still gates. In Claude Code hook mode the gate always exits 0: the veto is in the JSON, and with no bundle it fails open with a message rather than an error.

whoami

Show which organisation this machine is connected to — the org name, slug, and plan, confirmed with the control plane. Offline (or with a revoked key) it still prints the locally configured org, marked (could not verify online).

skillsvault whoami

Exit: 0, or 1 when the machine isn't configured.

status

Show the current config and synced-bundle freshness.

skillsvault status            # human-readable
skillsvault status --json     # machine-readable

The --json shape:

{
  "org": "acme",
  "base_url": "https://skillsvault.io",
  "machine": "macbook-pro",
  "bundle": {
    "version": 1750848000,
    "skills": 4,
    "policies": 3,
    "received_at": "2026-06-25T10:00:00Z"
  }
}

bundle is null when nothing has been synced yet. Exit: 0 / 1.

install-hook

Print the Claude Code hook config that wires the gate in: a PreToolUse hook with matcher Skill|Agent|Task (skills, and subagents under both tool names) and a UserPromptExpansion hook (a /command the user types). It only prints — paste the block into your Claude Code settings (~/.claude/settings.json for every project, or a project's .claude/settings.json). The command path is the absolute path of the running binary.

skillsvault install-hook
Add this to your Claude Code settings (.claude/settings.json) to gate skills,
subagents and commands:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Skill|Agent|Task",
        "hooks": [
          {
            "type": "command",
            "command": "/usr/local/bin/skillsvault gate"
          }
        ]
      }
    ],
    "UserPromptExpansion": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "/usr/local/bin/skillsvault gate"
          }
        ]
      }
    ]
  }
}

A machine set up before CLI 0.5.1 has a hook with matcher "Skill" and no UserPromptExpansion entry, which never sees subagents or typed commands: run install-hook again and replace the old skillsvault entry with the new block. See Harness coverage. Exit: 0.

version

Print the binary version.

skillsvault version          # also: --version, -v
# -> skillsvault 0.6.5