Source profileQuality 90/100Review permissions

ZaxbyHub/opencode-swarm/.opencode/skills/generated/guardrail-patterns/SKILL.md

guardrail-patterns

Guardrail patterns for opencode-swarm — pattern structure, bypass surfaces, regex anti-patterns, and test conventions for checkDestructiveCommand()

Source repository stars
451
Declared platforms
0
Static risk flags
1
Last source update
2026-08-25
Source checked
2026-08-25

Decision brief

What it does: where it fits

Source knowledge: 098926ef, 2c1e4689, 54c33fa4, 4f51d11a

Best for

    Not for

    • Anti-pattern 1: [^-] consuming path characters
    • Anti-pattern 2: Negative lookahead too broad ((?!-\S))

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexNot declaredNo explicit evidencePortability before use
    Claude CodeNot declaredNo explicit evidencePortability before use
    CursorNot declaredNo explicit evidencePortability before use
    Gemini CLINot declaredNo explicit evidencePortability before use
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/ZaxbyHub/opencode-swarm --skill ".opencode/skills/generated/guardrail-patterns"
    Safe inspection promptEditorial

    Inspect the Agent Skill "guardrail-patterns" from https://github.com/ZaxbyHub/opencode-swarm/blob/97dc624b391c8e2e80ed42f4bfa37876554c24cb/.opencode/skills/generated/guardrail-patterns/SKILL.md at commit 97dc624b391c8e2e80ed42f4bfa37876554c24cb. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      Step 1 — Determine the pattern placement

      Inside checkDestructiveCommand(), the per-segment for loop evaluates each segment against sections 1–22. A new section should be added after the last existing section and before the closing } of the for loop (currently after Section 22 at approximately line 1733).

      Inside checkDestructiveCommand(), the per-segment for loop evaluates each segment against sections 1–22. A new section should be added after the last existing section and before the closing } of the for loop (currently…
    2. 02

      Step 2 — Choose the regex pattern structure

      There are three patterns used in the codebase:

      There are three patterns used in the codebase:Pattern A — Simple inline regex (single condition):Pattern B — Multi-condition (flag check + path check):
    3. 03

      Step 3 — Handle all platform variants

      POSIX, Windows cmd.exe, and PowerShell often use different commands for the same operation. All three must be covered:

      POSIX, Windows cmd.exe, and PowerShell often use different commands for the same operation. All three must be covered:
    4. 04

      Step 4 — Handle the .swarm path separator

      Always use \x5c (backslash) for cross-platform path matching — \ alone is the regex escape character.

      Always use \x5c (backslash) for cross-platform path matching — \ alone is the regex escape character.
    5. 05

      Step 5 — Handle backslash-prefixed command evasion

      Commands prefixed with \ (e.g., \mv) bypass simple ^command\s anchors. Always add \\?:

      Commands prefixed with \ (e.g., \mv) bypass simple ^command\s anchors. Always add \\?:

    Permission review

    Static risk signals and limitations

    Runs scripts

    medium · line 24

    The documentation asks the agent to run terminal commands or scripts.

    `dcStripOneWrapper()` (line ~664) — detects and strips individual shell wrappers: `bash`, `sh`, `zsh`, `dash`, `fish`, `pwsh`, `powershell`, `cmd` (with `-c`/`-Command`), `sudo`, `nohup`, `time`, `nice`, `env VAR=val`, `call` (batch), `Invo

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score90/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars451SourceRepository attention, not individual Skill quality
    Compatibility0 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    ZaxbyHub/opencode-swarm
    Skill path
    .opencode/skills/generated/guardrail-patterns/SKILL.md
    Commit
    97dc624b391c8e2e80ed42f4bfa37876554c24cb
    License
    MIT
    Collected
    2026-08-25
    Default branch
    main
    View the original SKILL.md

    Skill: Guardrail Patterns for opencode-swarm

    Source knowledge: 098926ef, 2c1e4689, 54c33fa4, 4f51d11a

    Load this skill before modifying src/hooks/guardrails.ts — adding, removing, or changing guardrail blocks in checkDestructiveCommand(). It documents the pattern structure, known bypass surfaces, regex anti-patterns, and test conventions used across 41 guardrail test files and the ~3900-line guardrails.ts file.

    When to load this skill

    Load before any change to:

    • src/hooks/guardrails.ts — especially checkDestructiveCommand() or dcNormalizeCommand()
    • tests/unit/hooks/guardrails*.test.ts — any guardrail test file
    • Adding a new section (currently Sections 1–22) to checkDestructiveCommand()
    • Adding regex patterns for shell command blocking

    Architecture overview

    checkDestructiveCommand() — the shell command guard

    Located at src/hooks/guardrails.ts (line 1304). This is the only function that blocks destructive shell commands. It is invoked by the toolBefore hook in guardrails.ts before every bash or shell tool call.

    Pipeline (in order):

    1. dcNormalizeCommand() (line ~627) — NFKC normalization + evasion collapse: collapses "" (doubled double-quotes) and '' (doubled single-quotes). Single-quote splice like m'v' remains OPEN.
    2. dcStripOneWrapper() (line ~664) — detects and strips individual shell wrappers: bash, sh, zsh, dash, fish, pwsh, powershell, cmd (with -c/-Command), sudo, nohup, time, nice, env VAR=val, call (batch), Invoke-Command -ScriptBlock, & { } script blocks, wsl, iex
    3. dcUnwrapWrappers() (line ~737) — loops dcStripOneWrapper until no more wrappers remain (max depth 10)
    4. dcSplitSegments() (line ~753) — splits compound commands on &&, ;, |, newlines
    5. Per-segment loop — each segment evaluated against 22+ guardrail sections
    6. dcValidateTargets() — runtime lstat-ancestor walk on destructive targets

    Key normalization functions

    FunctionLineWhat it normalizes
    dcNormalizeCommand~627NFKC, caret escapes (^), backtick escapes, collapsed "" and ''
    dcStripOneWrapper~664Detects/strips a single shell wrapper (bash/sh/zsh/pwsh/cmd/powershell/wsl etc)
    dcUnwrapWrappers~737Loops dcStripOneWrapper until no more wrappers (max depth 10)
    dcSplitSegments~753Splits on &&, ;, `

    Known wrapper unwrapping limitation: sh -c and bash -c with single-quoted inner commands (sh -c 'mv ...') are NOT unwrapped because dcStripOneWrapper uses "? (optional double-quote). Only double-quoted inner commands are properly stripped.

    Adding a new guardrail block

    Step 1 — Determine the pattern placement

    Inside checkDestructiveCommand(), the per-segment for loop evaluates each segment against sections 1–22. A new section should be added after the last existing section and before the closing } of the for loop (currently after Section 22 at approximately line 1733).

    Step 2 — Choose the regex pattern structure

    There are three patterns used in the codebase:

    Pattern A — Simple inline regex (single condition):

    // Good for: single-command blocking with no complex extraction
    if (/^blockedcommand\b.*\.swarm[\x5c/\s]?/i.test(seg)) {
      throw new Error(`BLOCKED: "blockedcommand" targeting .swarm/ detected — ...`);
    }
    

    Pattern B — Multi-condition (flag check + path check):

    // Good for: archive tools with flags + .swarm/ path (prevents argument-order bypass)
    if (
      /^toolname\b.*--dangerous-flag\b/i.test(seg) &&
      /\.swarm(?:[\x5c/\s]|$)/i.test(seg)
    ) {
    

    This is recommended because it handles both tool --flag .swarm/path and tool .swarm/path --flag argument orders.

    Pattern C — Argument extraction + stripped check:

    // Good for: commands where you need argument isolation (e.g., `mv` with arg capture)
    if (/^\\?command\s/i.test(seg)) {
      const match = seg.match(/^\\?command\s+(.+)$/i);
      if (match) {
        const argsStr = match[1].replace(/["']/g, '');
        if (/\.swarm(?:[\x5c/\s]|$)/.test(argsStr)) {
          throw new Error(`BLOCKED: ...`);
        }
      }
    }
    

    Step 3 — Handle all platform variants

    POSIX, Windows cmd.exe, and PowerShell often use different commands for the same operation. All three must be covered:

    // POSIX section
    if (/^\\?posix-cmd\s/i.test(seg) && /\.swarm/i.test(strippedArgs)) { ... }
    
    // Windows cmd section (case-insensitive, optional .exe)
    if (/^\\?(?:cmd-cmd|cmd-cmd-alias)(?:\.exe)?\s/i.test(seg) && /\.swarm/i.test(argsStr)) { ... }
    
    // PowerShell section (case-insensitive, all aliases)
    if (/^\\?(?:PowerShell-Cmdlet|alias1|alias2)\b.*\.swarm/i.test(seg)) { ... }
    

    Step 4 — Handle the .swarm path separator

    Always use \x5c (backslash) for cross-platform path matching — \ alone is the regex escape character.

    // Correct: matches both / and \
    /\.swarm[\x5c/]/
    
    // More complete: also matches .swarm followed by whitespace or end-of-string
    // (catches whole-directory targeting like `mv .swarm /tmp/`)
    /\.swarm(?:[\x5c/\s]|$)/
    

    Step 5 — Handle backslash-prefixed command evasion

    Commands prefixed with \ (e.g., \mv) bypass simple ^command\s anchors. Always add \\?:

    // Correct: catches both mv and \mv
    if (/^\\?mv\s/i.test(seg)) { ... }
    
    // Correct for rm (uses \b instead of \s)
    if (/^\\?rm\b/i.test(seg)) { ... }
    

    Known bypass surfaces (must document in adversarial tests)

    These are documented bypass vectors that the current regex-based approach cannot fully close. Every new guardrail section should include adversarial tests for these patterns:

    EvasionExampleStatusMitigation
    Backslash prefix\mv .swarm/fileCLOSEDAdd ^\\? to command anchor
    Quote splicingm'v' .swarm/fileOPENRequires NFKC normalization change
    Quoted command name"mv" .swarm/fileOPENRequires NFKC normalization change
    Shell wrapper (double-quoted)sh -c "mv .swarm/file"CLOSEDdcUnwrapWrappers handles "
    Shell wrapper (single-quoted)sh -c 'mv .swarm/file'OPENdcUnwrapWrappers regex uses "?
    Relative path prefixmv ./swarm/fileOPENRequires path normalization
    Env var expansionmv $SWARM_DIR/fileOPENRequires variable resolution
    Unicode fullwidthmv .swarm/fileOPENRequires NFKC normalization

    Regex anti-patterns (from prior bugs)

    Anti-pattern 1: [^-] consuming path characters

    // WRONG — [^-] consumes the first character of the path
    if (/^rm\s+(?!\s*-)(?!-)[^-].*\.swarm/i.test(seg)) {
      // "rm .swarm/file" → [^-] consumes '.' → "swarm/file" doesn't match "\.swarm"
    }
    
    // CORRECT — use negative lookahead for flag exclusion
    if (
      /^rm\b/i.test(seg) &&
      !/^rm\s+(?:-[a-zA-Z]*[rR][a-zA-Z]*|--recursive)\b/i.test(seg) &&
      /\.swarm(?:[\x5c/\s]|$)/i.test(seg)
    ) {
      // "rm .swarm/file" → BLOCKED ✓
      // "rm -rf .swarm/" → Section 3 handles ✓
      // "rm -v .swarm/file" → BLOCKED ✓
    }
    

    Anti-pattern 2: Negative lookahead too broad ((?!-\S))

    // WRONG — (?!-\S) excludes ALL flag-prefixed rm commands,
    // but Section 3 only catches recursive/force flags
    if (/^rm\s+(?!-\S).*\.swarm/i.test(seg)) {
      // "rm -v .swarm/file" → NOT blocked by S19 (excluded by lookahead)
      // "rm -v .swarm/file" → NOT blocked by S3 (no -r/-f flags)
    }
    
    // CORRECT — use three-part condition
    

    Anti-pattern 3: .exec() confused by SAST

    // WRONG — SAST confuses RegExp.prototype.exec() with child_process.exec()
    const match = /^command\s+(.+)$/i.exec(seg);  // SAST false positive
    
    // CORRECT — use String.prototype.match()
    const match = seg.match(/^command\s+(.+)$/i);  // No SAST false positive
    

    Anti-pattern 4: Argument-order dependent patterns

    // WRONG — .swarm/ must appear AFTER the flag in the command string
    if (/^tool\b.*--flag\b.*\.swarm/i.test(seg)) {
      // "tool --flag .swarm/" → BLOCKED ✓
      // "tool .swarm/ --flag" → NOT BLOCKED ✗
    }
    
    // CORRECT — split flag check and path check
    if (/^tool\b.*--flag\b/i.test(seg) && /\.swarm(?:[\x5c/\s]|$)/i.test(seg)) {
      // Both argument orders BLOCKED ✓
    }
    

    Test conventions

    Test file structure

    // Positive tests: "command → BLOCKED"
    test('mv .swarm/evidence/file.json /tmp/ → BLOCKED', async () => { ... });
    
    // Negative tests: "command → ALLOWED (reason)"
    test('ls .swarm/evidence/ → ALLOWED (read-only)', async () => { ... });
    
    // Bypass when feature is disabled
    test('mv .swarm/file /tmp/ → ALLOWED when block_destructive_commands=false', async () => { ... });
    

    Test infrastructure pattern

    import { mkdtempSync, realpathSync } from 'node:fs';
    import { tmpdir } from 'node:os';
    import { join } from 'node:path';
    import { createGuardrailsHooks } from '../../../src/hooks/guardrails';
    import { resetSwarmState, startAgentSession } from '../../../src/state';
    
    const TEST_DIR = realpathSync(mkdtempSync(join(tmpdir(), 'guardrail-pattern-')));
    
    function defaultConfig(overrides?: Partial<GuardrailsConfig>): GuardrailsConfig {
      return {
        enabled: true,
        max_tool_calls: 200,
        max_duration_minutes: 30,
        idle_timeout_minutes: 60,
        max_repetitions: 10,
        max_consecutive_errors: 5,
        warning_threshold: 0.75,
        profiles: undefined,
        block_destructive_commands: true,
        ...overrides,
      };
    }
    
    function makeBashInput(sessionID = 'test-session', command: string) {
      // Note: command is accepted but passed to makeBashOutput, not makeBashInput
      return { tool: 'bash', sessionID, callID: 'call-1' };
    }
    
    function makeBashOutput(command: string) {
      return { args: { command } };
    }
    

    Required test categories

    Every new guardrail section MUST have tests for:

    1. Positive — command targeting .swarm/ is blocked
    2. Negative — same command with non-.swarm/ path is allowed
    3. Read-only — read-only commands (ls, cat, find) are not blocked
    4. Config bypass — verified unblocked when block_destructive_commands: false
    5. Platform variants — POSIX, Windows cmd, PowerShell forms where applicable
    6. Adversarial — documented bypass surfaces (one test per known evasion type)

    Key testing rules

    • Use bun:test only (no Jest/Vitest)
    • Use rejects.toThrow(/BLOCKED/) for positive assertions
    • Use resolves.toBeUndefined() for negative assertions
    • No hardcoded /tmp — use os.tmpdir() + mkdtempSync
    • No hardcoded C:\ strings
    • Wrap mkdtempSync in realpathSync for macOS compatibility

    Section pattern reference (current guardrail sections 1–22)

    | Section | Line | Commands blocked | Notes | |---|---|---|---|---| | 2 | ~1347 | Junction/symlink CREATION out-of-cwd | dcCheckJunctionCreation — creation of junctions/symlinks targeting outside cwd | | 3 | ~1353 | rm -r[Ff]*, rm -f -r, etc | Recursive + force only ([rRfF]+ flag set) | | 4 | ~1378 | rmdir /s, rd /s | Windows cmd, recursive | | 5 | ~1400 | del /s | Windows cmd | | 6–7 | ~1418 | Remove-Item -Recurse + pipeline form | PowerShell | | 8 | ~1457 | Ransomware-grade | vssadmin, wbadmin, diskpart, bcdedit, sdelete, fsutil, takeown, cipher, format, robocopy /MIR | | 9 | ~1510 | chmod -R 000, chattr +i, icacls /deny | Permission denial-of-service | | 10 | ~1529 | dd with /dev/zero/null/urandom | Data wipe | | 11 | ~1538 | Git destructive | push --force, reset --hard, reset --mixed, clean -fd, worktree remove --force | | 12 | ~1567 | rsync --delete(-before/-after/-during/-delay) | Mirror/sync with delete | | 13 | ~1576 | kubectl delete, docker system prune | Cluster/container | | 14 | ~1590 | DROP TABLE/DATABASE/SCHEMA, TRUNCATE TABLE | SQL DDL | | 15 | ~1604 | mkfs | Disk format | | 16 | ~1615 | mv | POSIX — blocked on .swarm/ | | 17 | ~1635 | move, ren | Windows cmd — blocked on .swarm\ | | 18 | ~1652 | Move-Item, Rename-Item, aliases | PowerShell — blocked on .swarm/ | | 19 | ~1667 | rm (non-recursive) | Blocked on .swarm/ (recursive → Section 3) | | 20 | ~1682 | cp + rm chain | Secondary defense (rm guard is primary) | | 21 | ~1697 | rsync --remove-source-files, tar --remove-files, zip -m, 7z -sdel | Archive tools with delete-source flags | | 22 | ~1728 | git clean -fd, git worktree remove --force | Verified existing patterns cover .swarm/ |

    Task checklist for adding a new guardrail block

    • Pattern chosen (A/B/C) and placed in correct section order
    • Command anchor includes ^\\? (backslash prefix)
    • .swarm path check uses (?:[\x5c/\s]|$) (whole-root + subpath)
    • Argument-order independent (split flag check from path check)
    • Platform variants covered (POSIX + cmd + PowerShell)
    • .exec().match() to avoid SAST false positives
    • Positive test: .swarm/ path blocked
    • Negative test: non-.swarm/ path allowed
    • Read-only test: read commands not blocked
    • Config bypass test: block_destructive_commands: false
    • Adversarial tests: document known bypasses
    • bun run build succeeds
    • bunx biome ci . clean
    • All guardrail test suites pass

    Frequently asked questions

    What to verify before installation and use

    What does the guardrail-patterns source document cover?

    Source knowledge: 098926ef, 2c1e4689, 54c33fa4, 4f51d11a

    How do I install guardrail-patterns?

    The source record exposes this install command: npx skills add https://github.com/ZaxbyHub/opencode-swarm --skill ".opencode/skills/generated/guardrail-patterns". Inspect the command and pinned source before running it.

    Which permission-related actions were detected?

    Static rules flagged exec-script in the source; the page lists the matching lines and excerpts.

    Alternatives

    Compare before choosing

    Computed 10045,511

    coreyhaines31/marketingskills

    ab-testing

    When the user wants to plan, design, or implement an A/B test or experiment, or build a growth experimentation program. Also use when the user mentions "A/B test," "split test," "experiment," "test this change," "variant copy," "multivariate test," "hypothesis," "should I test this," "which version is better," "test two versions," "statistical significance," "how long should I run this test," "growth experiments," "experiment velocity," "experiment backlog," "ICE score," "experimentation program

    Computed 10029,034

    garrytan/gbrain

    bulk-ingestion

    End-to-end discipline for turning any large data source (audio libraries, email takeouts, document corpora, chat exports, API dumps) into brain pages at scale. The lifecycle spine: SCHEMA → ACCESS → TRIAL → EVALUATE → IMPROVE → CODIFY → TEST → SKILLIFY → BULK → MONITOR. State is tracked in a durable JSON manifest (see MANIFEST-PATTERN.md) so any crash, session boundary, or subagent fan-out resumes from ground truth instead of memory.

    Computed 10024,921

    alirezarezvani/claude-skills

    app-store-optimization

    App Store Optimization (ASO) toolkit for researching keywords, analyzing competitor rankings, generating metadata suggestions, and improving app visibility on Apple App Store and Google Play Store. Use when the user asks about ASO, app store rankings, app metadata, app titles and descriptions, app store listings, app visibility, or mobile app marketing on iOS or Android. Supports keyword research and scoring, competitor keyword analysis, metadata optimization, A/B test planning, launch checklist

    Computed 1005,241

    dotnet/skills

    migrate-vstest-to-mtp

    Migrates .NET test projects from VSTest to Microsoft.Testing.Platform (MTP). Use when user asks to "migrate to MTP", "switch from VSTest", "enable Microsoft.Testing.Platform", "use MTP runner", set OutputType=Exe only for test projects in Directory.Build.props, or mentions EnableMSTestRunner, EnableNUnitRunner, or UseMicrosoftTestingPlatformRunner. USE FOR: MTP behavioral differences vs VSTest (exit code 8, zero tests discovered, --ignore-exit-code, TESTINGPLATFORM_EXITCODE_IGNORE); centralizing