agentleFS
QBall-IncQBall-Inc/the-bulwark/skills/bulwark-scaffold/SKILL.md

bulwark-scaffold

Skill8 starsChanged 5 months agoMITView on GitHub

Initialize Bulwark infrastructure in a project: language-aware Justfile (8 langs), bun + eval-framework toolchain, logs/ subdirectories, and optional hooks.

  • Pipes a download into a shell
  • Installs packages

The file

Show its rules and text

We split this skill into the rules it gives an agent

19 rules. About 0 are common, 5 are distinctive, and 14 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈5

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 14

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    If LANG_OVERRIDE is set, use that.

    line 82
  2. Very specific:

    No manifest above AND at least one *.sh file at project root or in scripts/ → shell

    line 90
  3. Very specific:

    If DRY_RUN is true, display preview and exit:

    line 188
  4. Very specific:

    If NOT SKIP_JUSTFILE:

    line 223
  5. Very specific:

    If DETECTED_LANG is one of node|python|rust|go|kotlin|swift|shell:

    line 227
  6. Very specific:

    If DETECTED_LANG is fallthrough (no manifest detected, no --lang override):

    line 230
  7. Very specific:

    Do NOT silently copy justfile-generic.just.

    line 231
  8. Distinctive:

    If option 8 (generic), print a warning before copying:

    line 253
  9. Very specific:

    Check if .gitignore exists and contains # Bulwark logs marker:

    line 277
  10. Distinctive:

    If marker exists: Skip (already configured)

    line 278
  11. Distinctive:

    If marker does not exist: Append the following patterns

    line 279
  12. Very specific:

    Check if .claude/settings.json exists:

    line 327
  13. Distinctive:

    If exists: Merge hooks into existing configuration (preserve other settings)

    line 328
  14. Distinctive:

    If not exists: Create new file

    line 329
  15. Very specific:

    Create parent directories as needed (mkdir -p).

    line 381
  16. Very specific:

    ONLY if WITH_PERMISSION_HOOK is true (the --with-permission-hook flag).

    line 385
  17. Very specific:

    If the user picks Skip (or declines): do NOT install.

    line 398
  18. Very specific:

    a. Idempotency check: If .claude/settings.json already registers bulwark-permission-hook.sh under PreToolUse, skip re-adding (set …

    line 402
  19. Very specific:

    Write diagnostic log to logs/diagnostics/bulwark-scaffold-{timestamp}.yaml:

    line 529

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Bulwark Scaffold

Initialize Bulwark infrastructure in a project by generating Justfile templates, creating the logs directory structure, and optionally configuring hooks.


Mandatory Execution Checklist (BINDING)

Every item below is mandatory. No deviations. No substitutions. No skipping. Skipping items violates SC1-SC3 (Skill Compliance Rules in Rules.md).

You are the orchestrator. Follow every item in order. Do NOT return to the user until all applicable items are checked.

  • Step 1 — Parse arguments: --force, --no-hooks, --with-permission-hook, --dry-run, --lang=<...> extracted from $ARGUMENTS
  • Step 2 — Detect project language: If --lang not supplied, project files inspected (package.json, pyproject.toml, Cargo.toml, go.mod, etc.); defaults to generic when no signal found
  • Step 3 — just runtime check: command -v just runs; if missing, follow Step 3 install path
  • Step 3.5a — bun runtime check: bash <resolved-installer-path> --verify invoked (NOT command -v bun — that bypasses version check); follow Step 3.5 install path if exit non-zero
  • Step 3.5b — Installer copy: scripts/install-bun.sh copied to ${CLAUDE_PROJECT_DIR}/scripts/ so Justfile recipes can reference it project-relatively
  • Step 3.6 — Existing Justfile check: If a Justfile is already present, abort unless --force (with backup created)
  • Step 4 — Dry-run check: If --dry-run, preview the planned writes and exit without modifying disk
  • Step 5 — Justfile generation: Template emitted from lib/templates/justfile-<lang>.just; bun + eval recipes (install-bun, verify-bun, eval-skill, eval-grade, eval) confirmed present in output
  • Step 6 — logs/ subdirectories: diagnostics/, validations/, debug-reports/ created
  • Step 7 — .gitignore: Bulwark log patterns appended idempotently
  • Step 8 — Hooks: If plugin-level hooks active, SKIP .claude/settings.json hook injection (anti-duplication)
  • Step 8a — Permission hook (opt-in): ONLY if --with-permission-hook — confirm trust (AskUserQuestion), merge PreToolUse entry into .claude/settings.json, copy bulwark-permission-hook.sh, record choice. Default (no flag) = NOT installed
  • Step 9 — Scaffold log: logs/scaffold-{ts}.yaml written with top-level reviewed_files: [...] (Stop-hook contract)
  • Step 10 — Report results: User-facing summary emitted listing files written, installer outcomes, and any skipped steps

Usage

/bulwark-scaffold [options]

Options:

  • --force - Overwrite existing Justfile (creates backup)
  • --no-hooks - Skip hook configuration (hooks are generated by default)
  • --with-permission-hook - Also install the opt-in PreToolUse permission-bypass hook (auto-approves Bulwark's own bundled-asset reads/edits/scripts). Default: NOT installed
  • --dry-run - Show what would be generated without writing files
  • --lang=<node|python|rust|go|kotlin|swift|shell|generic> - Override language detection

Examples:

  • /bulwark-scaffold - Full scaffold with Justfile + logs/ + hooks
  • /bulwark-scaffold --force - Overwrite existing Justfile
  • /bulwark-scaffold --no-hooks - Skip hook configuration
  • /bulwark-scaffold --with-permission-hook - Scaffold + install the opt-in permission-bypass hook
  • /bulwark-scaffold --dry-run - Preview changes

Execution Steps

Step 1: Parse Arguments

Extract options from $ARGUMENTS:

  • --force → FORCE_OVERWRITE=true
  • --no-hooks → SKIP_HOOKS=true
  • --with-permission-hook → WITH_PERMISSION_HOOK=true (default: false)
  • --dry-run → DRY_RUN=true
  • --lang=X → LANG_OVERRIDE=X

Step 2: Detect Project Language

If LANG_OVERRIDE is set, use that. Otherwise, search from current directory for manifest files in this order (first match wins):

  1. package.json → node
  2. pyproject.toml OR requirements.txt OR setup.py → python
  3. Cargo.toml → rust
  4. go.mod → go
  5. build.gradle OR build.gradle.kts OR any *.gradle.kts file → kotlin
  6. Package.swift → swift
  7. No manifest above AND at least one *.sh file at project root or in scripts/ → shell
  8. None of the above → fallthrough (do NOT silently default to generic; see Step 5)

Store result in DETECTED_LANG variable. If fallthrough, DETECTED_LANG=fallthrough (a marker value, not a template name).

Step 3: Verify just runtime

Pre-flight: Verify just is installed.

Run: command -v just

IF just is NOT found:
    Delegate the install attempt to scripts/install-just.sh — it detects the
    platform (macOS/WSL/Debian/RHEL/Windows) and uses the right package
    manager (brew/cargo/apt/dnf/winget/scoop) with cargo as primary for
    Linux. Does NOT use curl|bash.

    Locate the installer:
      - Plugin install: ${CLAUDE_PLUGIN_ROOT}/scripts/install-just.sh
      - Local dev:      ${CLAUDE_PROJECT_DIR}/scripts/install-just.sh

    Ask user: "just is required for the scaffolded Justfile. Install it now via scripts/install-just.sh (recommended) or skip Justfile generation?"
      - If install: Run `bash <installer-path>`
        - Exit 0: just installed → continue
        - Exit non-zero: installer already printed actionable per-platform
          instructions → set SKIP_JUSTFILE=true (do not re-print)
      - If skip: Set SKIP_JUSTFILE=true

    If the installer script cannot be located (rare — repo corruption):
        Print: "Could not find scripts/install-just.sh. Install just manually:"
        Print: "  macOS:   brew install just"
        Print: "  Linux:   cargo install just  (requires Rust: https://rustup.rs)"
        Print: "  Windows: winget install Casey.Just"
        Print: "  All:     https://just.systems/man/en/chapter_4.html"
        Set SKIP_JUSTFILE=true

Step 3.5: Verify bun runtime (eval framework + generated TS scripts)

Pre-flight: Verify bun is installed (required for create-skill eval framework + generated archetype scripts).

1. Locate the source installer (prefer plugin install path; fall back to local-dev):
     - Plugin install: ${CLAUDE_PLUGIN_ROOT}/scripts/install-bun.sh
     - Local dev:      ${CLAUDE_PROJECT_DIR}/scripts/install-bun.sh
   IF neither path exists (rare — repo corruption):
       Print: "Could not find scripts/install-bun.sh. Install bun manually:"
       Print: "  macOS:   brew install oven-sh/bun/bun"
       Print: "  Linux:   curl -fsSL https://bun.sh/install | bash"
       Print: "  Windows: powershell -c \"irm bun.sh/install.ps1 | iex\""
       Print: "  Docs:    https://bun.sh/docs/installation"
       Set SKIP_BUN_FEATURES=true
       Skip the rest of Step 3.5

2. Copy the installer into the project so the Justfile recipes can reference
   it project-relatively (the templates use `./scripts/install-bun.sh`):
     mkdir -p ${CLAUDE_PROJECT_DIR}/scripts
     cp <resolved-installer-path> ${CLAUDE_PROJECT_DIR}/scripts/install-bun.sh
     chmod +x ${CLAUDE_PROJECT_DIR}/scripts/install-bun.sh
   (Idempotent — overwriting any prior copy ensures the project mirrors the
   currently-installed plugin version.)

3. Run the verify probe with the project-local path (NOT `command -v bun`,
   which would bypass version checks performed by the installer):
     bash ${CLAUDE_PROJECT_DIR}/scripts/install-bun.sh --verify

4. IF bun is NOT found OR version < 1.0 (verify exit non-zero):
     Ask user: "bun is required for the create-skill eval framework and generated TS scripts. Install it now via scripts/install-bun.sh (recommended) or skip eval-framework features?"
       - If install: Run `bash ${CLAUDE_PROJECT_DIR}/scripts/install-bun.sh`
         - Exit 0: bun installed → continue
         - Exit non-zero: installer already printed actionable per-platform
           instructions → set SKIP_BUN_FEATURES=true (do not re-print)
       - If skip: Set SKIP_BUN_FEATURES=true; user can install later via `just install-bun`

5. IF bun is found (verify exit 0):
     Continue (no install needed; idempotent verify).

When bun is verified or installed AND the templates have been emitted, the recipes just install-bun, just verify-bun, just eval-skill, just eval-grade, and just eval are runnable. The first two delegate to the project-local scripts/install-bun.sh (copied in step 2); the eval recipes run TS scripts under skills/create-skill/scripts/ via bun. When SKIP_BUN_FEATURES=true, the scaffold continues but the user is informed those features will fail until just install-bun runs successfully.

The bun check is parallel to the just check (Step 3) — both are runtime installers; both follow the same locate-then-execute pattern; both have actionable manual fallbacks.

Step 3.6: Check for existing Justfile

IF Justfile exists AND NOT FORCE_OVERWRITE:
    Print: "Justfile already exists. Use --force to overwrite (creates backup)."
    Set SKIP_JUSTFILE=true
ELSE IF Justfile exists AND FORCE_OVERWRITE:
    Create backup: Justfile.backup-{YYYYMMDD-HHMMSS}
    Set SKIP_JUSTFILE=false
ELSE:
    Set SKIP_JUSTFILE=false

Step 4: Dry Run Check

If DRY_RUN is true, display preview and exit:

## Scaffold Preview (dry-run)

**Language detected:** {DETECTED_LANG} ({manifest file or "no manifest"})

**Would create:**
- Justfile (from `lib/templates/justfile-{RESOLVED_TEMPLATE}.just` — substitute the actual filename, e.g., `justfile-go.just`, NOT the interpolation placeholder)
- logs/
- logs/diagnostics/
- logs/validations/
- logs/debug-reports/
{IF NOT SKIP_HOOKS}
- .claude/settings.json (hooks configuration)
- .claude/skills/governance-protocol/SKILL.md
- scripts/hooks/inject-protocol.sh
- scripts/hooks/enforce-quality.sh
- scripts/hooks/suggest-pipeline-stop.sh
{ENDIF}
{IF WITH_PERMISSION_HOOK}
- scripts/hooks/bulwark-permission-hook.sh
- .claude/settings.json (PreToolUse permission-bypass entry — merged independently of --no-hooks)
{ENDIF}

**Would update:**
- .gitignore (add Bulwark patterns)

Run without --dry-run to apply changes.

Then STOP execution.

Step 5: Generate Justfile

If NOT SKIP_JUSTFILE:

Template selection:

If DETECTED_LANG is one of node|python|rust|go|kotlin|swift|shell:

  • TEMPLATE_NAME = justfile-{DETECTED_LANG}.just

If DETECTED_LANG is fallthrough (no manifest detected, no --lang override):

  • Do NOT silently copy justfile-generic.just. The generic template is now fail-loudly (every recipe exits 1 with an "unconfigured" error), so handing it to the user without explicit consent produces a broken-looking Justfile.
  • Prompt the user:
    No language manifest detected and no --lang override provided.
    
    Choose a language template:
      1) node     - eslint + tsc + vitest recipes
      2) python   - ruff + mypy + pytest recipes
      3) rust     - cargo fmt + clippy + test recipes
      4) go       - go vet + golangci-lint + gofmt recipes
      5) kotlin   - ktlint + detekt recipes
      6) swift    - swiftlint + swift-format recipes
      7) shell    - shellcheck + shfmt recipes
      8) generic  - placeholder Justfile that FAILS LOUDLY on every recipe
                    (use only if you will hand-edit it immediately)
      9) cancel   - skip Justfile generation
    
    Select [1-9]:
  • Record the user's choice in DETECTED_LANG. If option 9, set SKIP_JUSTFILE=true.
  • If option 8 (generic), print a warning before copying:
    WARNING: The generic Justfile fails every recipe with exit 1 by design.
    You must either (a) pick a language and re-run scaffold, or
    (b) replace the `_not_configured` recipe calls with real tool invocations
    before running `just <recipe>`.
  • Then TEMPLATE_NAME = justfile-{DETECTED_LANG}.just (with the user's choice).

Copy template:

  1. Locate template: ${CLAUDE_PLUGIN_ROOT}/lib/templates/{TEMPLATE_NAME}
    • For local development: ${CLAUDE_PROJECT_DIR}/lib/templates/{TEMPLATE_NAME}
  2. Copy template content to Justfile in project root

Step 6: Create logs/ Directory Structure

mkdir -p logs/diagnostics logs/validations logs/debug-reports
touch logs/.gitkeep logs/diagnostics/.gitkeep logs/validations/.gitkeep logs/debug-reports/.gitkeep

Step 7: Update .gitignore

Check if .gitignore exists and contains # Bulwark logs marker:

  • If marker exists: Skip (already configured)
  • If marker does not exist: Append the following patterns

Patterns to add:


# Bulwark logs
logs/*.yaml
logs/*.log
logs/diagnostics/*.yaml
logs/validations/*.yaml
logs/debug-reports/*.yaml
!logs/.gitkeep
!logs/*/.gitkeep

Step 8: Generate Hook Configuration (Default)

UNLESS SKIP_HOOKS is true:

Pre-flight: Check for existing Bulwark hooks to prevent duplication.

Plugin hooks (hooks/hooks.json) and settings hooks (.claude/settings.json) both fire at runtime. If hooks already exist in any location, adding them again causes double execution.

Check these locations for existing Bulwark hooks (search for enforce-quality or inject-protocol):

LocationScopeNotes
./hooks/hooks.jsonProject pluginBulwark installed as project-level plugin
~/.claude/plugins/*/hooks/hooks.jsonUser pluginBulwark installed at user level via /install
.claude/settings.jsonProject settingsPreviously scaffolded
.claude/settings.local.jsonProject localUser-specific project overrides
~/.claude/settings.jsonUser settingsGlobal user hooks
~/.claude/settings.local.jsonUser localGlobal user overrides
HOOKS_FOUND_IN = []

FOR each location above:
    IF file exists AND contains "enforce-quality" OR "inject-protocol":
        Append location to HOOKS_FOUND_IN

IF HOOKS_FOUND_IN is not empty:
    Print: "Bulwark hooks already present in: {HOOKS_FOUND_IN}. Skipping hook generation to prevent duplication."
    Set SKIP_HOOKS=true

If no existing hooks found, proceed with hook generation:

Check if .claude/settings.json exists:

  • If exists: Merge hooks into existing configuration (preserve other settings)
  • If not exists: Create new file

Hook configuration to add:

{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PROJECT_DIR}/scripts/hooks/inject-protocol.sh",
            "timeout": 5
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PROJECT_DIR}/scripts/hooks/enforce-quality.sh",
            "timeout": 60
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PROJECT_DIR}/scripts/hooks/suggest-pipeline-stop.sh",
            "timeout": 30
          }
        ]
      }
    ]
  }
}

Note: SessionStart has no matcher, so it fires for all session events (start, resume, clear, compact). The Stop hook fires once at Claude turn end and emits a single consolidated pipeline-suggestion block per turn (mirrors the plugin's own hooks/hooks.json). Do NOT install the deprecated suggest-pipeline.sh — it emits per-edit blocks and causes the hook storm P10.1 fixes.

Also copy required files (only if hooks were generated above):

  1. Copy scripts/hooks/inject-protocol.sh to ${CLAUDE_PROJECT_DIR}/scripts/hooks/
  2. Copy scripts/hooks/enforce-quality.sh to ${CLAUDE_PROJECT_DIR}/scripts/hooks/
  3. Copy scripts/hooks/suggest-pipeline-stop.sh to ${CLAUDE_PROJECT_DIR}/scripts/hooks/
  4. Copy skills/governance-protocol/SKILL.md to ${CLAUDE_PROJECT_DIR}/.claude/skills/governance-protocol/SKILL.md

Create parent directories as needed (mkdir -p).

Step 8a: Optional Permission-Bypass Hook (opt-in)

ONLY if WITH_PERMISSION_HOOK is true (the --with-permission-hook flag). Default (no flag) → SKIP this entire step; the permission hook is NOT installed and nothing below runs. Set PERMISSION_HOOK=not_requested and continue to Step 9.

This installs bulwark-permission-hook.sh as a project-scope PreToolUse hook that auto-approves Read/Edit/Bash operations on Bulwark's own bundled assets — skipping the per-file permission prompts CC raises on plugin-bundled files the user already trusted at install. It is a scoped workaround for upstream CC permission bugs (retire when #29285 lands; see docs/reference/hooks.md).

Runs independently of SKIP_HOOKS — a user may pass --no-hooks --with-permission-hook (no governance hooks, but yes permission-bypass). If Step 8 was skipped and .claude/settings.json does not exist, create it here.

1. Confirm the trust decision (REQUIRED — security-sensitive). Installing a permission-bypass hook is a trust decision, so confirm explicitly even though the flag was passed. Use AskUserQuestion:

Install the Bulwark permission-bypass hook? It auto-approves Read/Edit/Bash on Bulwark's own bundled assets (under the plugin cache root / ${CLAUDE_PLUGIN_ROOT}), so you stop seeing permission prompts for them. Everything else still prompts as normal. Writes are never auto-approved. Path-traversal that escapes the plugin root is denied. Requires trusting Bulwark at install level.

Options: Install / Skip

If the user picks Skip (or declines): do NOT install; set PERMISSION_HOOK=declined; continue to Step 9.

2. On Install:

a. Idempotency check. If .claude/settings.json already registers bulwark-permission-hook.sh under PreToolUse, skip re-adding (set PERMISSION_HOOK=already_present) and proceed to step (c) to ensure the script copy exists.

b. Merge the PreToolUse entry into .claude/settings.json (create the file and/or the hooks key if absent; preserve all existing settings — same merge discipline as Step 8):

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Read|Edit|Bash",
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PROJECT_DIR}/scripts/hooks/bulwark-permission-hook.sh",
            "timeout": 5
          }
        ]
      }
    ]
  }
}

c. Copy the hook script: copy scripts/hooks/bulwark-permission-hook.sh to ${CLAUDE_PROJECT_DIR}/scripts/hooks/ and ensure it is executable (chmod +x). Create parent dirs with mkdir -p.

d. Set PERMISSION_HOOK=installed.

Why there is no env-var gate in the project entry: the hook self-gates on $CLAUDE_PLUGIN_OPTION_ENABLE_PERMISSION_BYPASS, but project-scope installs do not set that var — the script treats an unset gate as active (bulwark-permission-hook.sh opt-in gate), so the entry's presence in settings.json IS the opt-in. (The env-var gate only matters for the plugin-level install, which defaults it to false.)

3. Record the choice in the scaffold log (Step 9): add scripts/hooks/bulwark-permission-hook.sh to reviewed_files when copied, and set actions.permission_hook.action to the PERMISSION_HOOK value.

Step 9: Write Scaffold Log

Write to logs/scaffold-{YYYYMMDD-HHMMSS}.yaml:

# Top-level — required for Stop-hook per-file pipeline-recursion suppression.
# List every script/.sh file generated or copied during scaffolding (e.g. the
# project copy of install-bun.sh, any hook scripts copied to scripts/hooks/).
# Paths relative to ${CLAUDE_PROJECT_DIR}. Empty list `[]` if no script files
# were touched. Missing field disables suppression for this log (strict mode).
reviewed_files:
  - scripts/install-bun.sh
  - scripts/hooks/enforce-quality.sh

metadata:
  timestamp: {ISO-8601}
  action: scaffold
  invocation: "/bulwark-scaffold {args}"

detection:
  # language must be one of: node | python | rust | go | kotlin | swift | shell | generic | fallthrough
  language: {DETECTED_LANG}
  manifest: {manifest path or null}
  override: {LANG_OVERRIDE or null}
  user_selected: {true|false}  # true if user picked a language at the fallthrough prompt

actions:
  justfile:
    action: created|skipped|overwritten
    backup: {backup path or null}
    # template filename resolves to one of:
    #   justfile-node.just | justfile-python.just | justfile-rust.just
    #   justfile-go.just | justfile-kotlin.just | justfile-swift.just
    #   justfile-shell.just | justfile-generic.just
    template: lib/templates/justfile-{RESOLVED_TEMPLATE}.just
  logs_directory:
    created: true
    subdirectories: [diagnostics, validations, debug-reports]
  gitignore:
    action: created|updated|skipped
    patterns_added: 7
  hooks:
    action: created|merged|skipped
    path: .claude/settings.json
    skipped_reason: {reason if skipped}
  permission_hook:
    # --with-permission-hook opt-in (Step 8a). not_requested when the flag is absent.
    action: installed|declined|already_present|not_requested
    path: .claude/settings.json
    script: scripts/hooks/bulwark-permission-hook.sh

summary: |
  Scaffold complete for {DETECTED_LANG} project.

Step 10: Report Results

Present summary to user:

## Scaffold Complete

**Language:** {DETECTED_LANG}
**Justfile:** {created|skipped|overwritten (backup: path)}
**logs/:** Created with subdirectories (diagnostics, validations, debug-reports)
**.gitignore:** {updated|created|unchanged}
**Hooks:** {created|merged|skipped (--no-hooks)}
**Permission hook:** {installed|declined|already present|not installed}
**Governance:** {installed|skipped} - Protocol injected at session start

Run `just` to see available recipes:
- `just typecheck` - Run type checker
- `just lint` - Run linter
- `just build` - Build project
- `just test` - Run tests
- `just ci` - Run all quality checks
- `just fix` - Auto-fix issues

Error Handling

ScenarioAction
Cannot detect languagePrompt user to pick from the Step 5 menu. Do NOT silently default to generic — it produces a fail-loudly Justfile by design.
Invalid --lang valuePrint: "Invalid --lang. Use one of: node, python, rust, go, kotlin, swift, shell, generic" and exit.
Template file missingPrint: "Template not found at {path}. Bulwark installation may be corrupted."
Cannot create logs/Print: "Cannot create logs/ directory. Check permissions."
.gitignore write failsPrint warning, continue with other operations
Justfile backup failsPrint error, abort Justfile generation

Diagnostic Output

Write diagnostic log to logs/diagnostics/bulwark-scaffold-{timestamp}.yaml:

# Top-level — mirror the same list emitted in the scaffold report (Stop hook contract).
reviewed_files:
  - scripts/install-bun.sh
  - scripts/hooks/enforce-quality.sh

skill: bulwark-scaffold
timestamp: {ISO-8601}
invocation: "{full command}"
inputs:
  force: {true|false}
  no_hooks: {true|false}
  with_permission_hook: {true|false}
  dry_run: {true|false}
  lang_override: {value or null}
detection:
  language: {detected}
  manifest_path: {path or null}
outputs:
  justfile_created: {true|false}
  logs_created: {true|false}
  gitignore_updated: {true|false}
  hooks_configured: {true|false}
  permission_hook_configured: {true|false}
errors: []

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.