Presets
Presets are bundled, curated rule sets that ship with the fencepost plugin (in presets/). Instead of copy-pasting allow/ask/deny rules for common tools, you import them by name and layer your own config on top.
Importing
Add a top-level import: list of bare preset names:
import:
- claude
- git
- kubernetes
default: ask
tools:
allow:
- Read
- Edit
Each name resolves to <presets-dir>/<name>.yaml. Presets deliberately do not set default — that belongs to your config.
How merging works
DEFAULT_CONFIG
+ preset[0] + preset[1] + ... (preset base, in import order)
+ your config (your rules win)
- Your config is resolved as usual (single file or
conf.d). - Every
import:entry is collected and the named presets are merged in listed order, starting from the built-in defaults, to form a preset base. - Your own config is merged on top.
Because your config is applied last, your rules layer over the presets and your default overrides theirs. Within list sections, preset and user rules are concatenated; tier precedence (deny > checks > ask > allow > default) then decides outcomes at evaluation time. See Config files → merge semantics.
Safety & resolution
- Names are sandboxed. A preset name must match
^[a-zA-Z0-9_-]+$. Anything with a path separator or.(e.g.../../etc/passwd) is rejected, soimport:can never escape the presets directory. - Typos never lock you out. An unknown or missing preset is logged at
warnand skipped — consistent with the fail-open posture for missing config. - One level deep. Nested imports (a preset importing another) are not processed.
- Lookup order for the presets directory:
$FENCEPOST_PRESETS_DIR(set by the plugin hook wrapper) →<binary dir>/../presets→<src>/../presets(development).
Imported preset paths show up in provenance, listed before your own files, so fencepost config and /audit show exactly which preset contributed each rule.
Bundled presets
Each preset has its own page, generated straight from the YAML in presets/ — what you see is exactly what you import.
📄️ Ansible
Normalises inventory and connection flags so rules match regardless of target, allows read-only and dry-run tooling, and asks before runs that change remote state.
📄️ Claude Code web tools
Allows Claude Code's network-reaching built-in tools (WebFetch and WebSearch), which the base claude preset leaves to your default decision. Import this when you want them allowed silently.
📄️ Claude Code
Sane defaults for Claude Code itself: allows the built-in tools so routine work doesn't prompt, and redirects /tmp paths to a per-session sandbox (/tmp/claude) so scratch files stay isolated.
📄️ Context7 (MCP)
Context7's documentation lookup tools (resolve-library-id, query-docs) are read-only, so they are allowed silently. The glob matches the tool names however the MCP server is namespaced in your install.
📄️ Filesystem
Read-only and inspection shell commands: directory listing, file viewing, and text processing. Mutating commands (rm, mv, chmod, ...) are deliberately excluded, and the destructive flags of find and sed are guarded.
📄️ GitHub CLI
Allows read-only inspection of repos, PRs, issues, runs and releases; asks before anything that writes to GitHub or changes local credentials; and guards the irreversible deletions.
📄️ Git
Allows everyday read/write porcelain, asks before destructive or history-rewriting operations, and guards force-pushes, hard resets and working-tree wipes.
📄️ Helm
Allows read-only and local operations (list, status, template, lint, diff), asks before anything that changes cluster state, and guards forced upgrades that can delete and recreate resources.
📄️ Helmfile
Allows the read-only diff/template workflow, asks before sync and apply, and guards a full destroy. Pairs well with the helm preset.
📄️ Kubernetes (kubectl)
Normalises away environment-specific flags (namespace, context, kubeconfig), allows read-only inspection, asks before mutating cluster state, and guards cascading or bulk deletes.
📄️ Playwright (MCP)
Browser inspection and navigation tools run silently, tools that interact with the page or reach the filesystem ask first, and the arbitrary code-execution tool is denied outright.
📄️ Python & JS safety
Inspects inline interpreter code (python -c, node -e, heredocs) and flags destructive operations the shell can't see: deletes and writes outside the sandbox, subprocess spawns, and dynamic execution. Pairs well with the claude preset, which defines the /tmp/claude sandbox.
📄️ Secrets protection
Blocks tool inputs that contain credentials and redacts secrets from tool outputs before they reach the model, using whichever of gitleaks, betterleaks, trufflehog, or detect-secrets is installed (gitleaks recommended). Without a scanner installed, scanning is skipped and a session-start warning explains how to enable it.
The claude preset in detail
The one most projects want. It makes routine work with Claude Code quiet:
Allows the built-in tools — Read, Glob, Grep, Edit, Write, NotebookEdit, TodoWrite, Task, ExitPlanMode, BashOutput, KillShell. Two deliberate exclusions:
Bashis absent — fencepost always routes Bash through the command pipeline, so listing it would do nothing.WebFetch/WebSearchare not allowed — they reach external services, so they fall through to yourdefault. Add theclaude-webpreset if you want them.
Enables the sandbox — turns on /tmp redirection and ships the structured rules that scope destructive ops to /tmp/claude.
A common starting point:
import:
- claude
- git
- kubernetes
default: ask
Generating rules for a new tool
Don't hand-write rules for a tool from memory — subcommands differ between versions. Two skills automate the method the bundled presets were built with:
/preset <tool>reads a tool's actual command surface (from the installed binary, or a connected MCP server's live tool list), classifies each command into allow / ask / deny, and merges the result into your own.claude/fencepost.yaml. It never setsdefault, and anything it's unsure about is left to fall through./contribute-preset <name>packages a rule set as a bundledpresets/*.yaml, updates the docs, validates it, and opens a pull request — the path the presets above came in through.