@guilz-dev/belay 0.1.0 → 0.1.1
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.
- package/README.md +43 -9
- package/dist/cli.js +11 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +2 -1
- package/package.json +4 -2
- package/skills/belay/SKILL.md +19 -5
package/README.md
CHANGED
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
|
|
9
9
|
[Documentation (日本語)](./docs/README.ja.md)
|
|
10
10
|
|
|
11
|
-
`@guilz-dev/belay` hooks into agent runtimes (Cursor, Claude Code) and
|
|
12
|
-
each shell command, subagent launch, and file mutation *before* it runs.
|
|
13
|
-
actions pass through untouched. Only the irreversible-and-catastrophic ones
|
|
14
|
-
held back for one-shot human approval — and every decision is written to an
|
|
11
|
+
`@guilz-dev/belay` hooks into agent runtimes (Cursor, Claude Code, Codex) and
|
|
12
|
+
inspects each shell command, subagent launch, and file mutation *before* it runs.
|
|
13
|
+
Most actions pass through untouched. Only the irreversible-and-catastrophic ones
|
|
14
|
+
are held back for one-shot human approval — and every decision is written to an
|
|
15
15
|
audit log.
|
|
16
16
|
|
|
17
17
|
<p align="center">
|
|
@@ -21,6 +21,30 @@ audit log.
|
|
|
21
21
|
> **0.0.x early release** — APIs and behavior may change. Cursor and Claude Code
|
|
22
22
|
> are the supported adapters; Codex is experimental.
|
|
23
23
|
|
|
24
|
+
## Supported agents
|
|
25
|
+
|
|
26
|
+
Belay works across three coding agents. Each one runs the **same classifier**,
|
|
27
|
+
wired in through that agent's native **hook** mechanism — no agent-specific
|
|
28
|
+
policy to maintain.
|
|
29
|
+
|
|
30
|
+
| Agent | Status | Hook config | belay config |
|
|
31
|
+
|-------|--------|-------------|--------------|
|
|
32
|
+
| **Cursor** | Supported | `.cursor/hooks.json` | `.cursor/belay.config.json` |
|
|
33
|
+
| **Claude Code** | Supported | `.claude/settings.json` | `.claude/belay.config.json` |
|
|
34
|
+
| **Codex** | Experimental | `.codex/config.toml` | `.codex/belay.config.json` |
|
|
35
|
+
|
|
36
|
+
Pick the adapter at install time with `--adapter cursor|claude|codex` (or let
|
|
37
|
+
`init-wizard` prompt). Hosts use different hook event names, but Belay registers
|
|
38
|
+
the same runners (`belay-tool-gate`, `belay-before-submit`, `belay-audit`) at
|
|
39
|
+
equivalent lifecycle points:
|
|
40
|
+
|
|
41
|
+
| Role | belay hook | Cursor | Claude Code | Codex |
|
|
42
|
+
|------|-----------|--------|-------------|-------|
|
|
43
|
+
| Gate shell / tools / file mutations | `belay-tool-gate` | `beforeShellExecution`, `preToolUse` | `PreToolUse` | `PreToolUse` |
|
|
44
|
+
| Gate subagent launches | `belay-tool-gate` | `subagentStart` | (via `PreToolUse`) | `SubagentStart` |
|
|
45
|
+
| One-shot approvals | `belay-before-submit` | `beforeSubmitPrompt` | `UserPromptSubmit` | `UserPromptSubmit` |
|
|
46
|
+
| Audit log | `belay-audit` | `postToolUse`, `stop`, `sessionEnd` | `PostToolUse` | `PostToolUse` |
|
|
47
|
+
|
|
24
48
|
## Why
|
|
25
49
|
|
|
26
50
|
Static denylists don't work for agents. The same command (`rm`, `curl`, a
|
|
@@ -48,6 +72,7 @@ npx @guilz-dev/belay init-wizard
|
|
|
48
72
|
|
|
49
73
|
# Or non-interactive
|
|
50
74
|
npx @guilz-dev/belay init --adapter claude # Claude Code
|
|
75
|
+
npx @guilz-dev/belay init --adapter codex # Codex (experimental)
|
|
51
76
|
npx @guilz-dev/belay init # Cursor (default)
|
|
52
77
|
```
|
|
53
78
|
|
|
@@ -64,10 +89,10 @@ verdict and `overrides.allow` to whitelist commands you trust.
|
|
|
64
89
|
|
|
65
90
|
## How it works
|
|
66
91
|
|
|
67
|
-
Belay registers hooks on the host runtime (`.cursor/hooks.json
|
|
68
|
-
`.claude/settings.json`) and gates shell execution,
|
|
69
|
-
mutations through one shared classifier. It always
|
|
70
|
-
does not trust an assessment supplied by the agent.
|
|
92
|
+
Belay registers hooks on the host runtime (`.cursor/hooks.json`,
|
|
93
|
+
`.claude/settings.json`, or `.codex/config.toml`) and gates shell execution,
|
|
94
|
+
subagent launches, and file mutations through one shared classifier. It always
|
|
95
|
+
forms its own judgment — it does not trust an assessment supplied by the agent.
|
|
71
96
|
|
|
72
97
|
Every gated action gets one of three verdicts:
|
|
73
98
|
|
|
@@ -84,7 +109,8 @@ When an action is denied, approve the **next matching action once** by sending:
|
|
|
84
109
|
```
|
|
85
110
|
|
|
86
111
|
Approvals are one-shot and expire after 15 minutes by default. Every decision is
|
|
87
|
-
written to `.cursor/belay/audit.ndjson
|
|
112
|
+
written to `.cursor/belay/audit.ndjson`, `.claude/belay/audit.ndjson`, or
|
|
113
|
+
`.codex/belay/audit.ndjson` (depending on the adapter).
|
|
88
114
|
|
|
89
115
|
In **audit mode** (`mode: "audit"`), would-be denials are recorded
|
|
90
116
|
(`wouldBlock: true`) but execution still continues, and no approval IDs are
|
|
@@ -247,6 +273,14 @@ Belay state files are local runtime artifacts and should usually stay out of git
|
|
|
247
273
|
.cursor/hooks/belay-*
|
|
248
274
|
.cursor/skills/belay/
|
|
249
275
|
.cursor/commands/belay-approve.md
|
|
276
|
+
|
|
277
|
+
.claude/belay/
|
|
278
|
+
.claude/belay.config.json
|
|
279
|
+
.claude/hooks/belay-*
|
|
280
|
+
|
|
281
|
+
.codex/belay/
|
|
282
|
+
.codex/belay.config.json
|
|
283
|
+
.codex/hooks/belay-*
|
|
250
284
|
```
|
|
251
285
|
|
|
252
286
|
## Library exports
|
package/dist/cli.js
CHANGED
|
@@ -16,9 +16,16 @@ import { loadConfigFile } from './config-io.js';
|
|
|
16
16
|
import { initProject, upgradeProject } from './installer.js';
|
|
17
17
|
import { egressEnv, egressStatus, formatEgressStatusReport, startEgressProxy, stopEgressProxy, } from './services/egress-service.js';
|
|
18
18
|
import { formatSandboxStatusReport, sandboxStatus } from './services/sandbox-service.js';
|
|
19
|
+
import { PACKAGE_VERSION } from './version.js';
|
|
19
20
|
function parseArgs(argv) {
|
|
20
21
|
const [command, ...rest] = argv;
|
|
21
22
|
const options = {};
|
|
23
|
+
if (!command || command === '--help' || command === '-h') {
|
|
24
|
+
return { command: 'help', options };
|
|
25
|
+
}
|
|
26
|
+
if (command === '--version' || command === '-V') {
|
|
27
|
+
return { command: 'version', options };
|
|
28
|
+
}
|
|
22
29
|
for (let index = 0; index < rest.length; index += 1) {
|
|
23
30
|
const token = rest[index];
|
|
24
31
|
if (token === '--with-skill') {
|
|
@@ -349,6 +356,10 @@ async function main() {
|
|
|
349
356
|
printHelp();
|
|
350
357
|
return;
|
|
351
358
|
}
|
|
359
|
+
if (command === 'version') {
|
|
360
|
+
process.stdout.write(`${PACKAGE_VERSION}\n`);
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
352
363
|
if (command === 'init-wizard') {
|
|
353
364
|
const { runInitWizard } = await import('./commands/init-wizard.js');
|
|
354
365
|
const result = await runInitWizard({ targetDir: options.targetDir });
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const PACKAGE_VERSION = "0.
|
|
1
|
+
export declare const PACKAGE_VERSION = "0.1.1";
|
package/dist/version.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
// Generated by scripts/sync-version.mjs — do not edit.
|
|
2
|
+
export const PACKAGE_VERSION = '0.1.1';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@guilz-dev/belay",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Belay-style approval and audit gating for agent runtimes.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -48,7 +48,9 @@
|
|
|
48
48
|
"agent-belay-logo.png"
|
|
49
49
|
],
|
|
50
50
|
"scripts": {
|
|
51
|
-
"build": "rm -rf dist && tsc -p tsconfig.build.json && node scripts/build-runtime.mjs",
|
|
51
|
+
"build": "rm -rf dist && node scripts/sync-version.mjs && tsc -p tsconfig.build.json && node scripts/build-runtime.mjs",
|
|
52
|
+
"check:version": "node scripts/check-cli-version.mjs",
|
|
53
|
+
"prepublishOnly": "pnpm build && node scripts/check-cli-version.mjs",
|
|
52
54
|
"lint": "biome check src package.json README.md CHANGELOG.md CONTRIBUTING.md SECURITY.md tsconfig.json tsconfig.build.json vitest.config.ts scripts docs",
|
|
53
55
|
"typecheck": "tsc --noEmit",
|
|
54
56
|
"test": "pnpm build && vitest run",
|
package/skills/belay/SKILL.md
CHANGED
|
@@ -2,16 +2,30 @@
|
|
|
2
2
|
name: belay
|
|
3
3
|
description: >-
|
|
4
4
|
Guides approval when belay blocks a high-risk shell command, subagent launch,
|
|
5
|
-
or tool action. Use when an action is
|
|
6
|
-
|
|
5
|
+
or tool action across Cursor, Claude Code, and Codex. Use when an action is
|
|
6
|
+
denied, blocked, or needs belay-approve, or when installing or checking belay
|
|
7
|
+
hook health in a repository.
|
|
7
8
|
disable-model-invocation: true
|
|
8
9
|
---
|
|
9
10
|
|
|
10
11
|
# Belay
|
|
11
12
|
|
|
12
|
-
Belay
|
|
13
|
-
subagent
|
|
14
|
-
|
|
13
|
+
Belay is a safety gate for coding agents: it inspects each shell command,
|
|
14
|
+
subagent launch, and file mutation *before* it runs, lets safe-and-local actions
|
|
15
|
+
through, and holds back only the irreversible-and-catastrophic ones for one-shot
|
|
16
|
+
human approval. Every decision is written to an audit log.
|
|
17
|
+
|
|
18
|
+
It runs on **Cursor**, **Claude Code**, and **Codex (experimental)**, wiring the
|
|
19
|
+
same classifier into each agent through its native hooks:
|
|
20
|
+
|
|
21
|
+
| Agent | Hook config |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| Cursor | `.cursor/hooks.json` |
|
|
24
|
+
| Claude Code | `.claude/settings.json` |
|
|
25
|
+
| Codex | `.codex/config.toml` |
|
|
26
|
+
|
|
27
|
+
Enforcement lives in those hooks; this skill only explains the flow and routes
|
|
28
|
+
you to the CLI. It does not classify commands itself.
|
|
15
29
|
|
|
16
30
|
## Prerequisites
|
|
17
31
|
|