guardrails-ref 1.2.0 → 1.2.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/README.md CHANGED
@@ -20,23 +20,31 @@ Creates `.agents/guardrails/`, adds the `no-plaintext-secrets` example, and conf
20
20
 
21
21
  > **Note:** IDEs don't yet recognize guardrails natively. The `setup` command adds a rule so the AI reads them. Once IDEs add support, this won't be needed.
22
22
 
23
+ **User-level guardrails:** Use `--user` or path `~` to work with `~/.agents/guardrails/` (applies across all projects). Example: `npx guardrails-ref init --user`.
24
+
23
25
  ## Commands
24
26
 
25
27
  | Command | Description |
26
28
  |---------|-------------|
27
29
  | `npx guardrails-ref init [path]` | Create `.agents/guardrails/`, add no-plaintext-secrets, configure Cursor, Claude Code, and VS Code Copilot |
28
30
  | `npx guardrails-ref init --minimal [path]` | Create `.agents/guardrails/` only (no example, no setup) |
31
+ | `npx guardrails-ref init --user` | Create `~/.agents/guardrails/` (user-level; setup is project-specific) |
29
32
  | `npx guardrails-ref add <name> [name2 ...] [path]` | Add example guardrail(s) — pass multiple names to add several at once |
30
- | `npx guardrails-ref remove <name> [path]` | Remove a guardrail (name required) |
33
+ | `npx guardrails-ref add <name> --user` or `add <name> ~` | Add to user-level `~/.agents/guardrails/` |
34
+ | `npx guardrails-ref remove <name> [path]` | Remove a guardrail |
35
+ | `npx guardrails-ref remove <name> --user` or `remove <name> ~` | Remove from user-level |
31
36
  | `npx guardrails-ref setup [path]` | Add the guardrail rule to Cursor, Claude Code, and VS Code Copilot |
32
37
  | `npx guardrails-ref setup --remove [path]` | Remove the guardrail rule from IDE configs |
33
38
  | `npx guardrails-ref setup --ide <name> [path]` | Target IDE: `cursor`, `claude`, `copilot`, or `auto` (only configured IDEs) |
34
39
  | `npx guardrails-ref setup --dry-run [path]` | Show what would be added/removed without writing files |
35
40
  | `npx guardrails-ref setup --check [path]` | Show which IDEs are configured and whether they have the rule |
36
41
  | `npx guardrails-ref validate [path]` | Validate GUARDRAIL.md files (use `--json` for JSON, `--strict` to fail on warnings) |
42
+ | `npx guardrails-ref validate --user` or `validate ~` | Validate user-level guardrails |
37
43
  | `npx guardrails-ref check [path]` | Validate with minimal output (CI-friendly, use `--strict` to fail on warnings) |
38
44
  | `npx guardrails-ref upgrade [path]` | Update installed guardrails to latest templates (use `--dry-run` to preview, `--diff` to show changes) |
45
+ | `npx guardrails-ref upgrade --user` or `upgrade ~` | Upgrade user-level guardrails |
39
46
  | `npx guardrails-ref list [path]` | List discovered guardrails (use `--json` for JSON output) |
47
+ | `npx guardrails-ref list --user` or `list ~` | List user-level guardrails |
40
48
  | `npx guardrails-ref why <name>` | Show guardrail template content (e.g. `why no-destructive-commands`) |
41
49
 
42
50
  ## Supported IDEs
@@ -66,12 +74,19 @@ Or with full output or JSON:
66
74
  ## Examples
67
75
 
68
76
  ```bash
77
+ # Project-level (default)
69
78
  npx guardrails-ref init
70
79
  npx guardrails-ref add no-destructive-commands no-hardcoded-urls
71
80
  npx guardrails-ref add no-new-deps-without-approval
72
81
  npx guardrails-ref why no-destructive-commands
73
82
  npx guardrails-ref validate .
74
83
  npx guardrails-ref list .
84
+
85
+ # User-level (~/.agents/guardrails/)
86
+ npx guardrails-ref init --user
87
+ npx guardrails-ref add no-plaintext-secrets --user
88
+ npx guardrails-ref list --user
89
+ npx guardrails-ref validate ~
75
90
  ```
76
91
 
77
92
  ## Available guardrails (add command)
@@ -82,9 +97,14 @@ npx guardrails-ref list .
82
97
  | `no-placeholder-credentials` | Fake or placeholder API keys instead of asking for real values |
83
98
  | `no-silent-error-handling` | Catching errors without surfacing them to the user |
84
99
  | `require-access-control` | Exposing sensitive data or admin actions without role checks |
100
+ | `artifact-verification` | Destructive ops without plan.md and audit log |
101
+ | `context-rotation` | Continuing in polluted context; reset when 80% full or 10+ errors |
85
102
  | `database-migrations` | Direct schema changes instead of migrations |
86
103
  | `no-destructive-commands` | rm -rf, DROP TABLE, TRUNCATE without approval |
104
+ | `no-eval-or-dynamic-code` | eval(), new Function(), or dynamic code execution |
87
105
  | `no-new-deps-without-approval` | New packages without approval |
106
+ | `privilege-boundaries` | Touching node_modules, .git, lockfiles, .env without approval |
107
+ | `require-commit-approval` | git commit or push without explicit user approval |
88
108
  | `no-hardcoded-urls` | Hardcoded API URLs, base URLs, endpoints |
89
109
  | `no-sudo-commands` | sudo/su/root commands without approval |
90
110
  | `rate-limiting` | Runaway tool calls and API loops |
package/dist/add.d.ts CHANGED
@@ -1 +1 @@
1
- export declare function runAdd(name: string, projectPath?: string): boolean;
1
+ export declare function runAdd(name: string, projectPath?: string, userScope?: boolean): boolean;
package/dist/add.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { existsSync, mkdirSync, writeFileSync } from "fs";
2
- import { resolve } from "path";
2
+ import { join } from "path";
3
3
  import chalk from "chalk";
4
+ import { resolveGuardrailsDir } from "./path-utils.js";
4
5
  import { TEMPLATES, TEMPLATE_NAMES } from "./templates.js";
5
- export function runAdd(name, projectPath = ".") {
6
+ export function runAdd(name, projectPath = ".", userScope = false) {
6
7
  const normalized = name.toLowerCase().replace(/\s+/g, "-");
7
8
  const content = TEMPLATES[normalized];
8
9
  if (!content) {
@@ -10,20 +11,20 @@ export function runAdd(name, projectPath = ".") {
10
11
  console.log(chalk.gray("Available: " + TEMPLATE_NAMES.join(", ")));
11
12
  return false;
12
13
  }
13
- const root = resolve(projectPath);
14
- const guardrailsDir = resolve(root, ".agents", "guardrails");
15
- const exampleDir = resolve(guardrailsDir, normalized);
16
- const exampleFile = resolve(exampleDir, "GUARDRAIL.md");
14
+ const guardrailsDir = resolveGuardrailsDir(projectPath, userScope);
15
+ const exampleDir = join(guardrailsDir, normalized);
16
+ const exampleFile = join(exampleDir, "GUARDRAIL.md");
17
+ const pathLabel = userScope ? "~/.agents/guardrails/" : ".agents/guardrails/";
17
18
  if (existsSync(exampleFile)) {
18
- console.log(chalk.yellow(".agents/guardrails/" + normalized + "/GUARDRAIL.md already exists"));
19
+ console.log(chalk.yellow(pathLabel + normalized + "/GUARDRAIL.md already exists"));
19
20
  return true;
20
21
  }
21
22
  if (!existsSync(guardrailsDir)) {
22
23
  mkdirSync(guardrailsDir, { recursive: true });
23
- console.log(chalk.green("✓") + " Created .agents/guardrails/");
24
+ console.log(chalk.green("✓") + " Created " + pathLabel);
24
25
  }
25
26
  mkdirSync(exampleDir, { recursive: true });
26
27
  writeFileSync(exampleFile, content);
27
- console.log(chalk.green("✓") + " Added .agents/guardrails/" + normalized + "/GUARDRAIL.md");
28
+ console.log(chalk.green("✓") + " Added " + pathLabel + normalized + "/GUARDRAIL.md");
28
29
  return true;
29
30
  }
package/dist/cli.js CHANGED
@@ -11,6 +11,7 @@ import { runAdd } from "./add.js";
11
11
  import { runWhy } from "./why.js";
12
12
  import { runRemove } from "./remove.js";
13
13
  import { runUpgrade } from "./upgrade.js";
14
+ import { resolveGuardrailsDir } from "./path-utils.js";
14
15
  import { TEMPLATE_NAMES } from "./templates.js";
15
16
  const require = createRequire(import.meta.url);
16
17
  const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -20,7 +21,9 @@ program
20
21
  .description("Validate and list Agent Guardrails (GUARDRAIL.md) files")
21
22
  .version(pkg.version);
22
23
  function runValidate(path, options) {
23
- const result = validatePath(path);
24
+ const userScope = options.user ?? path === "~";
25
+ const pathToScan = userScope ? resolveGuardrailsDir("~", true) : path;
26
+ const result = validatePath(pathToScan);
24
27
  const hasWarnings = result.results.some((r) => r.warnings.length > 0);
25
28
  const hasErrors = result.invalid > 0;
26
29
  const strictFail = options.strict && hasWarnings;
@@ -93,6 +96,7 @@ program
93
96
  .description("Validate GUARDRAIL.md files in a directory or a single file")
94
97
  .option("-j, --json", "Output as JSON")
95
98
  .option("-s, --strict", "Fail on warnings (CI mode)")
99
+ .option("-u, --user", "Use user-level guardrails (~/.agents/guardrails/)")
96
100
  .action(function (path) {
97
101
  const opts = this.opts();
98
102
  runValidate(path ?? ".", opts);
@@ -109,15 +113,17 @@ program
109
113
  .command("init [path]")
110
114
  .description("Create .agents/guardrails/, add no-plaintext-secrets, and run setup (one command to get started)")
111
115
  .option("-m, --minimal", "Create .agents/guardrails/ only, no example and no setup")
116
+ .option("-u, --user", "Create ~/.agents/guardrails/ (user-level); setup is project-specific")
112
117
  .action(function (path) {
113
118
  const opts = this.opts();
114
- runInit(path ?? ".", opts.minimal);
119
+ runInit(path ?? ".", opts.minimal, opts.user);
115
120
  });
116
121
  program
117
122
  .command("add [names...]")
118
123
  .description("Add example guardrail(s) by name — pass multiple to add several at once")
119
124
  .option("-l, --list", "List available guardrails to add")
120
125
  .option("-p, --path <path>", "Target directory", ".")
126
+ .option("-u, --user", "Add to user-level ~/.agents/guardrails/")
121
127
  .action(function (names = []) {
122
128
  const opts = this.opts();
123
129
  if (opts.list) {
@@ -132,7 +138,7 @@ program
132
138
  // --path takes precedence when explicitly provided (opts.path !== ".")
133
139
  let targetPath = opts.path ?? ".";
134
140
  const args = names.filter((n) => n != null && String(n).trim());
135
- const looksLikePath = (s) => s === "." || s === ".." || s.includes("/") || s.includes("\\");
141
+ const looksLikePath = (s) => s === "." || s === ".." || s === "~" || s.includes("/") || s.includes("\\");
136
142
  if (args.length >= 1 && looksLikePath(args[args.length - 1])) {
137
143
  if (args.length === 1) {
138
144
  console.log("Usage: npx guardrails-ref add <name> [name2 ...] [path]");
@@ -151,11 +157,13 @@ program
151
157
  process.exit(1);
152
158
  return;
153
159
  }
160
+ const userScope = opts.user ?? targetPath === "~";
161
+ const addPath = userScope ? "~" : targetPath;
154
162
  let failed = 0;
155
163
  for (const name of args) {
156
164
  if (!name.trim())
157
165
  continue;
158
- if (!runAdd(name, targetPath))
166
+ if (!runAdd(name, addPath, userScope))
159
167
  failed++;
160
168
  }
161
169
  process.exit(failed > 0 ? 1 : 0);
@@ -165,15 +173,22 @@ program
165
173
  .description("Update installed guardrails to latest template versions")
166
174
  .option("-n, --dry-run", "Show what would be updated without writing")
167
175
  .option("-d, --diff", "Show diff for each updated guardrail")
176
+ .option("-u, --user", "Upgrade user-level ~/.agents/guardrails/")
168
177
  .action(function (path) {
169
178
  const opts = this.opts();
170
- runUpgrade(path ?? ".", opts.dryRun, opts.diff);
179
+ const p = path ?? ".";
180
+ const userScope = opts.user ?? p === "~";
181
+ runUpgrade(userScope ? "~" : p, opts.dryRun, opts.diff, userScope);
171
182
  });
172
183
  program
173
184
  .command("remove <name> [path]")
174
185
  .description("Remove a guardrail from .agents/guardrails/")
175
- .action((name, path = ".") => {
176
- const ok = runRemove(name, path);
186
+ .option("-u, --user", "Remove from user-level ~/.agents/guardrails/")
187
+ .action(function (name, path) {
188
+ const opts = this.opts();
189
+ const p = path ?? ".";
190
+ const userScope = opts.user ?? p === "~";
191
+ const ok = runRemove(name, userScope ? "~" : p, userScope);
177
192
  process.exit(ok ? 0 : 1);
178
193
  });
179
194
  program
@@ -220,9 +235,12 @@ program
220
235
  .command("list [path]")
221
236
  .description("List discovered guardrails")
222
237
  .option("-j, --json", "Output as JSON")
238
+ .option("-u, --user", "List user-level ~/.agents/guardrails/")
223
239
  .action(function (path) {
224
240
  const opts = this.opts();
225
- const guardrails = listGuardrails(path ?? ".");
241
+ const userScope = opts.user ?? path === "~";
242
+ const pathToScan = userScope ? resolveGuardrailsDir("~", true) : (path ?? ".");
243
+ const guardrails = listGuardrails(pathToScan);
226
244
  if (opts.json) {
227
245
  console.log(JSON.stringify({ guardrails, total: guardrails.length }, null, 2));
228
246
  process.exit(guardrails.length === 0 ? 1 : 0);
package/dist/init.d.ts CHANGED
@@ -3,4 +3,4 @@ export interface InitResult {
3
3
  exampleCreated: boolean;
4
4
  setupDone: string;
5
5
  }
6
- export declare function runInit(projectPath?: string, minimal?: boolean): InitResult;
6
+ export declare function runInit(projectPath?: string, minimal?: boolean, userScope?: boolean): InitResult;
package/dist/init.js CHANGED
@@ -1,23 +1,29 @@
1
1
  import { existsSync, mkdirSync, writeFileSync } from "fs";
2
- import { resolve } from "path";
2
+ import { join } from "path";
3
3
  import chalk from "chalk";
4
+ import { resolveGuardrailsDir } from "./path-utils.js";
4
5
  import { runSetup } from "./setup.js";
5
6
  import { TEMPLATES } from "./templates.js";
6
- export function runInit(projectPath = ".", minimal = false) {
7
- const root = resolve(projectPath);
8
- const guardrailsDir = resolve(root, ".agents", "guardrails");
9
- const exampleDir = resolve(guardrailsDir, "no-plaintext-secrets");
10
- const exampleFile = resolve(exampleDir, "GUARDRAIL.md");
7
+ export function runInit(projectPath = ".", minimal = false, userScope = false) {
8
+ const guardrailsDir = resolveGuardrailsDir(projectPath, userScope);
9
+ const exampleDir = join(guardrailsDir, "no-plaintext-secrets");
10
+ const exampleFile = join(exampleDir, "GUARDRAIL.md");
11
11
  let exampleCreated = false;
12
12
  if (!existsSync(guardrailsDir)) {
13
13
  mkdirSync(guardrailsDir, { recursive: true });
14
- console.log(chalk.green("✓") + " Created .agents/guardrails/");
14
+ console.log(chalk.green("✓") + " Created " + (userScope ? "~/.agents/guardrails/" : ".agents/guardrails/"));
15
15
  }
16
- if (minimal) {
16
+ if (minimal || userScope) {
17
+ if (userScope && !existsSync(exampleFile)) {
18
+ mkdirSync(exampleDir, { recursive: true });
19
+ writeFileSync(exampleFile, TEMPLATES["no-plaintext-secrets"]);
20
+ exampleCreated = true;
21
+ console.log(chalk.green("✓") + " Created ~/.agents/guardrails/no-plaintext-secrets/GUARDRAIL.md");
22
+ }
17
23
  return {
18
24
  guardrailsDir,
19
- exampleCreated: false,
20
- setupDone: "",
25
+ exampleCreated,
26
+ setupDone: userScope ? "(setup is project-specific; run setup in each project)" : "",
21
27
  };
22
28
  }
23
29
  if (!existsSync(exampleFile)) {
@@ -29,7 +35,7 @@ export function runInit(projectPath = ".", minimal = false) {
29
35
  else {
30
36
  console.log(chalk.yellow(" .agents/guardrails/no-plaintext-secrets/GUARDRAIL.md already exists"));
31
37
  }
32
- const setupResult = runSetup(projectPath);
38
+ const setupResult = runSetup(projectPath); // project-level only
33
39
  console.log(setupResult.message);
34
40
  return {
35
41
  guardrailsDir,
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Resolve the guardrails directory path.
3
+ * When userScope or path is "~", returns ~/.agents/guardrails (user-level).
4
+ * Otherwise returns <path>/.agents/guardrails (project-level).
5
+ */
6
+ export declare function resolveGuardrailsDir(path: string, userScope?: boolean): string;
@@ -0,0 +1,14 @@
1
+ import { homedir } from "os";
2
+ import { join, resolve } from "path";
3
+ /**
4
+ * Resolve the guardrails directory path.
5
+ * When userScope or path is "~", returns ~/.agents/guardrails (user-level).
6
+ * Otherwise returns <path>/.agents/guardrails (project-level).
7
+ */
8
+ export function resolveGuardrailsDir(path, userScope) {
9
+ if (userScope || path === "~" || path === "~/") {
10
+ return join(homedir(), ".agents", "guardrails");
11
+ }
12
+ const root = resolve(path);
13
+ return join(root, ".agents", "guardrails");
14
+ }
package/dist/remove.d.ts CHANGED
@@ -1 +1 @@
1
- export declare function runRemove(name: string, projectPath?: string): boolean;
1
+ export declare function runRemove(name: string, projectPath?: string, userScope?: boolean): boolean;
package/dist/remove.js CHANGED
@@ -1,30 +1,31 @@
1
1
  import { existsSync, readdirSync, rmSync, rmdirSync } from "fs";
2
- import { resolve } from "path";
2
+ import { join } from "path";
3
3
  import chalk from "chalk";
4
+ import { resolveGuardrailsDir } from "./path-utils.js";
4
5
  import { listGuardrails } from "./validate.js";
5
- export function runRemove(name, projectPath = ".") {
6
+ export function runRemove(name, projectPath = ".", userScope = false) {
6
7
  const normalized = name.toLowerCase().replace(/\s+/g, "-");
7
- const root = resolve(projectPath);
8
- const guardrailsDir = resolve(root, ".agents", "guardrails");
9
- const targetDir = resolve(guardrailsDir, normalized);
10
- const targetFile = resolve(targetDir, "GUARDRAIL.md");
8
+ const guardrailsDir = resolveGuardrailsDir(projectPath, userScope);
9
+ const targetDir = join(guardrailsDir, normalized);
10
+ const targetFile = join(targetDir, "GUARDRAIL.md");
11
+ const pathLabel = userScope ? "~/.agents/guardrails/" : ".agents/guardrails/";
11
12
  if (!existsSync(targetFile)) {
12
13
  const guardrails = listGuardrails(guardrailsDir);
13
14
  const names = guardrails.map((g) => g.name);
14
- console.log(chalk.red("Guardrail not found:") + " .agents/guardrails/" + normalized);
15
+ console.log(chalk.red("Guardrail not found:") + " " + pathLabel + normalized);
15
16
  if (names.length > 0) {
16
17
  console.log(chalk.gray("Installed: " + names.join(", ")));
17
18
  }
18
19
  return false;
19
20
  }
20
21
  rmSync(targetDir, { recursive: true });
21
- console.log(chalk.green("✓") + " Removed .agents/guardrails/" + normalized);
22
+ console.log(chalk.green("✓") + " Removed " + pathLabel + normalized);
22
23
  // Remove parent dir if empty
23
24
  try {
24
25
  const remaining = readdirSync(guardrailsDir);
25
26
  if (remaining.length === 0) {
26
27
  rmdirSync(guardrailsDir);
27
- console.log(chalk.green("✓") + " Removed empty .agents/guardrails/");
28
+ console.log(chalk.green("✓") + " Removed empty " + pathLabel);
28
29
  }
29
30
  }
30
31
  catch {
package/dist/templates.js CHANGED
@@ -37,6 +37,7 @@ Implementing authentication endpoints, adding logging, integrating third-party A
37
37
  - Use bcrypt with 12 salt rounds for password hashing
38
38
  - Always require HTTPS for authentication endpoints
39
39
  - Use a \`redactSensitive()\` helper when logging objects that may contain secrets
40
+ - Audit all logs before committing to ensure no credentials are included
40
41
 
41
42
  ## Reason
42
43
  API keys were exposed in git during a 2025 security audit. Plaintext credentials in logs led to emergency key rotation.
package/dist/upgrade.d.ts CHANGED
@@ -3,4 +3,4 @@ export interface UpgradeResult {
3
3
  skipped: string[];
4
4
  notFound: string[];
5
5
  }
6
- export declare function runUpgrade(projectPath?: string, dryRun?: boolean, showDiff?: boolean): UpgradeResult;
6
+ export declare function runUpgrade(projectPath?: string, dryRun?: boolean, showDiff?: boolean, userScope?: boolean): UpgradeResult;
package/dist/upgrade.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { existsSync, readdirSync, readFileSync, writeFileSync } from "fs";
2
- import { resolve } from "path";
2
+ import { join } from "path";
3
3
  import chalk from "chalk";
4
4
  import { createPatch } from "diff";
5
+ import { resolveGuardrailsDir } from "./path-utils.js";
5
6
  import { TEMPLATES } from "./templates.js";
6
7
  function printDiff(name, current, template) {
7
8
  const patch = createPatch(".agents/guardrails/" + name + "/GUARDRAIL.md", current, template, "current", "template");
@@ -12,12 +13,12 @@ function printDiff(name, current, template) {
12
13
  console.log(chalk.gray(body));
13
14
  }
14
15
  }
15
- export function runUpgrade(projectPath = ".", dryRun = false, showDiff = false) {
16
- const root = resolve(projectPath);
17
- const guardrailsDir = resolve(root, ".agents", "guardrails");
16
+ export function runUpgrade(projectPath = ".", dryRun = false, showDiff = false, userScope = false) {
17
+ const guardrailsDir = resolveGuardrailsDir(projectPath, userScope);
18
18
  const result = { updated: [], skipped: [], notFound: [] };
19
+ const pathLabel = userScope ? "~/.agents/guardrails/" : ".agents/guardrails/";
19
20
  if (!existsSync(guardrailsDir)) {
20
- console.log(chalk.yellow("No .agents/guardrails/ directory found"));
21
+ console.log(chalk.yellow("No " + pathLabel + " directory found"));
21
22
  return result;
22
23
  }
23
24
  const entries = readdirSync(guardrailsDir, { withFileTypes: true });
@@ -26,7 +27,7 @@ export function runUpgrade(projectPath = ".", dryRun = false, showDiff = false)
26
27
  continue;
27
28
  const name = ent.name.toLowerCase().replace(/\s+/g, "-");
28
29
  const template = TEMPLATES[name];
29
- const filePath = resolve(guardrailsDir, ent.name, "GUARDRAIL.md");
30
+ const filePath = join(guardrailsDir, ent.name, "GUARDRAIL.md");
30
31
  if (!existsSync(filePath))
31
32
  continue;
32
33
  if (!template) {
@@ -44,10 +45,10 @@ export function runUpgrade(projectPath = ".", dryRun = false, showDiff = false)
44
45
  printDiff(name, current, template);
45
46
  }
46
47
  writeFileSync(filePath, template);
47
- console.log(chalk.green("✓") + " Updated .agents/guardrails/" + name + "/GUARDRAIL.md");
48
+ console.log(chalk.green("✓") + " Updated " + pathLabel + name + "/GUARDRAIL.md");
48
49
  }
49
50
  else {
50
- console.log(chalk.cyan("Would update") + " .agents/guardrails/" + name + "/GUARDRAIL.md");
51
+ console.log(chalk.cyan("Would update") + " " + pathLabel + name + "/GUARDRAIL.md");
51
52
  if (showDiff) {
52
53
  printDiff(name, current, template);
53
54
  }
@@ -8,9 +8,14 @@ Reference guardrails you can add with `npx guardrails-ref add <name>`. Use `npx
8
8
  | `no-placeholder-credentials` | Fake or placeholder API keys instead of asking for real values |
9
9
  | `no-silent-error-handling` | Catching errors without surfacing them to the user |
10
10
  | `require-access-control` | Exposing sensitive data or admin actions without role checks |
11
+ | `artifact-verification` | Destructive ops without plan.md and audit log |
12
+ | `context-rotation` | Continuing in polluted context; reset when 80% full or 10+ errors |
11
13
  | `database-migrations` | Direct schema changes instead of migrations |
12
14
  | `no-destructive-commands` | `rm -rf`, `DROP TABLE`, `TRUNCATE` without approval |
15
+ | `no-eval-or-dynamic-code` | eval(), new Function(), or dynamic code execution |
13
16
  | `no-new-deps-without-approval` | New packages without human confirmation |
17
+ | `privilege-boundaries` | Touching node_modules, .git, lockfiles, .env without approval |
18
+ | `require-commit-approval` | git commit or push without explicit user approval |
14
19
  | `no-hardcoded-urls` | Hardcoded API URLs, base URLs, endpoints |
15
20
  | `no-sudo-commands` | `sudo`, `su`, or root commands without approval |
16
21
  | `rate-limiting` | Runaway tool calls and API loops |
@@ -0,0 +1,35 @@
1
+ ---
2
+ name: artifact-verification
3
+ description: Before destructive operations, generate a plan for human review and log actions to an audit trail. Apply when deleting, dropping, truncating, or modifying production.
4
+ scope: project
5
+ severity: critical
6
+ triggers:
7
+ - "Deleting files or directories"
8
+ - "Dropping tables or databases"
9
+ - "Truncating data"
10
+ - "Production modifications"
11
+ - "Schema changes"
12
+ license: MIT
13
+ metadata:
14
+ author: agent-guardrails
15
+ version: "1.0"
16
+ source: https://guardrails.md/
17
+ ---
18
+
19
+ # Artifact Verification
20
+
21
+ ## Trigger
22
+ Before any destructive operation: deletes, drops, truncates, or production modifications.
23
+
24
+ ## Instruction
25
+ - Generate a `plan.md` (or equivalent) describing all changes, affected paths, and impact
26
+ - Present the plan for human approval before executing
27
+ - Wait for explicit confirmation before proceeding
28
+ - Log all actions to `audit.log` (or project-defined audit trail) with timestamp and scope
29
+ - Never skip the plan step even if the user seems to approve verbally — require written confirmation or explicit approval in the plan
30
+
31
+ ## Reason
32
+ Agents have executed destructive operations without a reviewable artifact. A plan provides rollback context and ensures humans can verify scope before irreversible changes. Audit logging enables post-incident analysis.
33
+
34
+ ## Provenance
35
+ Based on guardrails.md Pattern 1: Artifact verification.
@@ -0,0 +1,34 @@
1
+ ---
2
+ name: context-rotation
3
+ description: When context exceeds 80% capacity or 10+ consecutive errors, save state, summarize, and reset to prevent "The Gutter" — agents repeating mistakes in polluted context.
4
+ scope: session
5
+ severity: warning
6
+ triggers:
7
+ - "Context window approaching capacity"
8
+ - "Repeated identical errors"
9
+ - "Circular tool call loops"
10
+ - "10+ consecutive failures"
11
+ license: MIT
12
+ metadata:
13
+ author: agent-guardrails
14
+ version: "1.0"
15
+ source: https://guardrails.md/
16
+ ---
17
+
18
+ # Context Rotation
19
+
20
+ ## Trigger
21
+ Context exceeds 80% capacity, 10+ consecutive errors, repeated identical failures, or circular tool call loops.
22
+
23
+ ## Instruction
24
+ - Save current state to `context-snapshot.md` (or equivalent) before resetting
25
+ - Summarize key learnings and what was attempted
26
+ - Reset the context window
27
+ - Re-inject: GUARDRAILS.md + summary + original objective
28
+ - Do not continue in polluted context — rotation prevents recursive failure loops
29
+
30
+ ## Reason
31
+ Agents feed outputs back into context. When it fills with error logs and failed attempts, the agent prioritizes recent failures over original instructions and enters "The Gutter" — repeating the same mistakes indefinitely. Rotation breaks the loop.
32
+
33
+ ## Provenance
34
+ Based on guardrails.md Pattern 2: Context rotation.
@@ -0,0 +1,34 @@
1
+ ---
2
+ name: no-eval-or-dynamic-code
3
+ description: Never use eval(), new Function(), or similar dynamic code execution. Prevents code injection and security vulnerabilities.
4
+ scope: project
5
+ severity: critical
6
+ triggers:
7
+ - "Executing user input"
8
+ - "Dynamic code execution"
9
+ - "JSON parsing to code"
10
+ - "eval"
11
+ - "Function constructor"
12
+ license: MIT
13
+ metadata:
14
+ author: agent-guardrails
15
+ version: "1.0"
16
+ ---
17
+
18
+ # No Eval or Dynamic Code
19
+
20
+ ## Trigger
21
+ Considering `eval()`, `new Function()`, `setTimeout(string)`, `setInterval(string)`, or any mechanism that executes a string as code.
22
+
23
+ ## Instruction
24
+ - Never use `eval()` — use `JSON.parse()` for JSON, proper parsers for other formats
25
+ - Never use `new Function(body)` or `Function(arg1, arg2, body)` with dynamic body
26
+ - Never pass user input to `setTimeout`, `setInterval`, or `vm.runInContext` as executable code
27
+ - For dynamic behavior: use lookup tables, strategy pattern, or safe configuration — not code-as-string
28
+ - If the user requests "eval" or "dynamic execution": explain the security risk and suggest alternatives
29
+
30
+ ## Reason
31
+ Dynamic code execution with user or external input enables code injection. Attackers can escape strings and execute arbitrary code. Use structured data and safe parsing instead.
32
+
33
+ ## Provenance
34
+ OWASP, common security guidance for handling untrusted input.
@@ -25,6 +25,7 @@ Implementing authentication endpoints, adding logging, integrating third-party A
25
25
  - Use bcrypt with 12 salt rounds for password hashing
26
26
  - Always require HTTPS for authentication endpoints
27
27
  - Use a `redactSensitive()` helper when logging objects that may contain secrets
28
+ - Audit all logs before committing to ensure no credentials are included
28
29
 
29
30
  ## Reason
30
31
  API keys were exposed in git during a 2025 security audit. Plaintext credentials in logs led to emergency key rotation.
@@ -0,0 +1,34 @@
1
+ ---
2
+ name: privilege-boundaries
3
+ description: Define what paths and resources the agent can read or write. Never touch node_modules, .git, or production config without explicit approval.
4
+ scope: project
5
+ severity: critical
6
+ triggers:
7
+ - "File system operations"
8
+ - "Reading or writing files"
9
+ - "Modifying config"
10
+ - "Accessing dependencies"
11
+ license: MIT
12
+ metadata:
13
+ author: agent-guardrails
14
+ version: "1.0"
15
+ source: https://guardrails.md/
16
+ ---
17
+
18
+ # Privilege Boundaries
19
+
20
+ ## Trigger
21
+ Any file system read/write, config modification, or access to project directories.
22
+
23
+ ## Instruction
24
+ - **Forbidden (never touch without explicit approval):** `node_modules/`, `.git/`, `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`, `.env`, `.env.*`, production config files
25
+ - **Read-only unless instructed:** Database migrations, CI config (`.github/`, `.gitlab-ci.yml`), deployment config
26
+ - **Allowed for normal edits:** Source code (`src/`, `lib/`), tests (`test/`, `__tests__/`), docs, project config files
27
+ - When in doubt, ask before modifying files outside the current task scope
28
+ - If the user requests changes to forbidden paths, stop and confirm scope before proceeding
29
+
30
+ ## Reason
31
+ Agents have corrupted `node_modules`, overwritten lockfiles, and exposed secrets by modifying `.env`. Explicit boundaries prevent accidental damage to dependency state and version control.
32
+
33
+ ## Provenance
34
+ Based on guardrails.md Pattern 3: Privilege boundaries.
@@ -0,0 +1,33 @@
1
+ ---
2
+ name: require-commit-approval
3
+ description: Never run git commit or git push without explicit user approval. Show diff, wait for confirmation before committing.
4
+ scope: project
5
+ severity: critical
6
+ triggers:
7
+ - "Committing changes"
8
+ - "git commit"
9
+ - "git push"
10
+ - "Pushing to remote"
11
+ license: MIT
12
+ metadata:
13
+ author: agent-guardrails
14
+ version: "1.0"
15
+ ---
16
+
17
+ # Require Commit Approval
18
+
19
+ ## Trigger
20
+ About to run `git commit`, `git push`, or any operation that persists changes to version control.
21
+
22
+ ## Instruction
23
+ - Never run `git commit` or `git push` without explicit user approval
24
+ - Show the diff (or summary of changes) and ask for confirmation before committing
25
+ - Wait for the user to confirm (e.g. "yes", "commit", "push") before executing
26
+ - If the user says "commit my changes" or similar, still show what will be committed and get explicit approval
27
+ - Prefer `git add` + show status, then wait — do not auto-commit
28
+
29
+ ## Reason
30
+ Agents have committed incomplete work, wrong files, or broken code without the user reviewing. Unapproved commits pollute history and can push secrets or bugs to remotes.
31
+
32
+ ## Provenance
33
+ Common failure mode in autonomous coding agents.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "guardrails-ref",
3
- "version": "1.2.0",
3
+ "version": "1.2.3",
4
4
  "description": "Validate and manage Agent Guardrails (GUARDRAIL.md) — init, add, remove, setup, validate, check, upgrade, list, why",
5
5
  "type": "module",
6
6
  "main": "dist/validate.js",