Skip to main content
← Back to list
01Issue
FeatureClosedSwamp CLITeam
AssigneesNone

Relationships

#1075 Add swamp straitjacket: opt-in, binary-shipped agent guardrail hooks

Opened by webframp · 7/10/2026

Problem

When an AI agent drives swamp, it repeatedly reaches for the wrong tool. It pipes --json output through jq/grep/awk/head to slice results, or shells out to glab/gh/curl/inline HTTP for data a model already provides, instead of using CEL queries and model methods. This is exactly the behavior swamp's whole design argues against: observe through the model, don't bypass it.

Today the only way to enforce that is hand-written host-agent hooks (for example, Claude Code PreToolUse hooks) maintained per user and per machine. Those are unversioned, undiscoverable, drift as swamp's data shapes evolve, and every team reinvents them from scratch. There is no first-class, shippable way to ship the discipline alongside the tool.

Proposed solution

Ship a curated set of agent guardrail hooks with the binary, the same way skills ship with the binary, installed opt-in through an in-process command. Working name: straitjacket.

Install as a thin shim; keep the logic in the binary.

  • swamp straitjacket install writes a one-line shim into the host agent's hook config (e.g. Claude Code .claude/settings.json PreToolUse), project-level so it travels with the repo. The shim is just swamp hook exec pre-tool-use.
  • All rule logic lives in the binary and upgrades with it. No copied scripts to drift.
  • swamp straitjacket status lists active rules and their current modes.
  • Because the logic runs in-process, a blocked command can name the exact CEL query or model method that replaces it: the binary has the model registry in hand.

Compose rules from two sources.

  • Core built-ins: no-shell-parsing (block jq/yq and swamp ... | <slicer>), anti-bypass (block glab/gh/curl/inline-HTTP fetches for data a model exposes), no-inline-exec, verify-before-destructive.
  • Extension-contributed: an installed extension declares its own hooks (e.g. a GitLab extension blocks glab api; a cloud extension blocks raw CLI calls where a model exists). The straitjacket aggregates core plus every installed extension's rules.

Per-rule enforcement with an optional ramp.

  • Each rule has a mode: off | warn | block, configured in a checked-in straitjacket.yaml. Each rule ships a sensible default; a newly added rule can ship as warn so it does not ambush anyone.
  • A rule may optionally declare a warn -> block ramp with a trigger: a date, a swamp version, or an observed-warning count. Teams set everything to warn on adoption and let each rule harden on its own timeline instead of flipping the whole thing at once.
  • A logged escape hatch (env var, e.g. SWAMP_STRAITJACKET=off) covers the rare genuine one-off.
# .swamp/straitjacket.yaml (checked in, travels with the repo)
straitjacket:
  defaults: { mode: block }
  bypass:   { env: SWAMP_STRAITJACKET }   # =off -> one invocation, logged
  rules:
    no-shell-parsing:
      mode: block
    anti-bypass:
      mode: warn
      ramp: { to: block, after: "2026-08-01" }   # or afterVersion / afterWarnings
    gitlab/no-glab-api:        # contributed by an installed extension
      mode: warn               # slow-walk an extension's rule locally

Host scope. Start with Claude Code as the first host, but keep the internal rule representation host-agnostic so other agents (and their hook mechanisms) can be added without rewriting the rules.

Alternatives considered

  • Hand-written host-agent hooks (status quo): unversioned, per-user, drift, every team reinvents them.
  • Documentation or skill guidance only: agents ignore prose under pressure; there is no enforcement.
  • Generated standalone scripts written into the repo: transparent and hackable, but drift from the binary and need a re-sync step. Could be offered later as swamp straitjacket eject <rule> for users who want to fork a specific rule while leaving the rest as thin shims.
  • Multi-agent host support from day one: more surface than needed initially; better to ship Claude Code first behind a host-agnostic rule spec.
02Bog Flow
OPENTRIAGEDIN PROGRESSCLOSED

Closed

7/10/2026, 11:30:59 PM

No activity in this phase yet.

03Sludge Pulse
Editable. Press Enter to edit.

stack72 commented 7/10/2026, 11:30:58 PM

@webframp — thanks for the thorough writeup, this is clearly well thought through.

We've decided not to take this on. The core reason: swamp is the primitive that lets agents work with your data and models. How an agent host enforces discipline — what it blocks, what it warns on, how it ramps rules — is a concern that belongs to the host, not to us.

The pain point you're describing is real. Agents absolutely do reach for jq and curl when they should be using CEL queries and model methods. But the right fix is better skills, better model discoverability, and clearer method signatures — making the right path obvious so agents naturally follow it. Not an enforcement layer bolted onto swamp.

If we ship straitjacket, we're taking on a rule engine, per-host hook integrations, ramp/scheduling logic, extension-contributed rules, and a config format — all to govern how a different tool calls us. That's a large ongoing surface area in a direction orthogonal to what swamp actually does. And it opens the door to an endless stream of "can you add rule X for host Y" requests that we'd have to either maintain or decline one by one.

Teams that want this today can write their own Claude Code hooks (or equivalent for their agent host) — it's a few lines of config, and they have full control over what to block and when. That's the right layer for this kind of enforcement to live.

That said, the underlying problem is worth addressing from our side. I've filed #1078 to research how we can improve our skills and documentation so that agents are guided toward the right patterns in the first place — making the correct path the path of least resistance, rather than trying to fence off the wrong ones.

Sign in to post a ripple.