Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions .agents/skills/version-sentinel/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
name: version-sentinel
description: Use when adding, bumping, or changing a dependency in package.json, requirements*.txt, constraints*.txt, pyproject.toml, Cargo.toml, *.csproj, *.fsproj, or *.vbproj. Triggered automatically by version-sentinel's PreToolUse hook (where the host supports hooks) — this skill explains how to satisfy the block and record a version check.
---

# Version Sentinel — Workflow

The `version-sentinel` setup blocks dependency changes until you've verified the package version against its upstream registry. Here's the required flow. (On hosts without hook support, such as Zed, this same flow applies manually — follow it whenever you touch a manifest or run an install command.)

## When you see a BLOCKED message

If a tool call exits 2 with `BLOCKED: version-sentinel`, you must:

1. **Look up the latest version.** Use a web search first:
- `npm`: search `"<pkg> latest version site:npmjs.com"`
- `pip`/`pyproject`: search `"<pkg> latest version site:pypi.org"`
- `csproj`: search `"<pkg> latest version site:nuget.org"`
- `cargo`: search `"<pkg> latest version site:crates.io"`

If web search is unavailable, fetch the registry URL directly, or consult a docs tool (e.g. context7) for the package.

2. **Record the check.** Run in the terminal:

bash scripts/vs-record.sh <ecosystem> <pkg> <version-you-intend-to-install> <source-url>

The source must be an `http(s)://` URL from your search OR prefixed with `intentional:` for deliberate pins.

3. **Retry the original edit or install.** The hook will see the fresh entry and let the tool call through.

## Intentional non-latest pins

If you genuinely intend to install an older version (CVE mitigation, compat, private registry), record with:

bash scripts/vs-record.sh <ecosystem> <pkg> <version> "intentional: <brief reason>"

This passes the hook and is flagged as `intentional-pin` (not `DRIFT`) in `bash scripts/check-versions.sh` output.

## What NOT to do

- Don't fake a source URL you didn't actually see. The skill contract assumes honest reporting.
- Don't try to bypass the hook with `git commit --no-verify` or similar — the hook runs on file edits and terminal commands, not on git.
- Don't `unset VS_DISABLE` without the user's awareness; that's an escape hatch for throwaway sessions, not normal flow.

## Audit command

`bash scripts/check-versions.sh` scans manifests within 4 directory levels of the current directory and reports drift. Run it before tagging a release.
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/claude-code-marketplace.json",
"name": "version-sentinel-marketplace",
"version": "0.2.1",
"version": "0.3.0",
"description": "Claude Code plugin that hard-blocks dependency additions, bumps, and downgrades until a fresh, source-cited version check is recorded. Supports npm, pip, Poetry/uv, Cargo, and NuGet.",
"owner": {
"name": "Daniel Kiska",
Expand Down
22 changes: 22 additions & 0 deletions .codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "version-sentinel",
"version": "0.3.0",
"description": "Hard-blocks dependency additions and version changes until the agent records a WebSearch-verified latest-version check.",
"author": {
"name": "Daniel Kiska",
"url": "https://github.com/KSEGIT"
},
"homepage": "https://github.com/KSEGIT/Version-Sentinel#readme",
"repository": "https://github.com/KSEGIT/Version-Sentinel",
"license": "MIT",
"keywords": [
"dependencies",
"packages",
"versions",
"guardrails",
"hooks",
"supply-chain-security"
],
"skills": "./skills/",
"hooks": "./hooks/hooks.json"
}
28 changes: 28 additions & 0 deletions .github/agents/version-reviewer.agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
name: version-reviewer
description: Use before tagging a release, merging a release PR, or whenever the user asks to audit dependency freshness. Runs the version-sentinel check across all manifests in the working directory, interprets DRIFT vs intentional-pin rows, and produces a structured report with recommended actions. Read-only — does not edit files.
tools: ['search', 'read', 'execute']
---

You are the version-sentinel release-audit reviewer. Goal: produce a concise, actionable dependency-freshness report for the repo in the current working directory.

## What to run

1. `bash scripts/check-versions.sh`. Capture full output.
2. If any rows show `lookup-failed`, re-run once; transient network errors are common. Don't retry more than twice.

## What to report

Group output into three sections:

- **DRIFT** — rows where current ≠ latest and no `intentional:` record. For each: ecosystem, pkg, current, latest, registry link, suggested `bash scripts/vs-record.sh ...` command to take before bumping.
- **intentional-pin** — rows the user has deliberately pinned. List with the recorded reason (pulled from the sidecar `.version-sentinel/checks.json` via `jq`). Flag any pins older than 30 days as "re-review recommended".
- **lookup-failed** — registry fetch failed. List with the registry URL the user can check manually.

## Rules

- Do not modify any files. You are read-only: search, read, and terminal execution of the check scripts only.
- If the repo has no recognized manifests, say so and exit.
- Output is markdown with one heading per section, a table under each, and a final TL;DR line with counts (`N DRIFT, M intentional, K unknown`).
- Keep the full report under 400 words.
- If there are 0 DRIFT and 0 lookup-failed, end with: `READY TO RELEASE`.
27 changes: 27 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Version Sentinel

This workspace uses version-sentinel: dependency edits and install commands are blocked (via workspace hooks) until the target version is verified against its upstream registry and recorded.

## When a tool call is BLOCKED with "version-sentinel"

1. Look up the latest version of the package on its upstream registry:
- npm → npmjs.com
- pip / pyproject → pypi.org
- cargo → crates.io
- csproj → nuget.org
2. Record the check by running in the terminal:
`bash scripts/vs-record.sh <ecosystem> <pkg> <version> <source-url>`
The source must be an `http(s)://` URL you actually saw, or `intentional: <reason>` for deliberate pins.
3. Retry the original edit or install — the hook will see the fresh record and let it through.

## Intentional pins

To deliberately install a non-latest version (CVE mitigation, compatibility), record with `intentional: <reason>` as the source. These show as `intentional-pin`, not `DRIFT`, in audits.

## Audit

Run `bash scripts/check-versions.sh` before tagging a release. It scans `package.json`, `requirements*.txt`, `constraints*.txt`, `pyproject.toml`, `Cargo.toml`, `*.csproj`, `*.fsproj`, and `*.vbproj` and reports drift without blocking.

## Escape hatch

Set `VS_DISABLE=1` in the environment to disable blocking for a session (throwaway work only, with the user's awareness).
33 changes: 33 additions & 0 deletions .github/hooks/version-sentinel.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"hooks": {
"SessionStart": [
{
"type": "command",
"command": "bash scripts/prereq-check.sh",
"timeout": 10
}
],
"PreToolUse": [
{
"matcher": "Edit|Write|MultiEdit|apply_patch|editFiles|createFile|write_file|replace",
"type": "command",
"command": "bash scripts/detect-manifest-edit.sh",
"timeout": 10
},
{
"matcher": "Bash|run_shell_command|runTerminalCommand|exec_command",
"type": "command",
"command": "bash scripts/detect-install-cmd.sh",
"timeout": 10
}
],
"PostToolUse": [
{
"matcher": "Bash|run_shell_command|runTerminalCommand|exec_command",
"type": "command",
"command": "bash scripts/auto-record.sh",
"timeout": 10
}
]
}
}
14 changes: 14 additions & 0 deletions .github/prompts/check-versions.prompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
description: Audit dependencies against upstream registries (npm, pypi, nuget, crates.io)
agent: agent
---

Use the terminal tool to run `bash scripts/check-versions.sh` in the workspace root. It scans manifests under the current directory and compares each dependency version to the latest upstream. Supported (v0.1): `package.json`, `requirements*.txt`, `pyproject.toml`, `Cargo.toml`, `*.csproj`.

Relay the full output to the user, then interpret it briefly:

- **DRIFT** rows: current ≠ latest with no `intentional:` record. Suggest looking up the latest version and recording it with `bash scripts/vs-record.sh <ecosystem> <pkg> <version> <source-url>` before bumping.
- **intentional-pin** rows: deliberate pins with a recorded reason — no action needed unless the pin is stale.
- **lookup-failed** rows: registry fetch failed; suggest re-running once, then checking the registry URL manually.

This audit reports drift without blocking anything.
20 changes: 20 additions & 0 deletions .github/prompts/vs-record.prompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
description: Record a fresh version check in the version-sentinel sidecar
agent: agent
argument-hint: <ecosystem> <pkg> <version> <source-url-or-intentional:>
---

Record that a dependency version has been verified. Run after a web search or registry fetch confirms the version.

**Usage:** `/vs-record <ecosystem> <pkg> <version> <source>`

**Source** must be an `http(s)://` URL or `intentional:<reason>`.

**Ecosystems (v0.1):** npm, pip, cargo, csproj, pyproject

**Examples:**
- `/vs-record npm lodash 4.17.21 https://www.npmjs.com/package/lodash`
- `/vs-record pip requests 2.31.0 https://pypi.org/project/requests/`
- `/vs-record csproj Serilog 3.1.1 "intentional: CVE lock pending audit"`

Use the terminal tool to run `bash scripts/vs-record.sh` with the arguments the user supplied, exactly as given. When the fourth argument is an intentional-pin reason, pass it as ONE quoted argument preserving the "intentional: <reason>" format. Relay the script's output verbatim to the user. If the script fails, show its stderr and do not retry with modified arguments unless the user asks.
66 changes: 66 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Version Sentinel — Cross-Agent Instructions

Version Sentinel is a guardrail that prevents stale, hallucinated, or compromised dependency versions from reaching your manifests. Before any dependency is added, bumped, downgraded, or installed, the agent must verify the intended version against its upstream registry and record that check. Checks are stored in `.version-sentinel/checks.json` and expire after a freshness window (default 24h).

## Required workflow when a dependency change is blocked

If a hook blocks an edit or install (exit 2, `BLOCKED: version-sentinel`), or if you are about to change any dependency on a platform without hooks:

1. **Look up the latest version on the upstream registry** via web search or fetch:
- npm: `https://www.npmjs.com/package/<pkg>`
- pip / pyproject: `https://pypi.org/project/<pkg>/`
- cargo: `https://crates.io/crates/<pkg>`
- csproj (NuGet): `https://www.nuget.org/packages/<pkg>`
2. **Record the check:**

```bash
bash scripts/vs-record.sh <ecosystem> <pkg> <version> <source-url-or-intentional:reason>
```

The source must be an `http(s)://` URL you actually consulted, or `intentional:<reason>` for deliberate pins (e.g. CVE lock, compatibility). Example:

```bash
bash scripts/vs-record.sh npm lodash 4.17.21 https://www.npmjs.com/package/lodash

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Keep supported-manifest documentation consistent.

The scanner supports constraints*.txt, *.fsproj, and *.vbproj, but both audit descriptions omit them.

  • AGENTS.md#L23-L23: update the documented audit manifest list.
  • .github/copilot-instructions.md#L23-L23: update the documented audit manifest list.

As per coding guidelines, all supported manifest patterns must be documented consistently.

📍 Affects 2 files
  • AGENTS.md#L23-L23 (this comment)
  • .github/copilot-instructions.md#L23-L23
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@AGENTS.md` at line 23, Update the audit manifest list in AGENTS.md at lines
23-23 and .github/copilot-instructions.md at lines 23-23 to include
constraints*.txt, *.fsproj, and *.vbproj, keeping both descriptions identical
and consistent with the scanner’s supported patterns.

Source: Coding guidelines

bash scripts/vs-record.sh csproj Serilog 3.1.1 "intentional: CVE lock pending audit"
```

3. **Retry the edit or install.** With a fresh entry on record, the hook (where present) lets the operation through.

Never fabricate a source URL you did not actually consult, and never bypass the record step to force a dependency change through.

## Audit

```bash
bash scripts/check-versions.sh
```

Scans manifests within 4 directory levels of the current directory, compares each dependency against its upstream registry, and reports drift. Intentional pins show as `intentional-pin`, not `DRIFT`. Run before tagging a release.

## Supported manifests

`package.json` (npm/pnpm/yarn/bun), `requirements*.txt`, `constraints*.txt`, `pyproject.toml` (pip, Poetry, uv), `Cargo.toml`, and `*.csproj` / `*.fsproj` / `*.vbproj` (NuGet).

## Escape hatch

`VS_DISABLE=1` makes all hooks no-op (block, prereq warning, auto-record). Use only for throwaway sessions; do not set it without the user's awareness.

## Platform behavior

- On platforms with hooks (Claude Code and derivatives such as z.ai's ZCode / GLM Coding Plan, Kimi Code, OpenAI Codex), the workflow above is **enforced automatically** via PreToolUse hooks.
- On platforms without hooks (e.g. Zed), you MUST follow the same workflow **voluntarily** before any dependency change: look up the version, run `bash scripts/vs-record.sh ...`, then make the edit.

## Project structure

- `plugin.json`, `.claude-plugin/` — Claude Code plugin manifest and metadata.
- `kimi.plugin.json` — Kimi Code plugin manifest (root); `kimi-marketplace.json` — Kimi marketplace catalog.
- `gemini-extension.json`, `GEMINI.md` — Gemini CLI extension manifest and context; `hooks/gemini-hooks.json` + `platforms/gemini/setup.sh` — Gemini hook wiring.
- `.codex-plugin/plugin.json` — OpenAI Codex plugin manifest (reuses `hooks/hooks.json`).
- `.github/` — GitHub Copilot: `hooks/`, `agents/`, `prompts/`, `copilot-instructions.md`.
- `.agents/skills/` — cross-tool skills (Copilot, Zed, Codex).
- `AGENTS.md` — this file; read automatically by Codex, Zed, and GitHub Copilot.
- `scripts/` — hook and workflow scripts (`vs-record.sh`, `check-versions.sh`, `detect-manifest-edit.sh`, `detect-install-cmd.sh`, `auto-record.sh`, `prereq-check.sh`).
- `commands/` — Claude Code slash commands (`/vs-record`, `/check-versions`).
- `platforms/kimi/commands/` — Kimi Code command files (same workflow, `$KIMI_PLUGIN_ROOT`-based).
- `skills/version-sentinel/` — agent skill explaining how to satisfy the hook.
- `hooks/hooks.json` — hook definitions (Claude Code / Codex schema).
- `tests/` — shell test suite; run `tests/run.sh`.
18 changes: 14 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
# Version Sentinel

Claude Code plugin that hard-blocks dependency additions, bumps, and downgrades until a fresh, source-cited version check is recorded.
Claude Code plugin that hard-blocks dependency additions, bumps, and downgrades until a fresh, source-cited version check is recorded. Multi-agent: ships adapters for Claude Code (also covers z.ai GLM Coding Plan / ZCode, which reuse the Claude Code plugin format), Kimi Code, GitHub Copilot (VS Code), Gemini CLI, OpenAI Codex, and Zed.

## Project structure

```
.claude-plugin/ Plugin + marketplace metadata (plugin.json, marketplace.json)
hooks/hooks.json Hook definitions (SessionStart, PreToolUse, PostToolUse)
plugin.json Claude Code plugin manifest
hooks/hooks.json Hook definitions, Claude Code/Codex schema (SessionStart, PreToolUse, PostToolUse)
hooks/gemini-hooks.json Gemini CLI hook definitions (SessionStart startup, BeforeTool, AfterTool) — separate because Claude's plugin loader rejects Gemini keys in hooks/hooks.json; Gemini only auto-loads hooks/hooks.json, so point/copy this file on Gemini install (upstream: google-gemini/gemini-cli#25630)
scripts/ Bash scripts executed by hooks (prereq-check, detect-manifest-edit, detect-install-cmd, auto-record)
commands/ Slash commands: /vs-record, /check-versions
skills/ Skills: version-sentinel, vs-record, check-versions
commands/ Slash commands: /vs-record, /check-versions (.md for Claude Code, .toml for Gemini CLI)
skills/ Skills: version-sentinel
agents/ Subagent: version-reviewer
kimi.plugin.json Kimi Code plugin manifest
platforms/kimi/ Kimi Code adapter
gemini-extension.json Gemini CLI extension manifest
GEMINI.md Gemini CLI auto-loaded context
.codex-plugin/ OpenAI Codex plugin metadata
.github/ GitHub Copilot hooks, agents, prompts
.agents/skills/ Cross-tool skills (Copilot, Zed, ...)
AGENTS.md Cross-tool agent instructions
tests/ Test suite
bin/ CLI entry points
docs/ Documentation
Expand Down
56 changes: 56 additions & 0 deletions GEMINI.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# version-sentinel (Gemini CLI extension)

This extension hard-blocks dependency additions, bumps, and downgrades until a
fresh, source-cited version check is recorded. It exists to stop the model from
shipping a hallucinated or stale package version remembered from training data.

## How it works

1. You try to edit a dependency manifest (`write_file` / `replace` on
`package.json`, `requirements*.txt`, `pyproject.toml`, `Cargo.toml`,
`*.csproj`, ...) or run an install command via `run_shell_command`
(`npm install`, `pip install`, `cargo add`, `dotnet add package`, ...).
2. A `BeforeTool` hook fires and exits 2 — the tool call is blocked and the
hook's stderr explains why:
```text
BLOCKED: version-sentinel.
Package: lodash (npm). Version: 4.17.21.
No fresh version check on record.
```
3. To unblock: look up the real latest version on the upstream registry
(npmjs.com, pypi.org, crates.io, nuget.org), then record the check:
```bash
/vs-record npm lodash 4.17.21 https://www.npmjs.com/package/lodash
```
Then retry the original edit or install — the hook finds the fresh entry
and lets it through.

## Intentional pins

Pinning an old version on purpose is fine — record it with a reason instead
of a URL:

```bash
/vs-record npm pkg 1.0.0 "intentional: CVE fix deferred pending audit"
```

Intentional pins unblock the hook and show as `intentional-pin` (not `DRIFT`)
in audits.

## Auditing drift

Run `/check-versions` to scan manifests within 4 directory levels of the workspace
and compare each pinned version against the latest upstream release. Advisory only
— never blocks.

## Escape hatch

Set `VS_DISABLE=1` in the environment to make every version-sentinel hook a
no-op (useful for throwaway sessions).

## Prerequisites

`bash`, `jq`, `curl`, and `python3` (3.11+, for `tomllib`) on `PATH`.

Recorded checks live in `<workspace>/.version-sentinel/checks.json`
(auto-gitignored on first write).
Loading