failproofai 0.0.2-beta.1 → 0.0.2-beta.3
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/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +2 -2
- package/.next/standalone/.next/server/app/_not-found.rsc +17 -17
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +17 -17
- package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +11 -11
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +16 -16
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +16 -16
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +11 -11
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +8 -8
- package/.next/standalone/.next/server/app/policies/page.js +1 -1
- package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__02nt~6d._.js +1 -1
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_0z7w.hh._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0a3kr67._.js → [root-of-the-server]__07k6eu-._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__092s1ta._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__09icjsf._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0g.lg8b._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h..k-e._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0rbuarm._.js → [root-of-the-server]__0kfv9fw._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0osi8nq._.js → [root-of-the-server]__0okos0k._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0w6l33k._.js +5 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11pa2ra._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__12t-wym._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_10lm7or._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_0xerkr6._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_0q-m0y-._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_0rd0oc-._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/pages/404.html +2 -2
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +9 -9
- package/.next/standalone/.next/static/chunks/{0a08gn8709y98.js → 0.jo.465b6_k..js} +1 -1
- package/.next/standalone/.next/static/chunks/{0jhw8ofx.5g_e.js → 01haq0a3zrx0v.js} +1 -1
- package/.next/standalone/.next/static/chunks/08f78tecvx61l.css +1 -0
- package/.next/standalone/.next/static/chunks/{0mr-jhx402yci.js → 0a6xi1a8f_qlp.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0qvj8bhl661lq.js → 0mq7ze1vkeo1p.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0gcz-jqgqz~9m.js → 0p_fpyfmmohnx.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0kob_5.phc~sk.js → 0qwyj3m400l_g.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0mjc3aq2wxvlt.js → 0t94r_mk0s7e4.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0q7z97izctgrw.js → 139~00zc9.u7s.js} +1 -1
- package/.next/standalone/Dockerfile.docs +12 -0
- package/.next/standalone/README.md +68 -55
- package/.next/standalone/bin/failproofai.mjs +221 -128
- package/.next/standalone/dist/cli.mjs +415 -106
- package/.next/standalone/dist/index.js +2 -2
- package/.next/standalone/docs/{architecture.md → architecture.mdx} +40 -23
- package/.next/standalone/docs/{built-in-policies.md → built-in-policies.mdx} +134 -12
- package/.next/standalone/docs/cli/dashboard.mdx +28 -0
- package/.next/standalone/docs/cli/environment-variables.mdx +34 -0
- package/.next/standalone/docs/cli/hook.mdx +30 -0
- package/.next/standalone/docs/cli/install-policies.mdx +48 -0
- package/.next/standalone/docs/cli/list-policies.mdx +31 -0
- package/.next/standalone/docs/cli/remove-policies.mdx +44 -0
- package/.next/standalone/docs/cli/version.mdx +12 -0
- package/.next/standalone/docs/{configuration.md → configuration.mdx} +16 -16
- package/.next/standalone/docs/{custom-hooks.md → custom-policies.mdx} +80 -42
- package/.next/standalone/docs/{dashboard.md → dashboard.mdx} +26 -29
- package/.next/standalone/docs/docs.json +31 -4
- package/.next/standalone/docs/examples.mdx +253 -0
- package/.next/standalone/docs/for-agents.mdx +38 -0
- package/.next/standalone/docs/getting-started.mdx +134 -0
- package/.next/standalone/docs/introduction.mdx +57 -0
- package/.next/standalone/docs/logo/dark.svg +21 -0
- package/.next/standalone/docs/logo/light.svg +21 -0
- package/.next/standalone/docs/{package-aliases.md → package-aliases.mdx} +5 -5
- package/.next/standalone/docs/{testing.md → testing.mdx} +11 -11
- package/.next/standalone/package.json +6 -9
- package/.next/standalone/scripts/publish-aliases.mjs +4 -2
- package/.next/standalone/skills-lock.json +10 -0
- package/.next/standalone/src/cli-error.ts +18 -0
- package/.next/standalone/src/hooks/builtin-policies.ts +259 -20
- package/.next/standalone/src/hooks/manager.ts +17 -3
- package/.next/standalone/src/hooks/policy-evaluator.ts +19 -1
- package/.next/standalone/src/hooks/policy-helpers.ts +2 -2
- package/.next/standalone/vitest.config.e2e.mts +3 -0
- package/.next/standalone/vitest.config.mts +3 -0
- package/README.md +68 -55
- package/bin/failproofai.mjs +221 -128
- package/dist/cli.mjs +415 -106
- package/dist/index.js +2 -2
- package/package.json +6 -9
- package/scripts/publish-aliases.mjs +4 -2
- package/src/cli-error.ts +18 -0
- package/src/hooks/builtin-policies.ts +259 -20
- package/src/hooks/manager.ts +17 -3
- package/src/hooks/policy-evaluator.ts +19 -1
- package/src/hooks/policy-helpers.ts +2 -2
- package/.next/standalone/.next/static/chunks/15jpradyu_531.css +0 -1
- package/.next/standalone/docs/cli-reference.md +0 -175
- package/.next/standalone/docs/getting-started.md +0 -128
- package/.next/standalone/docs/introduction.md +0 -47
- /package/.next/standalone/.next/static/{Dnk96sbMPjYOx1pdLdOH0 → 7fR022u1Sj-s5MfKO1q9Y}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{Dnk96sbMPjYOx1pdLdOH0 → 7fR022u1Sj-s5MfKO1q9Y}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{Dnk96sbMPjYOx1pdLdOH0 → 7fR022u1Sj-s5MfKO1q9Y}/_ssgManifest.js +0 -0
|
@@ -4,7 +4,7 @@ description: "Config file format, three-scope system, and merge rules"
|
|
|
4
4
|
icon: gear
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
failproofai uses JSON configuration files to control which policies are active, how they behave, and where custom
|
|
7
|
+
failproofai uses JSON configuration files to control which policies are active, how they behave, and where custom policies are loaded from. Configuration is designed to be easy to share with your team - commit it to your repo and every developer gets the same agent safety net.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -22,9 +22,9 @@ When failproofai receives a hook event, it loads and merges all three files that
|
|
|
22
22
|
|
|
23
23
|
### Merge rules
|
|
24
24
|
|
|
25
|
-
**`enabledPolicies`**
|
|
25
|
+
**`enabledPolicies`** - the union of all three scopes. A policy enabled at any level is active.
|
|
26
26
|
|
|
27
|
-
```
|
|
27
|
+
```text
|
|
28
28
|
project: ["block-sudo"]
|
|
29
29
|
local: ["block-rm-rf"]
|
|
30
30
|
global: ["block-sudo", "sanitize-api-keys"]
|
|
@@ -32,16 +32,16 @@ global: ["block-sudo", "sanitize-api-keys"]
|
|
|
32
32
|
resolved: ["block-sudo", "block-rm-rf", "sanitize-api-keys"] ← deduplicated union
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
**`policyParams`**
|
|
35
|
+
**`policyParams`** - first scope that defines params for a given policy wins entirely. There is no deep merging of values within a policy's params.
|
|
36
36
|
|
|
37
|
-
```
|
|
37
|
+
```text
|
|
38
38
|
project: block-sudo → { allowPatterns: ["sudo apt-get update"] }
|
|
39
39
|
global: block-sudo → { allowPatterns: ["sudo systemctl status"] }
|
|
40
40
|
|
|
41
41
|
resolved: { allowPatterns: ["sudo apt-get update"] } ← project wins, global ignored
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
```
|
|
44
|
+
```text
|
|
45
45
|
project: (no block-sudo entry)
|
|
46
46
|
local: (no block-sudo entry)
|
|
47
47
|
global: block-sudo → { allowPatterns: ["sudo systemctl status"] }
|
|
@@ -49,9 +49,9 @@ global: block-sudo → { allowPatterns: ["sudo systemctl status"] }
|
|
|
49
49
|
resolved: { allowPatterns: ["sudo systemctl status"] } ← falls through to global
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
**`customPoliciesPath`**
|
|
52
|
+
**`customPoliciesPath`** - first scope that defines it wins.
|
|
53
53
|
|
|
54
|
-
**`llm`**
|
|
54
|
+
**`llm`** - first scope that defines it wins.
|
|
55
55
|
|
|
56
56
|
---
|
|
57
57
|
|
|
@@ -102,7 +102,7 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← falls through to glo
|
|
|
102
102
|
|
|
103
103
|
Type: `string[]`
|
|
104
104
|
|
|
105
|
-
List of policy names to enable. Names must match exactly the policy identifiers shown
|
|
105
|
+
List of policy names to enable. Names must match exactly the policy identifiers shown by `failproofai policies`. See [Built-in Policies](/built-in-policies) for the full list.
|
|
106
106
|
|
|
107
107
|
Policies not in `enabledPolicies` are inactive, even if they have entries in `policyParams`.
|
|
108
108
|
|
|
@@ -110,19 +110,19 @@ Policies not in `enabledPolicies` are inactive, even if they have entries in `po
|
|
|
110
110
|
|
|
111
111
|
Type: `Record<string, Record<string, unknown>>`
|
|
112
112
|
|
|
113
|
-
Per-policy parameter overrides. The outer key is the policy name; the inner keys are policy-specific. Each policy documents its available parameters in [Built-in Policies](
|
|
113
|
+
Per-policy parameter overrides. The outer key is the policy name; the inner keys are policy-specific. Each policy documents its available parameters in [Built-in Policies](/built-in-policies).
|
|
114
114
|
|
|
115
115
|
If a policy has parameters but you don't specify them, the policy's built-in defaults are used. Users who do not configure `policyParams` at all get identical behavior to previous versions.
|
|
116
116
|
|
|
117
|
-
Unknown keys inside a policy's params block are silently ignored at hook-fire time but flagged as warnings when you run `failproofai
|
|
117
|
+
Unknown keys inside a policy's params block are silently ignored at hook-fire time but flagged as warnings when you run `failproofai policies`.
|
|
118
118
|
|
|
119
119
|
### `customPoliciesPath`
|
|
120
120
|
|
|
121
121
|
Type: `string` (absolute path)
|
|
122
122
|
|
|
123
|
-
Path to a JavaScript file containing custom hook policies. This is set automatically by `failproofai --install
|
|
123
|
+
Path to a JavaScript file containing custom hook policies. This is set automatically by `failproofai policies --install --custom <path>` (the path is resolved to absolute before being stored).
|
|
124
124
|
|
|
125
|
-
The file is loaded fresh on every hook event
|
|
125
|
+
The file is loaded fresh on every hook event - there is no caching. See [Custom Policies](/custom-policies) for authoring details.
|
|
126
126
|
|
|
127
127
|
### `llm`
|
|
128
128
|
|
|
@@ -143,10 +143,10 @@ LLM client configuration for policies that make AI calls. Not required for most
|
|
|
143
143
|
|
|
144
144
|
## Managing configuration from the CLI
|
|
145
145
|
|
|
146
|
-
The
|
|
146
|
+
The `policies --install` and `policies --uninstall` commands write to Claude Code's `settings.json` (the hook entry points), while `policies-config.json` is the file you manage directly. The two are separate:
|
|
147
147
|
|
|
148
|
-
- **`settings.json`**
|
|
149
|
-
- **`policies-config.json`**
|
|
148
|
+
- **`settings.json`** - tells Claude Code to call `failproofai --hook <event>` on each tool use
|
|
149
|
+
- **`policies-config.json`** - tells failproofai which policies to evaluate and with what params
|
|
150
150
|
|
|
151
151
|
You can edit `policies-config.json` directly at any time; changes take effect immediately on the next hook event with no restart needed.
|
|
152
152
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: Custom
|
|
3
|
-
description: "Write your own policies in JavaScript
|
|
2
|
+
title: Custom Policies
|
|
3
|
+
description: "Write your own policies in JavaScript - enforce conventions, prevent drift, detect failures, integrate with external systems"
|
|
4
4
|
icon: code
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
Custom
|
|
7
|
+
Custom policies let you write rules for any agent behavior: enforce project conventions, prevent drift, gate destructive operations, detect stuck agents, or integrate with Slack, approval workflows, and more. They use the same hook event system and `allow`, `deny`, `instruct` decisions as built-in policies.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -32,7 +32,7 @@ customPolicies.add({
|
|
|
32
32
|
Install it:
|
|
33
33
|
|
|
34
34
|
```bash
|
|
35
|
-
failproofai --install
|
|
35
|
+
failproofai policies --install --custom ./my-policies.js
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
---
|
|
@@ -40,17 +40,17 @@ failproofai --install-policies --custom ./my-policies.js
|
|
|
40
40
|
## Installing and updating
|
|
41
41
|
|
|
42
42
|
```bash
|
|
43
|
-
# Install with a custom
|
|
44
|
-
failproofai --install
|
|
43
|
+
# Install with a custom policies file
|
|
44
|
+
failproofai policies --install --custom ./my-policies.js
|
|
45
45
|
|
|
46
|
-
# Replace the
|
|
47
|
-
failproofai --install
|
|
46
|
+
# Replace the policies file path
|
|
47
|
+
failproofai policies --install --custom ./new-policies.js
|
|
48
48
|
|
|
49
|
-
# Remove the custom
|
|
50
|
-
failproofai
|
|
49
|
+
# Remove the custom policies path from config
|
|
50
|
+
failproofai policies --uninstall --custom
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
The resolved absolute path is stored in `policies-config.json` as `customPoliciesPath`. The file is loaded fresh on every hook event
|
|
53
|
+
The resolved absolute path is stored in `policies-config.json` as `customPoliciesPath`. The file is loaded fresh on every hook event - there is no caching between events.
|
|
54
54
|
|
|
55
55
|
---
|
|
56
56
|
|
|
@@ -64,12 +64,12 @@ import { customPolicies, allow, deny, instruct } from "failproofai";
|
|
|
64
64
|
|
|
65
65
|
### `customPolicies.add(hook)`
|
|
66
66
|
|
|
67
|
-
Registers a
|
|
67
|
+
Registers a policy. Call this as many times as needed for multiple policies in the same file.
|
|
68
68
|
|
|
69
69
|
```ts
|
|
70
70
|
customPolicies.add({
|
|
71
|
-
name: string; // required
|
|
72
|
-
description?: string; // shown in
|
|
71
|
+
name: string; // required - unique identifier
|
|
72
|
+
description?: string; // shown in `failproofai policies` output
|
|
73
73
|
match?: { events?: HookEventType[] }; // filter by event type; omit to match all
|
|
74
74
|
fn: (ctx: PolicyContext) => PolicyResult | Promise<PolicyResult>;
|
|
75
75
|
});
|
|
@@ -79,13 +79,47 @@ customPolicies.add({
|
|
|
79
79
|
|
|
80
80
|
| Function | Effect | Use when |
|
|
81
81
|
|----------|--------|----------|
|
|
82
|
-
| `allow()` | Permit the
|
|
83
|
-
| `deny(message)` | Block the
|
|
84
|
-
| `instruct(message)` | Add context
|
|
82
|
+
| `allow()` | Permit the operation silently | The action is safe, no message needed |
|
|
83
|
+
| `deny(message)` | Block the operation | The agent should not take this action |
|
|
84
|
+
| `instruct(message)` | Add context without blocking | Give the agent extra context to stay on track |
|
|
85
85
|
|
|
86
|
-
`deny(message)`
|
|
86
|
+
`deny(message)` - the message appears to Claude prefixed with `"Blocked by failproofai:"`. A single `deny` short-circuits all further evaluation.
|
|
87
87
|
|
|
88
|
-
`instruct(message)`
|
|
88
|
+
`instruct(message)` - the message is appended to Claude's context for the current tool call. The first `instruct` wins — subsequent `instruct` returns from other policies are ignored.
|
|
89
|
+
|
|
90
|
+
### Informational allow messages (beta)
|
|
91
|
+
|
|
92
|
+
<Note>
|
|
93
|
+
`allow(message)` is a beta feature available since v0.0.2-beta.3. The API may change in future releases. Earlier versions only support `allow()` without arguments.
|
|
94
|
+
</Note>
|
|
95
|
+
|
|
96
|
+
`allow(message)` permits the operation **and** sends an informational message back to Claude. The message is delivered as `additionalContext` in the hook handler's stdout response — the same mechanism used by `instruct`, but semantically different: it's a status update, not a warning.
|
|
97
|
+
|
|
98
|
+
| Function | Effect | Use when |
|
|
99
|
+
|----------|--------|----------|
|
|
100
|
+
| `allow(message)` | Permit and send context to Claude | Confirm a check passed, or explain why a check was skipped |
|
|
101
|
+
|
|
102
|
+
Use cases:
|
|
103
|
+
- **Status confirmations:** `allow("All CI checks passed.")` — tells Claude everything is green
|
|
104
|
+
- **Fail-open explanations:** `allow("GitHub CLI not installed, skipping CI check.")` — tells Claude why a check was skipped so it has full context
|
|
105
|
+
- **Multiple messages accumulate:** if several policies each return `allow(message)`, all messages are joined with newlines and delivered together
|
|
106
|
+
|
|
107
|
+
```js
|
|
108
|
+
customPolicies.add({
|
|
109
|
+
name: "confirm-branch-status",
|
|
110
|
+
match: { events: ["Stop"] },
|
|
111
|
+
fn: async (ctx) => {
|
|
112
|
+
const cwd = ctx.session?.cwd;
|
|
113
|
+
if (!cwd) return allow("No working directory, skipping branch check.");
|
|
114
|
+
|
|
115
|
+
// ... check branch status ...
|
|
116
|
+
if (allPushed) {
|
|
117
|
+
return allow("Branch is up to date with remote.");
|
|
118
|
+
}
|
|
119
|
+
return deny("Unpushed changes detected.");
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
```
|
|
89
123
|
|
|
90
124
|
### `PolicyContext` fields
|
|
91
125
|
|
|
@@ -111,25 +145,27 @@ customPolicies.add({
|
|
|
111
145
|
|-------|--------------|----------------------|
|
|
112
146
|
| `PreToolUse` | Before Claude runs a tool | The tool's input (e.g. `{ command: "..." }` for Bash) |
|
|
113
147
|
| `PostToolUse` | After a tool completes | The tool's input + `tool_result` (the output) |
|
|
114
|
-
| `Notification` | When Claude sends a notification | `{ message: "...", notification_type: "idle" \| "permission_prompt" \| ... }`
|
|
148
|
+
| `Notification` | When Claude sends a notification | `{ message: "...", notification_type: "idle" \| "permission_prompt" \| ... }` - hooks must always return `allow()`, they cannot block notifications |
|
|
115
149
|
| `Stop` | When the Claude session ends | Empty |
|
|
116
150
|
|
|
117
151
|
---
|
|
118
152
|
|
|
119
153
|
## Evaluation order
|
|
120
154
|
|
|
121
|
-
|
|
155
|
+
Policies are evaluated in this order:
|
|
122
156
|
|
|
123
157
|
1. Built-in policies (in definition order)
|
|
124
|
-
2. Custom
|
|
158
|
+
2. Custom policies (in `.add()` order)
|
|
125
159
|
|
|
126
|
-
|
|
160
|
+
<Note>
|
|
161
|
+
The first `deny` short-circuits all subsequent policies. The first `instruct` wins — subsequent `instruct` returns are ignored.
|
|
162
|
+
</Note>
|
|
127
163
|
|
|
128
164
|
---
|
|
129
165
|
|
|
130
166
|
## Transitive imports
|
|
131
167
|
|
|
132
|
-
Custom
|
|
168
|
+
Custom policy files can import local modules using relative paths:
|
|
133
169
|
|
|
134
170
|
```js
|
|
135
171
|
// my-policies.js
|
|
@@ -150,9 +186,9 @@ All relative imports reachable from the entry file are resolved. This is impleme
|
|
|
150
186
|
|
|
151
187
|
---
|
|
152
188
|
|
|
153
|
-
##
|
|
189
|
+
## Event type filtering
|
|
154
190
|
|
|
155
|
-
Use `match.events` to limit when a
|
|
191
|
+
Use `match.events` to limit when a policy fires:
|
|
156
192
|
|
|
157
193
|
```js
|
|
158
194
|
customPolicies.add({
|
|
@@ -172,34 +208,36 @@ Omit `match` entirely to fire on every event type.
|
|
|
172
208
|
|
|
173
209
|
## Error handling and failure modes
|
|
174
210
|
|
|
175
|
-
Custom
|
|
211
|
+
Custom policies are **fail-open**: errors never block built-in policies or crash the hook handler.
|
|
176
212
|
|
|
177
213
|
| Failure | Behavior |
|
|
178
214
|
|---------|----------|
|
|
179
|
-
| `customPoliciesPath` not set | No custom
|
|
215
|
+
| `customPoliciesPath` not set | No custom policies run; built-ins continue normally |
|
|
180
216
|
| File not found | Warning logged to `~/.failproofai/hook.log`; built-ins continue |
|
|
181
|
-
| Syntax/import error | Error logged to `~/.failproofai/hook.log`; all custom
|
|
217
|
+
| Syntax/import error | Error logged to `~/.failproofai/hook.log`; all custom policies skipped |
|
|
182
218
|
| `fn` throws at runtime | Error logged; that hook treated as `allow`; other hooks continue |
|
|
183
219
|
| `fn` takes longer than 10s | Timeout logged; treated as `allow` |
|
|
184
220
|
|
|
185
|
-
|
|
221
|
+
<Tip>
|
|
222
|
+
To debug custom policy errors, watch the log file:
|
|
186
223
|
|
|
187
224
|
```bash
|
|
188
225
|
tail -f ~/.failproofai/hook.log
|
|
189
226
|
```
|
|
227
|
+
</Tip>
|
|
190
228
|
|
|
191
229
|
---
|
|
192
230
|
|
|
193
|
-
## Full example: multiple
|
|
231
|
+
## Full example: multiple policies
|
|
194
232
|
|
|
195
233
|
```js
|
|
196
234
|
// my-policies.js
|
|
197
235
|
import { customPolicies, allow, deny, instruct } from "failproofai";
|
|
198
236
|
|
|
199
|
-
//
|
|
237
|
+
// Prevent agent from writing to secrets/ directory
|
|
200
238
|
customPolicies.add({
|
|
201
239
|
name: "block-secrets-dir",
|
|
202
|
-
description: "
|
|
240
|
+
description: "Prevent agent from writing to secrets/ directory",
|
|
203
241
|
match: { events: ["PreToolUse"] },
|
|
204
242
|
fn: async (ctx) => {
|
|
205
243
|
if (!["Write", "Edit"].includes(ctx.toolName ?? "")) return allow();
|
|
@@ -209,10 +247,10 @@ customPolicies.add({
|
|
|
209
247
|
},
|
|
210
248
|
});
|
|
211
249
|
|
|
212
|
-
//
|
|
250
|
+
// Keep the agent on track: verify tests before committing
|
|
213
251
|
customPolicies.add({
|
|
214
252
|
name: "remind-test-before-commit",
|
|
215
|
-
description: "
|
|
253
|
+
description: "Keep the agent on track: verify tests pass before committing",
|
|
216
254
|
match: { events: ["PreToolUse"] },
|
|
217
255
|
fn: async (ctx) => {
|
|
218
256
|
if (ctx.toolName !== "Bash") return allow();
|
|
@@ -224,10 +262,10 @@ customPolicies.add({
|
|
|
224
262
|
},
|
|
225
263
|
});
|
|
226
264
|
|
|
227
|
-
//
|
|
265
|
+
// Prevent unplanned dependency changes during freeze
|
|
228
266
|
customPolicies.add({
|
|
229
267
|
name: "dependency-freeze",
|
|
230
|
-
description: "
|
|
268
|
+
description: "Prevent unplanned dependency changes during freeze period",
|
|
231
269
|
match: { events: ["PreToolUse"] },
|
|
232
270
|
fn: async (ctx) => {
|
|
233
271
|
if (ctx.toolName !== "Bash") return allow();
|
|
@@ -245,17 +283,17 @@ export { customPolicies };
|
|
|
245
283
|
|
|
246
284
|
---
|
|
247
285
|
|
|
248
|
-
## Examples
|
|
286
|
+
## Examples
|
|
249
287
|
|
|
250
|
-
The `examples/` directory contains ready-to-run
|
|
288
|
+
The `examples/` directory contains ready-to-run policy files:
|
|
251
289
|
|
|
252
290
|
| File | Contents |
|
|
253
291
|
|------|----------|
|
|
254
|
-
| `examples/policies-basic.js` | Five starter policies covering common
|
|
255
|
-
| `examples/policies-advanced/index.js` | Advanced patterns
|
|
292
|
+
| `examples/policies-basic.js` | Five starter policies covering common agent failure modes |
|
|
293
|
+
| `examples/policies-advanced/index.js` | Advanced patterns: transitive imports, async calls, output scrubbing, and session-end hooks |
|
|
256
294
|
|
|
257
295
|
Install the basic examples:
|
|
258
296
|
|
|
259
297
|
```bash
|
|
260
|
-
failproofai --install
|
|
298
|
+
failproofai policies --install --custom ./examples/policies-basic.js
|
|
261
299
|
```
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Dashboard
|
|
3
|
-
description: "
|
|
3
|
+
description: "Monitor agent sessions, review tool calls, and manage policies"
|
|
4
4
|
icon: chart-line
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
The failproofai dashboard is a local web application for
|
|
7
|
+
The failproofai dashboard is a local web application for monitoring your AI agent sessions and managing policies. See what your agents did while you were away.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -16,13 +16,7 @@ failproofai
|
|
|
16
16
|
|
|
17
17
|
Opens at `http://localhost:8020`.
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
failproofai --start
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
The dashboard reads directly from the filesystem — your Claude Code project folders and the failproofai config files. Nothing is written to a remote service.
|
|
19
|
+
The dashboard reads directly from the filesystem - your Claude Code project folders and the failproofai config files. Nothing is written to a remote service.
|
|
26
20
|
|
|
27
21
|
---
|
|
28
22
|
|
|
@@ -53,11 +47,11 @@ Click a session to open the session viewer.
|
|
|
53
47
|
|
|
54
48
|
### Session viewer
|
|
55
49
|
|
|
56
|
-
|
|
50
|
+
The session viewer answers the key question for autonomous agents: what did the agent do, and did it stay on track? It shows a timeline of everything that happened in a session:
|
|
57
51
|
|
|
58
|
-
- **Messages**
|
|
59
|
-
- **Tool calls**
|
|
60
|
-
- **
|
|
52
|
+
- **Messages** - Claude's text responses and user prompts
|
|
53
|
+
- **Tool calls** - Every tool Claude invoked, with its input and output
|
|
54
|
+
- **Policy activity** - For each tool call, which policies fired and what decision they returned
|
|
61
55
|
|
|
62
56
|
The stats bar at the top shows session duration, total tool calls, and a summary of hook decisions (allow / deny / instruct counts).
|
|
63
57
|
|
|
@@ -67,24 +61,25 @@ You can export the session as a ZIP or JSONL file using the download button.
|
|
|
67
61
|
|
|
68
62
|
A two-tab page for managing policies and reviewing activity.
|
|
69
63
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
- Toggle individual policies on or off with a single click (writes to `~/.failproofai/policies-config.json`)
|
|
73
|
-
- Expand a policy to configure its parameters (for policies that support `policyParams`)
|
|
74
|
-
- Install or remove hooks for a given scope
|
|
75
|
-
- Set a custom
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
-
|
|
80
|
-
-
|
|
81
|
-
|
|
64
|
+
<Tabs>
|
|
65
|
+
<Tab title="Policies tab">
|
|
66
|
+
- Toggle individual policies on or off with a single click (writes to `~/.failproofai/policies-config.json`)
|
|
67
|
+
- Expand a policy to configure its parameters (for policies that support `policyParams`)
|
|
68
|
+
- Install or remove hooks for a given scope
|
|
69
|
+
- Set a custom policies file path
|
|
70
|
+
</Tab>
|
|
71
|
+
<Tab title="Activity tab">
|
|
72
|
+
- Full paginated history of every hook event that has fired across all sessions
|
|
73
|
+
- Search by policy name, session ID, tool name, or decision
|
|
74
|
+
- Each row shows: timestamp, policy name, decision, tool name, session ID, and the reason for deny/instruct decisions
|
|
75
|
+
</Tab>
|
|
76
|
+
</Tabs>
|
|
82
77
|
|
|
83
78
|
---
|
|
84
79
|
|
|
85
80
|
## Auto-refresh
|
|
86
81
|
|
|
87
|
-
The dashboard has an auto-refresh toggle in the top navigation. When enabled, the current page refreshes periodically to show new sessions and
|
|
82
|
+
The dashboard has an auto-refresh toggle in the top navigation. When enabled, the current page refreshes periodically to show new sessions and policy activity as they appear. Essential for monitoring long-running autonomous agent sessions.
|
|
88
83
|
|
|
89
84
|
---
|
|
90
85
|
|
|
@@ -118,9 +113,9 @@ CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai
|
|
|
118
113
|
|
|
119
114
|
## Accessing from a non-localhost host
|
|
120
115
|
|
|
121
|
-
When running the dashboard in **dev mode** (`npm run dev`) and accessing it from a hostname other than `localhost`
|
|
116
|
+
When running the dashboard in **dev mode** (`npm run dev`) and accessing it from a hostname other than `localhost` - for example, a custom domain, a remote IP, or a tunneled URL - you may see a warning like:
|
|
122
117
|
|
|
123
|
-
```
|
|
118
|
+
```text
|
|
124
119
|
⚠ Blocked cross-origin request to Next.js dev resource /_next/webpack-hmr from "dashboard.example.com".
|
|
125
120
|
```
|
|
126
121
|
|
|
@@ -142,4 +137,6 @@ You can also set the `FAILPROOFAI_ALLOWED_DEV_ORIGINS` environment variable inst
|
|
|
142
137
|
FAILPROOFAI_ALLOWED_DEV_ORIGINS=dashboard.example.com npm run dev
|
|
143
138
|
```
|
|
144
139
|
|
|
145
|
-
>
|
|
140
|
+
<Note>
|
|
141
|
+
This only applies to dev mode. When running `failproofai` (production mode), there is no HMR websocket and no cross-origin dev resource issue.
|
|
142
|
+
</Note>
|
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
"light": "#e4587d",
|
|
8
8
|
"dark": "#002CA7"
|
|
9
9
|
},
|
|
10
|
+
"logo": {
|
|
11
|
+
"light": "/logo/exosphere-light.png",
|
|
12
|
+
"dark": "/logo/exosphere-dark.png"
|
|
13
|
+
},
|
|
10
14
|
"favicon": "/favicon.ico",
|
|
11
15
|
"navigation": {
|
|
12
16
|
"tabs": [
|
|
@@ -23,15 +27,26 @@
|
|
|
23
27
|
{
|
|
24
28
|
"group": "Core Concepts",
|
|
25
29
|
"pages": [
|
|
26
|
-
"configuration",
|
|
27
30
|
"built-in-policies",
|
|
28
|
-
"custom-
|
|
31
|
+
"custom-policies",
|
|
32
|
+
"configuration"
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"group": "CLI",
|
|
37
|
+
"pages": [
|
|
38
|
+
"cli/dashboard",
|
|
39
|
+
"cli/install-policies",
|
|
40
|
+
"cli/remove-policies",
|
|
41
|
+
"cli/list-policies",
|
|
42
|
+
"cli/hook",
|
|
43
|
+
"cli/version",
|
|
44
|
+
"cli/environment-variables"
|
|
29
45
|
]
|
|
30
46
|
},
|
|
31
47
|
{
|
|
32
48
|
"group": "Tools",
|
|
33
49
|
"pages": [
|
|
34
|
-
"cli-reference",
|
|
35
50
|
"dashboard"
|
|
36
51
|
]
|
|
37
52
|
},
|
|
@@ -40,7 +55,19 @@
|
|
|
40
55
|
"pages": [
|
|
41
56
|
"architecture",
|
|
42
57
|
"testing",
|
|
43
|
-
"package-aliases"
|
|
58
|
+
"package-aliases",
|
|
59
|
+
"for-agents"
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"tab": "Examples",
|
|
66
|
+
"groups": [
|
|
67
|
+
{
|
|
68
|
+
"group": "Examples",
|
|
69
|
+
"pages": [
|
|
70
|
+
"examples"
|
|
44
71
|
]
|
|
45
72
|
}
|
|
46
73
|
]
|