npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@controlvector/cv-agent

v1.21.0

Published

Standalone agent daemon for CV-Hub — bridges Claude Code with CV-Hub task dispatch

Readme

CV-Agent

Remote task dispatch daemon for CV-Hub. Bridges Claude Code with CV-Hub's agentic task system.

CV-Agent (cva) runs as a daemon on your machine, polls CV-Hub for dispatched tasks, spawns Claude Code to execute them, and reports results back. It handles permission relay, git remote management, and executor heartbeats.

npm License: MIT


Installation

npm install -g @controlvector/cv-agent

Requires Claude Code to be installed and on your PATH. --auto-approve (and every cvod-managed executor) needs Claude Code 0.2.117 or later, because it reads claude -p --output-format stream-json output.


Quick Start

# Authenticate with CV-Hub
cva auth login

# Add the CV-Hub remote to your repo
cd your-project
cva remote add

# Start the agent daemon (auto-approves Claude Code tool permissions)
cva agent --auto-approve

The agent will register as an executor with CV-Hub, poll for tasks, and execute them using Claude Code.


Commands

cva agent [options]

Start the agent daemon. Polls CV-Hub for pending tasks and executes them with Claude Code (the default) or cv-code.

cva agent                  # Start with permission relay to CV-Hub
cva agent --auto-approve   # Auto-approve all Claude Code permissions locally
cva agent --working-dir /path   # Override working directory (--dir is accepted as an alias)
cva agent --engine cv-code --model terastor-llm/deepseek-v4-flash --auto-approve   # cv-code, no Claude Code

Options:

  • --auto-approve — Auto-approve all tool permission prompts (no CV-Hub relay)
  • --working-dir <path> — Working directory for Claude Code sessions (alias: --dir)
  • --silence-timeout <minutes> — Fail a task whose engine produces no output for this long (default: 15). Separate from the task's timeout_at, which is also enforced.
  • --engine <engine>claude-code (default) or cv-code. See cv-code engine.
  • --model <provider/model> — The model cv-code must use. Required with --engine cv-code, rejected otherwise.
  • --trusted-config <path> — Operator-trusted config: pinned deploy manifests and credential-filter exemptions (default ~/.config/cva/trusted.json). See Operator-trusted configuration.
  • --targeted-only — Never be offered untargeted work. The executor runs only tasks dispatched to it by id or name. See Targeted-only executors.

Targeted-only executors

Without --targeted-only, an executor can be handed untargeted work. That means tasks nobody dispatched to a specific executor:

  • in an organization, any untargeted org task, the moment it is created;
  • after about a minute, any untargeted task it can see.

A new or experimental executor usually shouldn't take that. --targeted-only registers the executor with accepts_untargeted: false. CV-Hub then keeps it online and heartbeating but offers it nothing except tasks targeted at it, and never another executor's fallback. The banner's Routing: line shows which you are running.

The flag is verified, not assumed. CV-Hub echoes the routing preference back at registration. If it doesn't confirm accepts_untargeted: false, cva agent refuses to start: it marks the executor offline, and exits 1 before polling. That happens with a CV-Hub from before cv-hub#223, which silently drops the field. It exists because a flag that appears to work and doesn't is worse than no flag. Without the flag, nothing changes.

cv-code engine

--engine cv-code runs each task with cv-code (cvc) instead of Claude Code. Claude Code does not have to be installed: a cv-code executor never looks for claude, and its readiness check does not involve it.

Requirements

  • cvc on the executor's PATH (tested with 0.3.0), with the provider configured in cv-code's config for the user the executor runs as (~/.config/cv-code/). Run the executor as that user, not as root.
  • Node 20 or later for cva itself. A service or sudo shell often finds an older system node first. In that case start cva with an absolute path to a Node 20 binary, and put a PATH in front of it that contains cvc and git.

Readiness. At start, cva runs cvc --version and cvc endpoint test <provider>, and refuses to start if either fails. The same check replaces the Claude login re-check while the executor polls.

How it runs. cva drives cvc acp (the Agent Client Protocol, JSON-RPC over stdio) with one session per task. An answer to an engine question relayed through CV-Hub goes back into the same session as a follow-up prompt.

The model is verified, not assumed.

  • cva refuses to prompt unless --model is one of the models cv-code offers, and it sets that model explicitly. A new cv-code session otherwise defaults to a hosted model (cv-code#25).
  • cva checks every model request in cv-code's service=llm log lines. A request to any other model fails the run with ENGINE_ERROR.
  • At the end of each task, cva logs the request count, the models and the output tokens to the task. This is the token evidence when cv-meter records nothing.

Run verdicts are the same as for Claude Code:

  • NO_MODEL_TURN when no model request produced output. This catches cv-code exiting 0 without calling the model (cv-code#21).
  • ENGINE_SILENT when the ACP stream goes quiet (cv-code#18). cv-code's own stderr logging does not count as activity.
  • ENGINE_ERROR for a failed tool or a failed prompt (cv-code#19).

Permissions: auto-approve only.

  • A cv-code executor must be started with --auto-approve.
  • Every permission cv-code asks for is approved, except access outside the workspace. That covers cv-code's external_directory, for file tools and for bash commands whose outside paths cv-code detects. Such access is refused, and the task fails with ENGINE_ERROR, naming the path or the refused command.
  • A shell command that reaches outside in a way cv-code does not detect is not confined.

Not supported yet (#29):

  • relay mode, where permissions are approved from CV-Hub
  • --profile, whose tool policy cva cannot enforce on cv-code yet

cva refuses both at start rather than ignoring them.

The executor registers with CV-Hub as type custom, engine cv_code.

cva auth login

Authenticate with CV-Hub. Opens a browser for device auth flow, or accepts a token paste.

cva auth login

Token is stored in ~/.config/cva/config.json.

cva remote add [--name <n>]

Add or update the CV-Hub git remote for the current repository.

cva remote add                          # Auto-detects from CV-Hub
cva remote add --name cvhub             # Custom remote name (default: cvhub)

cva remote setup <owner/repo>

Create a repo on CV-Hub and configure the local remote in one step.

cva task list [--status <status>]

List tasks for the current executor.

cva task logs <task-id>

Stream task logs and progress.

cva status

Show executor registration status, active tasks, and recent completions.


How It Works

  1. cva agent registers this machine as an executor with CV-Hub
  2. It polls CV-Hub every 5 seconds for pending tasks
  3. When a task is claimed, it spawns Claude Code with the task prompt
  4. Permission handling: Claude Code tool calls require approval:
    • --auto-approve: writes y to stdin automatically
    • Default: relays prompts to CV-Hub for remote approval (e.g., from Claude.ai)
  5. When Claude Code exits, the agent decides the task's verdict before it writes anything to the repository (see below), then reports it to CV-Hub with the files changed, commits and exit code
  6. Heartbeats are sent every 30 seconds while the run is healthy. A run that has gone silent past the watchdog threshold, or has been terminated, stops sending the task heartbeat

How a task is judged

An exit code of 0 is not treated as proof that work happened. A task is completed only on positive evidence:

  • the working tree changed during the run (compared with a fingerprint taken before it started), or
  • for task types that need not change files (review, research, debug, test, deploy, custom), the engine reported at least one model turn.

A code_change task (or any task whose metadata.expects_changes is true) that changed nothing fails with NO_CHANGES. Every other failure names its cause too: TIMEOUT (past timeout_at), ENGINE_SILENT (no output for --silence-timeout), ENGINE_FAILED, ENGINE_ERROR, NO_MODEL_TURN, WORKSPACE_UNVERIFIABLE, NO_EVIDENCE, ABORTED, AUTH_FAILED.

Only a completed task is committed and pushed by the git safety net. A failed run is quarantined and nothing is pushed: its uncommitted changes go into a local stash labelled cva: FAILED run, contents are partial, do not merge, and any commits the engine made move to a local cva/failed/<task-id> branch while the working branch goes back to where it was. Recover them with git stash apply <sha> or git merge cva/failed/<task-id>.

What the safety net commits. It judges every file on its own. It lists the working tree with git status --porcelain -z -uall, so a directory the engine created is listed file by file, not as one dir/ entry (#24). It acts on those names literally (GIT_LITERAL_PATHSPECS), so a file named ?env never stages .env with it.

It leaves these out, and records each one in ~/.cva/git-safety-audit.log with its reason:

  • Credentials. That means credential stores and key files by path, and files whose content carries a credential signature. It includes a change to a tracked credential file such as a committed .env: the change stays in the working tree, uncommitted.
  • Untracked files that existed before the task.
  • Generated artifacts (#30): __pycache__/, *.pyc, *.pyo, .pytest_cache/, .mypy_cache/, .ruff_cache/, .tox/, .nox/, .ipynb_checkpoints/, .venv/, node_modules/.
  • An untracked directory git will not list file by file, such as a nested repository, because its files cannot be checked.

It also respects .gitignore: ignored files are never listed, so they are never committed.

  • Build outputs such as dist/ and build/ are not on the generated list, because some repositories commit them on purpose. If yours does not, put them in .gitignore.
  • The generated list is applied by the safety net itself. It is not written into the workspace's .gitignore.

Before committing, the safety net reads the index back and commits only if it holds exactly the files it approved. If the engine staged a file the filter left out, the safety net unstages it first.

The safety net refuses in three cases:

  • it cannot list the working tree;
  • it cannot read the index back;
  • the index holds anything it did not approve.

When it refuses, nothing is committed or pushed, the changes stay in the working tree, and the task fails with SAFETY_NET_REFUSED.

Commits are judged too, the engine's own included (#33). Before any push, the safety net lists every commit the push would carry.

  • The range. The commits reachable from HEAD that the remote does not have. The remote's refs are read live, and history already on the remote is never judged again.
  • The same filter. Each file a commit adds or changes goes through the same per-file filter, with its content read from the commit.
  • Merges. A merge is judged by what the merge commit itself changed. The merged branch's own commits are in the range.
  • Deleted files still count. A file added in one commit and deleted in the next is still refused, because its content would still reach the remote.

The safety net refuses on an excluded file, or if it cannot read the remote, the range or a commit. Then nothing is pushed, and the task fails with SAFETY_NET_REFUSED, naming each commit and file. The audit log records them as commits: [{commit, path, reason}].

Nothing is rewritten or amended: the commits stay local, and taking the file out of them is left to you. The safety net never force-pushes, so if the remote has moved on, the remote rejects the push as before.

Git Remote Management

Before each task, the agent ensures a cvhub remote exists pointing to the correct CV-Hub repo URL. Task prompts are prepended with instructions to push to cvhub instead of origin.


Prerequisites

| Requirement | Version | Notes | |-------------|---------|-------| | Node.js | >= 20 | Runtime | | Claude Code | Latest | Must be on PATH as claude | | CV-Hub account | — | Sign up at hub.controlvector.io |


Configuration

Global config file: ~/.config/cva/config.json

{
  "hub": {
    "api": "https://api.hub.controlvector.io",
    "token": "cvh_xxxxxxxxxxxx"
  },
  "agent": {
    "pollInterval": 5000,
    "heartbeatInterval": 30000,
    "autoApprove": false,
    "maxConcurrentTasks": 1
  },
  "defaults": {
    "remoteName": "cvhub"
  }
}

An Anthropic API key can be configured as a fallback for Claude Code authentication:

cva auth set-api-key sk-ant-...

This stores anthropic_api_key in the config file. If ANTHROPIC_API_KEY is already set in the environment, the env var takes priority.

Workspace-local config can be placed in .cva/agent.json within your project directory.

Operator-trusted configuration

Some decisions must never be the engine's to make: which commands run on the host after a task, and which files the credential filter lets through. The engine can write anything in the workspace, so cva takes those decisions only from operator-trusted configuration. It lives outside the workspace, in the executor's own config, and nothing inside a workspace, including .cva/agent.json and a .cva/trusted.json, is ever read for it.

  • Where it lives. ~/.config/cva/trusted.json, or the file you pass with cva agent --trusted-config <path>.
    • cva agent reads it once, at start. Restart it after editing the file.
    • The banner shows what was loaded.
    • If the file is writable by the executor's own user, cva agent warns at start: an engine with shell access running as that user could edit it. For a boundary the engine cannot cross, use a file that user cannot write, such as root:root mode 0644, and pass it with --trusted-config.
  • Fail closed.
    • No file means nothing is trusted.
    • A file that cannot be read, parsed or validated also means nothing is trusted, and that is said at start and in every decision.
    • The file is strictly validated: unknown keys, relative workspace paths and malformed hashes all invalidate it.
{
  "version": 1,
  "deploy_manifests": {
    "/home/deploy/app": { "sha256": "3b1f…<64 hex chars>" }
  },
  "credential_filter_exempt": {
    "/home/deploy/app": [".env.example", "web/.env.sample"]
  }
}

Workspace keys are the absolute path the executor runs in (--working-dir).

Enabling a deploy manifest (#27). After a verified task, cva runs <workspace>/.cva/deploy.json (build, migrate, restart, verify) only if its sha256 matches the pin for that workspace:

  1. Read the manifest, and make sure it is the one you want run.
  2. Get its hash with sha256sum <workspace>/.cva/deploy.json, and add it under deploy_manifests.
  3. Restart cva agent.

A manifest with no pin, or one that changed after it was pinned, is not run. That covers one the engine created or edited, and one you edited without re-pinning. When that happens:

  • the task log gets a DEPLOY MANIFEST IGNORED error;
  • the completion summary says so;
  • the audit log records the decision, the manifest's sha256 and the reason;
  • at start, cva agent warns if the workspace's manifest will not run.

The check is on who wrote the manifest, never on what its commands look like. A trusted manifest's commands still run through a shell. Trust covers the manifest itself, not whatever it invokes: a step like npm run build runs the task's own build scripts, as it always did.

Exempting a path from the credential filter (#34). The credential filter refuses files whose names match credential patterns, .env* among them. To let a file such as .env.example through, list its exact path, relative to the workspace root, under credential_filter_exempt, then restart cva agent.

  • It is one exact path. .env.example does not cover web/.env.example.
  • It lifts only the name-based rule. A generated artifact is still left out, and a file whose content carries a credential signature (a real key) is still refused.
  • Every exemption used is recorded in the audit log, with its basis.

Why a Separate Binary?

CV-Git (cv) and CV-Agent (cva) are separate packages to avoid a recursion trap: cv agent would spawn Claude Code, which might call cv commands, creating a circular dependency. By using cva as the agent binary, Claude Code sessions use standard git commands only.

| Binary | Package | Responsibility | |--------|---------|---------------| | cv | @controlvector/cv-git | Git operations, knowledge graph, code analysis, local dev | | cva | @controlvector/cv-agent | Agent daemon, task dispatch, CV-Hub remote management |


Related Projects

  • CV-Git (cv) — AI-native version control CLI
  • CV-Hub — AI-native Git platform (web app + API)

License

MIT