[READ-ONLY] Mirror of https://github.com/andrioid/pi-fence. Fence wrapper for Pi coding agent. Wraps bash calls and intercepts reads/writes according to fence config
1/**
2 * Pi-fence starter `fence.jsonc` template.
3 *
4 * This is a vendored, opinionated baseline that pi-fence scaffolds into
5 * project roots that have no existing fence config. It is intentionally
6 * self-contained (no `extends`) because fence's slice-merge semantics
7 * are append-only — a child config cannot remove inherited rules. The
8 * only way to express "I want code's allowlist but a *narrower*
9 * denyWrite" is to author the policy from scratch.
10 *
11 * What this template is, relative to fence's built-in `code`:
12 *
13 * - Same network allowlist + deniedDomains, plus the language-toolchain
14 * CDNs that fence's `code` doesn't carry today (mise infra, nodejs.org,
15 * dl.google.com, hashicorp, rust). These cover the most common
16 * `mise install <runtime>@<ver>` workflows.
17 *
18 * - Same `allowWrite` set, plus `~/Library/Caches/**`. mise on macOS
19 * resolves its cache to `~/Library/Caches/mise/` (platform dirs
20 * convention); without this every install fails with EPERM mid-tar.
21 *
22 * - Same `denyRead` (secret/credentials carve-out). Unchanged.
23 *
24 * - **denyWrite scoped to the project tree (`./**\/...`)** instead of
25 * `**\/...`. Same security signal — agent can't write `.env`,
26 * `*.pem`, `*.key` into the repo — but no longer false-positives on
27 * tarball test fixtures (Go stdlib, Node source, npm packages with
28 * test certs) extracted into ~/.local/share, /tmp, or any cache dir.
29 *
30 * - Same `command.deny` list (git push, npm publish, sudo, gh ...).
31 * Unchanged.
32 *
33 * When fence's `code` template gains new rules upstream, this file needs
34 * a manual resync. Diff against `fence config show --template code | jq -S .`
35 * and update accordingly. Bumped versions of pi-fence may ship with a
36 * refreshed template; users who want to follow upstream more closely can
37 * delete their project `fence.jsonc` and let pi-fence re-scaffold (or
38 * change the file to `extends: "code"` and accept the mise/npm gaps).
39 *
40 * Pi-fence source-of-truth diff is recorded in PLAN.md §"Starter template".
41 */
42
43/**
44 * The literal JSONC content pi-fence writes when scaffolding. We keep
45 * comments in the on-disk file so users can read what each section does
46 * without leaving their editor — that's why this is a string and not a
47 * structured object piped through JSON.stringify.
48 *
49 * Trailing newline is intentional (POSIX text-file convention).
50 */
51export const STARTER_TEMPLATE = `// fence.jsonc — pi-fence starter policy.
52//
53// Scaffolded by pi-fence. Edit freely; pi-fence will not overwrite it.
54// Reference: https://github.com/Use-Tusk/fence/blob/main/docs/configuration.md
55//
56// Why this is self-contained instead of \`extends: "code"\`: fence's
57// \`code\` template carries a global \`denyWrite: ["**/*.pem", "**/*.key", ...]\`
58// that false-positives on language-toolchain extractions (e.g. Go's
59// crypto/tls/testdata/*.pem). Slice fields only append on extends, so
60// the only way to scope those denies to the project tree is to author
61// the full policy here. See pi-fence README §"Project scaffolding"
62// for the rationale and how this template differs from \`code\`.
63{
64 "$schema": "https://raw.githubusercontent.com/Use-Tusk/fence/main/docs/schema/fence.schema.json",
65 "allowPty": true,
66
67 "network": {
68 "allowedDomains": [
69 // LLM providers
70 "api.openai.com",
71 "*.anthropic.com",
72 "api.githubcopilot.com",
73 "generativelanguage.googleapis.com",
74 "api.mistral.ai",
75 "api.cohere.ai",
76 "api.together.xyz",
77 "openrouter.ai",
78 "api.morphllm.com",
79 "*.amazonaws.com",
80 "opencode.ai",
81 "api.opencode.ai",
82 "ampcode.com",
83 "*.ampcode.com",
84 "*.factory.ai",
85 "api.workos.com",
86 "*.cursor.sh",
87 "data.charm.land",
88 "catwalk.charm.sh",
89 "*.githubcopilot.com",
90 "models.dev",
91
92 // Source hosting
93 "github.com",
94 "api.github.com",
95 "raw.githubusercontent.com",
96 "codeload.github.com",
97 "objects.githubusercontent.com",
98 "release-assets.githubusercontent.com",
99 "gitlab.com",
100
101 // Package registries
102 "registry.npmjs.org",
103 "*.npmjs.org",
104 "registry.yarnpkg.com",
105 "pypi.org",
106 "files.pythonhosted.org",
107 "crates.io",
108 "static.crates.io",
109 "index.crates.io",
110 "proxy.golang.org",
111 "sum.golang.org",
112 "formulae.brew.sh",
113
114 // Language toolchain CDNs (pi-fence additions over fence's "code")
115 "*.jdx.dev", // mise infrastructure (mise.jdx.dev, mise-versions.jdx.dev)
116 "nodejs.org", // node downloads (mise install node@...)
117 "dl.google.com", // go downloads (mise install go@...)
118 "static.rust-lang.org", // rust toolchains (mise install rust@...)
119 "releases.hashicorp.com" // terraform/vault/consul/...
120 ],
121 "deniedDomains": [
122 "169.254.169.254",
123 "metadata.google.internal",
124 "instance-data.ec2.internal",
125 "statsig.anthropic.com",
126 "*.sentry.io"
127 ],
128 "allowLocalBinding": true,
129 "allowLocalOutbound": true
130 },
131
132 "filesystem": {
133 // Reads are default-allow; only the listed paths are blocked.
134 // Common credential/secret stores — kept identical to fence "code".
135 "denyRead": [
136 "~/.ssh/id_*",
137 "~/.ssh/config",
138 "~/.ssh/*.pem",
139 "~/.gnupg/**",
140 "~/.aws/**",
141 "~/.config/gcloud/**",
142 "~/.kube/**",
143 "~/.docker/**",
144 "~/.pypirc",
145 "~/.netrc",
146 "~/.git-credentials",
147 "~/.cargo/credentials",
148 "~/.cargo/credentials.toml"
149 ],
150
151 // Writes are default-deny; only listed paths are writable.
152 "allowWrite": [
153 // Project + scratch
154 ".",
155 "/tmp",
156
157 // Generic caches
158 "~/.cache",
159 "~/.cache/**",
160 "~/Library/Caches/**", // macOS platform cache (mise, many tools) — pi-fence addition
161
162 // Pi & sibling agent state dirs (so agents can persist their own state)
163 "~/.pi/**",
164 "~/.claude*",
165 "~/.claude/**",
166 "~/.amp",
167 "~/.codex/**",
168 "~/.cursor/**",
169 "~/.opencode/**",
170 "~/.gemini/**",
171 "~/.factory/**",
172 "~/.copilot/**",
173 "~/.kiro/**",
174 "~/Library/Application Support/kiro-cli/**",
175
176 // XDG-ish state and share
177 "~/.local/state/**",
178 "~/.local/share/**",
179 "~/.config/**",
180
181 // Per-language tool dirs
182 "~/.npm/_cacache",
183 "~/.npm/_npx",
184 "~/.bun/**",
185 "~/.cargo/registry/**",
186 "~/.cargo/git/**",
187 "~/.cargo/.package-cache",
188
189 // Misc
190 "~/.zcompdump*"
191 ],
192
193 // Tripwires for "agent writing fresh secrets into the repo".
194 // Scoped to ./**/* so package-manager extractions outside the project
195 // (which legitimately ship test fixtures named *.pem / *.key) are not
196 // false-positived. Pi-fence's mandatory denies (extension/skill dirs,
197 // global fence config, audit log) are appended at runtime.
198 "denyWrite": [
199 "./**/.env",
200 "./**/.env.*",
201 "./**/*.key",
202 "./**/*.pem",
203 "./**/*.p12",
204 "./**/*.pfx"
205 ]
206 },
207
208 "command": {
209 "deny": [
210 // Destructive git
211 "git push",
212 "git reset",
213 "git clean",
214 "git checkout --",
215 "git rebase",
216 "git merge",
217
218 // Package publishing
219 "npm publish",
220 "pnpm publish",
221 "yarn publish",
222 "cargo publish",
223 "twine upload",
224 "gem push",
225
226 // Privilege
227 "sudo",
228
229 // gh — destructive / publishing / auth
230 "gh pr create",
231 "gh pr merge",
232 "gh pr close",
233 "gh pr reopen",
234 "gh pr review",
235 "gh pr comment",
236 "gh release create",
237 "gh release delete",
238 "gh repo create",
239 "gh repo fork",
240 "gh repo delete",
241 "gh issue create",
242 "gh issue close",
243 "gh issue comment",
244 "gh gist create",
245 "gh workflow run",
246 "gh api",
247 "gh auth login",
248 "gh secret set",
249 "gh secret delete",
250 "gh variable set",
251 "gh variable delete"
252 ],
253 "useDefaults": true
254 }
255}
256`;
257
258/**
259 * Stable identifier for the template version we last shipped. Bumped
260 * when STARTER_TEMPLATE changes meaningfully (new domain, new path).
261 *
262 * Currently unused at runtime; reserved for future "your scaffold is
263 * stale" lint warnings if pi-fence wants to nudge users to refresh
264 * after upstream `code` template additions.
265 */
266export const STARTER_TEMPLATE_VERSION = "2026.05.10";