failproofai 0.0.2-beta.2 → 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.
Files changed (124) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +3 -3
  3. package/.next/standalone/.next/prerender-manifest.json +3 -3
  4. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  6. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  7. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  9. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  10. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  11. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
  12. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  13. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  16. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  17. package/.next/standalone/.next/server/app/_not-found.html +2 -2
  18. package/.next/standalone/.next/server/app/_not-found.rsc +17 -17
  19. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +17 -17
  20. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  21. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +11 -11
  22. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  23. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  24. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  25. package/.next/standalone/.next/server/app/index.html +1 -1
  26. package/.next/standalone/.next/server/app/index.rsc +16 -16
  27. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  28. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +16 -16
  29. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
  30. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +11 -11
  31. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  32. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  33. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  35. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +8 -8
  36. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  38. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  39. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  41. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  42. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  43. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  45. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  46. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  47. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  48. package/.next/standalone/.next/server/chunks/[root-of-the-server]__02nt~6d._.js +1 -1
  49. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_0z7w.hh._.js +1 -1
  50. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0103jwf._.js → [root-of-the-server]__07k6eu-._.js} +2 -2
  51. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__092s1ta._.js +2 -2
  52. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__09icjsf._.js +2 -2
  53. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0g.lg8b._.js +2 -2
  54. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h..k-e._.js +2 -2
  55. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0ovwjau._.js → [root-of-the-server]__0kfv9fw._.js} +2 -2
  56. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0okos0k._.js +2 -2
  57. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0w6l33k._.js +5 -5
  58. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11pa2ra._.js +2 -2
  59. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__12t-wym._.js +2 -2
  60. package/.next/standalone/.next/server/chunks/ssr/_10lm7or._.js +1 -1
  61. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_0xerkr6._.js +1 -1
  62. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_0q-m0y-._.js +1 -1
  63. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  64. package/.next/standalone/.next/server/pages/404.html +2 -2
  65. package/.next/standalone/.next/server/pages/500.html +1 -1
  66. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  67. package/.next/standalone/.next/server/server-reference-manifest.json +9 -9
  68. package/.next/standalone/.next/static/chunks/{0uftmw5od9kdz.js → 0.jo.465b6_k..js} +1 -1
  69. package/.next/standalone/.next/static/chunks/{0wtcha31~i7rm.js → 01haq0a3zrx0v.js} +1 -1
  70. package/.next/standalone/.next/static/chunks/08f78tecvx61l.css +1 -0
  71. package/.next/standalone/.next/static/chunks/{0tl2f-3yc.rqc.js → 0a6xi1a8f_qlp.js} +1 -1
  72. package/.next/standalone/.next/static/chunks/{0tbr0o7vwc~-s.js → 0mq7ze1vkeo1p.js} +1 -1
  73. package/.next/standalone/.next/static/chunks/{0sm1iqi3m~xiz.js → 0p_fpyfmmohnx.js} +1 -1
  74. package/.next/standalone/.next/static/chunks/{0pdd7~yp8ytu6.js → 0qwyj3m400l_g.js} +1 -1
  75. package/.next/standalone/.next/static/chunks/{001k0zayn2o.s.js → 0t94r_mk0s7e4.js} +1 -1
  76. package/.next/standalone/.next/static/chunks/{0jrzwsyo7wo26.js → 139~00zc9.u7s.js} +1 -1
  77. package/.next/standalone/Dockerfile.docs +12 -0
  78. package/.next/standalone/README.md +59 -46
  79. package/.next/standalone/dist/cli.mjs +215 -20
  80. package/.next/standalone/dist/index.js +2 -2
  81. package/.next/standalone/docs/{architecture.md → architecture.mdx} +40 -23
  82. package/.next/standalone/docs/{built-in-policies.md → built-in-policies.mdx} +134 -12
  83. package/.next/standalone/docs/cli/dashboard.mdx +28 -0
  84. package/.next/standalone/docs/cli/environment-variables.mdx +34 -0
  85. package/.next/standalone/docs/cli/hook.mdx +30 -0
  86. package/.next/standalone/docs/cli/install-policies.mdx +48 -0
  87. package/.next/standalone/docs/cli/list-policies.mdx +31 -0
  88. package/.next/standalone/docs/cli/remove-policies.mdx +44 -0
  89. package/.next/standalone/docs/cli/version.mdx +12 -0
  90. package/.next/standalone/docs/{configuration.md → configuration.mdx} +16 -16
  91. package/.next/standalone/docs/{custom-hooks.md → custom-policies.mdx} +80 -42
  92. package/.next/standalone/docs/{dashboard.md → dashboard.mdx} +26 -29
  93. package/.next/standalone/docs/docs.json +31 -4
  94. package/.next/standalone/docs/examples.mdx +253 -0
  95. package/.next/standalone/docs/for-agents.mdx +38 -0
  96. package/.next/standalone/docs/getting-started.mdx +134 -0
  97. package/.next/standalone/docs/introduction.mdx +57 -0
  98. package/.next/standalone/docs/logo/dark.svg +21 -0
  99. package/.next/standalone/docs/logo/light.svg +21 -0
  100. package/.next/standalone/docs/{package-aliases.md → package-aliases.mdx} +5 -5
  101. package/.next/standalone/docs/{testing.md → testing.mdx} +11 -11
  102. package/.next/standalone/package.json +6 -9
  103. package/.next/standalone/scripts/publish-aliases.mjs +4 -2
  104. package/.next/standalone/skills-lock.json +10 -0
  105. package/.next/standalone/src/hooks/builtin-policies.ts +259 -20
  106. package/.next/standalone/src/hooks/policy-evaluator.ts +19 -1
  107. package/.next/standalone/src/hooks/policy-helpers.ts +2 -2
  108. package/.next/standalone/vitest.config.e2e.mts +3 -0
  109. package/.next/standalone/vitest.config.mts +3 -0
  110. package/README.md +59 -46
  111. package/dist/cli.mjs +215 -20
  112. package/dist/index.js +2 -2
  113. package/package.json +6 -9
  114. package/scripts/publish-aliases.mjs +4 -2
  115. package/src/hooks/builtin-policies.ts +259 -20
  116. package/src/hooks/policy-evaluator.ts +19 -1
  117. package/src/hooks/policy-helpers.ts +2 -2
  118. package/.next/standalone/.next/static/chunks/15jpradyu_531.css +0 -1
  119. package/.next/standalone/docs/cli-reference.md +0 -175
  120. package/.next/standalone/docs/getting-started.md +0 -128
  121. package/.next/standalone/docs/introduction.md +0 -47
  122. /package/.next/standalone/.next/static/{JksWDLwDoPy6bcczVWlff → 7fR022u1Sj-s5MfKO1q9Y}/_buildManifest.js +0 -0
  123. /package/.next/standalone/.next/static/{JksWDLwDoPy6bcczVWlff → 7fR022u1Sj-s5MfKO1q9Y}/_clientMiddlewareManifest.js +0 -0
  124. /package/.next/standalone/.next/static/{JksWDLwDoPy6bcczVWlff → 7fR022u1Sj-s5MfKO1q9Y}/_ssgManifest.js +0 -0
@@ -1,10 +1,10 @@
1
1
  ---
2
- title: Custom Hooks
3
- description: "Write your own policies in JavaScript with allow, deny, and instruct decisions"
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 hooks let you write your own policies in JavaScript. They integrate with the same hook event system as built-in policies and support the same `allow`, `deny`, and `instruct` decisions.
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-policies --custom ./my-policies.js
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 hooks file
44
- failproofai --install-policies --custom ./my-policies.js
43
+ # Install with a custom policies file
44
+ failproofai policies --install --custom ./my-policies.js
45
45
 
46
- # Replace the hooks file path
47
- failproofai --install-policies --custom ./new-policies.js
46
+ # Replace the policies file path
47
+ failproofai policies --install --custom ./new-policies.js
48
48
 
49
- # Remove the custom hooks path from config
50
- failproofai --remove-policies --custom
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 there is no caching between events.
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 hook. Call this as many times as needed for multiple hooks in the same file.
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 unique identifier
72
- description?: string; // shown in --list-policies output
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 tool call | Nothing to block or warn about |
83
- | `deny(message)` | Block the tool call | The action should not proceed |
84
- | `instruct(message)` | Add context to Claude's prompt | You want Claude to be careful but not stopped |
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)` the message appears to Claude prefixed with `"Blocked by failproofai:"`.
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)` the message is appended to Claude's context for the current tool call. Multiple `instruct` returns from different hooks accumulate; a single `deny` short-circuits all further evaluation.
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" \| ... }` hooks must always return `allow()`, they cannot block notifications |
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
- Hooks are evaluated in this order:
155
+ Policies are evaluated in this order:
122
156
 
123
157
  1. Built-in policies (in definition order)
124
- 2. Custom hooks (in `.add()` order)
158
+ 2. Custom policies (in `.add()` order)
125
159
 
126
- The first `deny` short-circuits all subsequent hooks. All `instruct` returns accumulate into a single message regardless of which hook produced them.
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 hook files can import local modules using relative paths:
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
- ## Hook event type filtering
189
+ ## Event type filtering
154
190
 
155
- Use `match.events` to limit when a hook fires:
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 hooks are **fail-open**: errors never block built-in policies or crash the hook handler.
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 hooks run; built-ins continue normally |
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 hooks skipped |
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
- To debug custom hook errors:
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 hooks
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
- // Block any write to a path containing "secrets/"
237
+ // Prevent agent from writing to secrets/ directory
200
238
  customPolicies.add({
201
239
  name: "block-secrets-dir",
202
- description: "Block writes to secrets/ directory",
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
- // Remind Claude to check test results before committing
250
+ // Keep the agent on track: verify tests before committing
213
251
  customPolicies.add({
214
252
  name: "remind-test-before-commit",
215
- description: "Remind Claude to verify tests pass before committing",
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
- // Block npm install during a freeze period
265
+ // Prevent unplanned dependency changes during freeze
228
266
  customPolicies.add({
229
267
  name: "dependency-freeze",
230
- description: "Block new package installs during freeze period",
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 in the repository
286
+ ## Examples
249
287
 
250
- The `examples/` directory contains ready-to-run hook files:
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 use cases |
255
- | `examples/policies-advanced/index.js` | Advanced patterns including transitive imports, async calls, and `Stop` event hooks |
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-policies --custom ./examples/policies-basic.js
298
+ failproofai policies --install --custom ./examples/policies-basic.js
261
299
  ```
@@ -1,10 +1,10 @@
1
1
  ---
2
2
  title: Dashboard
3
- description: "Session viewer, policy management, and activity log"
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 browsing Claude Code sessions and managing security policies.
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
- For production mode (faster startup, no file watching):
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
- A timeline of everything that happened in a session:
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** Claude's text responses and user prompts
59
- - **Tool calls** Every tool Claude invoked, with its input and output
60
- - **Hook activity** For each tool call, which policies fired and what decision they returned
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
- **Policies tab:**
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 hooks file path
76
-
77
- **Activity tab:**
78
-
79
- - Full paginated history of every hook event that has fired across all sessions
80
- - Search by policy name, session ID, tool name, or decision
81
- - Each row shows: timestamp, policy name, decision, tool name, session ID, and the reason for deny/instruct decisions
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 hook activity as they appear. Useful when you have an active Claude Code session running in parallel.
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` for example, a custom domain, a remote IP, or a tunneled URL you may see a warning like:
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
- > **Note:** This only applies to dev mode. When running `failproofai` (production mode), there is no HMR websocket and no cross-origin dev resource issue.
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-hooks"
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
  ]
@@ -0,0 +1,253 @@
1
+ ---
2
+ title: Examples
3
+ description: "How to set up hooks for Claude Code and the Agents SDK"
4
+ icon: book-open
5
+ ---
6
+
7
+ Ready-to-use examples for common scenarios. Each one shows how to install and what to expect.
8
+
9
+ ---
10
+
11
+ ## Setting up hooks for Claude Code
12
+
13
+ Failproof AI integrates with Claude Code via its [hooks system](https://docs.anthropic.com/en/docs/claude-code/hooks). When you run `failproofai policies --install`, it registers hook commands in Claude Code's `settings.json` that fire on every tool call.
14
+
15
+ <Steps>
16
+ <Step title="Install failproofai">
17
+ ```bash
18
+ npm install -g failproofai
19
+ ```
20
+ </Step>
21
+ <Step title="Enable all built-in policies">
22
+ ```bash
23
+ failproofai policies --install
24
+ ```
25
+ </Step>
26
+ <Step title="Verify hooks are registered">
27
+ ```bash
28
+ cat ~/.claude/settings.json | grep failproofai
29
+ ```
30
+
31
+ You should see hook entries for `PreToolUse`, `PostToolUse`, `Notification`, and `Stop` events.
32
+ </Step>
33
+ <Step title="Run Claude Code">
34
+ ```bash
35
+ claude
36
+ ```
37
+
38
+ Policies now run automatically on every tool call. Try asking Claude to run `sudo rm -rf /` - it will be blocked.
39
+ </Step>
40
+ </Steps>
41
+
42
+ ---
43
+
44
+ ## Setting up hooks for the Agents SDK
45
+
46
+ If you're building with the [Agents SDK](https://docs.anthropic.com/en/docs/agents-sdk), you can use the same hook system programmatically.
47
+
48
+ <Steps>
49
+ <Step title="Install failproofai in your project">
50
+ ```bash
51
+ npm install failproofai
52
+ ```
53
+ </Step>
54
+ <Step title="Configure hooks in your agent">
55
+ Pass hook commands when creating your agent process. The hooks fire the same way as in Claude Code - via stdin/stdout JSON:
56
+
57
+ ```bash
58
+ failproofai --hook PreToolUse # called before each tool
59
+ failproofai --hook PostToolUse # called after each tool
60
+ ```
61
+ </Step>
62
+ <Step title="Write a custom policy for your agent">
63
+ ```javascript
64
+ import { customPolicies, allow, deny } from "failproofai";
65
+
66
+ customPolicies.add({
67
+ name: "limit-to-project-dir",
68
+ description: "Keep the agent inside the project directory",
69
+ match: { events: ["PreToolUse"] },
70
+ fn: async (ctx) => {
71
+ const path = String(ctx.toolInput?.file_path ?? "");
72
+ if (path.startsWith("/") && !path.startsWith(ctx.session?.cwd ?? "")) {
73
+ return deny("Agent is restricted to the project directory");
74
+ }
75
+ return allow();
76
+ },
77
+ });
78
+ ```
79
+ </Step>
80
+ <Step title="Install the custom policy">
81
+ ```bash
82
+ failproofai policies --install --custom ./my-agent-policies.js
83
+ ```
84
+ </Step>
85
+ </Steps>
86
+
87
+ ---
88
+
89
+ ## Block destructive commands
90
+
91
+ The most common setup - prevent agents from doing irreversible damage.
92
+
93
+ ```bash
94
+ failproofai policies --install block-sudo block-rm-rf block-force-push block-curl-pipe-sh
95
+ ```
96
+
97
+ What this does:
98
+ - `block-sudo` - blocks all `sudo` commands
99
+ - `block-rm-rf` - blocks recursive file deletion
100
+ - `block-force-push` - blocks `git push --force`
101
+ - `block-curl-pipe-sh` - blocks piping remote scripts to shell
102
+
103
+ ---
104
+
105
+ ## Prevent secret leakage
106
+
107
+ Stop agents from seeing or leaking credentials in tool output.
108
+
109
+ ```bash
110
+ failproofai policies --install sanitize-api-keys sanitize-jwt sanitize-connection-strings sanitize-bearer-tokens
111
+ ```
112
+
113
+ These fire on `PostToolUse` - after a tool runs, they scrub the output before the agent sees it.
114
+
115
+ ---
116
+
117
+ ## Get Slack alerts when agents need attention
118
+
119
+ Use the notification hook to forward idle alerts to Slack.
120
+
121
+ ```javascript
122
+ import { customPolicies, allow, instruct } from "failproofai";
123
+
124
+ customPolicies.add({
125
+ name: "slack-on-idle",
126
+ description: "Alert Slack when the agent is waiting for input",
127
+ match: { events: ["Notification"] },
128
+ fn: async (ctx) => {
129
+ const webhookUrl = process.env.SLACK_WEBHOOK_URL;
130
+ if (!webhookUrl) return allow();
131
+
132
+ const message = String(ctx.payload?.message ?? "Agent is waiting");
133
+ const project = ctx.session?.cwd ?? "unknown";
134
+
135
+ try {
136
+ await fetch(webhookUrl, {
137
+ method: "POST",
138
+ headers: { "Content-Type": "application/json" },
139
+ body: JSON.stringify({
140
+ text: `*${message}*\nProject: \`${project}\``,
141
+ }),
142
+ signal: AbortSignal.timeout(5000),
143
+ });
144
+ } catch {
145
+ // never block the agent if Slack is unreachable
146
+ }
147
+
148
+ return allow();
149
+ },
150
+ });
151
+ ```
152
+
153
+ Install it:
154
+
155
+ ```bash
156
+ SLACK_WEBHOOK_URL=https://hooks.slack.com/... failproofai policies --install --custom ./slack-alerts.js
157
+ ```
158
+
159
+ ---
160
+
161
+ ## Keep agents on a branch
162
+
163
+ Prevent agents from switching branches or pushing to protected ones.
164
+
165
+ ```javascript
166
+ import { customPolicies, allow, deny } from "failproofai";
167
+
168
+ customPolicies.add({
169
+ name: "stay-on-branch",
170
+ description: "Prevent the agent from checking out other branches",
171
+ match: { events: ["PreToolUse"] },
172
+ fn: async (ctx) => {
173
+ if (ctx.toolName !== "Bash") return allow();
174
+ const cmd = String(ctx.toolInput?.command ?? "");
175
+ if (/git\s+checkout\s+(?!-b)/.test(cmd)) {
176
+ return deny("Stay on the current branch. Create a new branch with -b if needed.");
177
+ }
178
+ return allow();
179
+ },
180
+ });
181
+ ```
182
+
183
+ ---
184
+
185
+ ## Require tests before commits
186
+
187
+ Remind agents to run tests before committing.
188
+
189
+ ```javascript
190
+ import { customPolicies, allow, instruct } from "failproofai";
191
+
192
+ customPolicies.add({
193
+ name: "test-before-commit",
194
+ description: "Remind the agent to run tests before committing",
195
+ match: { events: ["PreToolUse"] },
196
+ fn: async (ctx) => {
197
+ if (ctx.toolName !== "Bash") return allow();
198
+ const cmd = String(ctx.toolInput?.command ?? "");
199
+ if (/git\s+commit/.test(cmd)) {
200
+ return instruct("Run tests before committing. Use `npm test` or `bun test` first.");
201
+ }
202
+ return allow();
203
+ },
204
+ });
205
+ ```
206
+
207
+ ---
208
+
209
+ ## Lock down a production repo
210
+
211
+ Commit a project-level config so every developer on your team gets the same policies.
212
+
213
+ Create `.failproofai/policies-config.json` in your repo:
214
+
215
+ ```json
216
+ {
217
+ "enabledPolicies": [
218
+ "block-sudo",
219
+ "block-rm-rf",
220
+ "block-force-push",
221
+ "block-push-master",
222
+ "block-env-files",
223
+ "sanitize-api-keys",
224
+ "sanitize-jwt"
225
+ ],
226
+ "policyParams": {
227
+ "block-push-master": {
228
+ "protectedBranches": ["main", "release", "production"]
229
+ }
230
+ }
231
+ }
232
+ ```
233
+
234
+ Then commit it:
235
+
236
+ ```bash
237
+ git add .failproofai/policies-config.json
238
+ git commit -m "Add failproofai team policies"
239
+ ```
240
+
241
+ Every team member who has failproofai installed will automatically pick up these rules.
242
+
243
+ ---
244
+
245
+ ## More examples
246
+
247
+ The [`examples/`](https://github.com/exospherehost/failproofai/tree/main/examples) directory in the repo contains:
248
+
249
+ | File | What it shows |
250
+ |------|---------------|
251
+ | `policies-basic.js` | Starter policies - block production writes, force-push, piped scripts |
252
+ | `policies-notification.js` | Slack alerts for idle notifications and session end |
253
+ | `policies-advanced/index.js` | Transitive imports, async hooks, PostToolUse output scrubbing, Stop event handling |