Skip to content
334 linesCodeBlameRaw
1---
2title: Guardrails
3description: What g1t's agents may reach, run, spend and take in a project's sandboxes, and how each rule is enforced.
4---
5
6Guardrails decide what g1t's agents may do in their sandboxes: which hosts
7a sandbox can reach, which commands the agent's harness refuses, and how
8much one run may cost and how long it may take. A workspace sets defaults,
9and each project can override them.
10
11They apply to every sandbox g1t starts for a project's agents (implement,
12revise, answer, catch up, review, plan, and replies to mentions). The
13sandboxes of its merge queue get the network list and the time cap; they
14build the queue's states, not an agent's work, so command rules and the
15cost cap do not apply to them. GitHub Actions jobs and deploy
16builds get the network list too, with what builds need added (see
17[builds](#builds)), and their own time limit. Merge checks are not covered;
18see [What is not covered](#what-is-not-covered). Every sandbox, whatever
19it runs, is watched for [mining](#abuse-and-mining).
20
21## Where to set them
22
23- **Workspace defaults**: the workspace's **Settings**, **Guardrails**.
24 Owners can change them; members can read them.
25- **A project's overrides**: the project's **Settings**, **Guardrails**.
26 People with the Admin [role](/guides/access-and-roles/) on
27 its repository can see and change them; the page is not shown to anyone
28 else.
29
30Every setting on a project's page starts as "As the workspace", which
31follows the workspace's default, whatever it is now. Choose a value to
32override it for that project only. Allowed domains, workflow-only domains
33and deny patterns add up: a project's are added to the workspace's, never
34instead of them.
35
36Changes apply to runs that start after you save. A run that is under way
37keeps the guardrails it started with.
38
39## Network
40
41With **Only allowed hosts** restricted (the default), a sandbox can reach:
42
43- g1t's own hosts, always: `g1t.sh`, `api.g1t.sh`, `models.g1t.sh` and
44 `mcp.g1t.sh`, for cloning, pushing, reporting and the model;
45- the package registries that are on (all of them by default):
46
47 | Registry | Hosts |
48 | --- | --- |
49 | npm and Yarn | `registry.npmjs.org`, `registry.yarnpkg.com`, `repo.yarnpkg.com` |
50 | PyPI | `pypi.org`, `files.pythonhosted.org` |
51 | crates.io and Rust toolchains | `crates.io`, `index.crates.io`, `static.crates.io`, `static.rust-lang.org` |
52 | Go module proxy | `proxy.golang.org`, `sum.golang.org` |
53 | GitHub downloads | `codeload.github.com`, `raw.githubusercontent.com`, `objects.githubusercontent.com` |
54
55- the domains you list: `api.stripe.com` allows exactly that host, and
56 `*.example.com` allows every subdomain of `example.com` (not
57 `example.com` itself; list both if you need both).
58
59`github.com` itself is not on the default list. A project with
60dependencies fetched with git from GitHub, rather than as archives, needs it
61listed.
62
63### How it is enforced
64
65This is enforced outside the sandbox, by Cloudflare Containers' outbound
66interception:
67
68- A restricted sandbox starts with no internet connection at all. Its DNS
69 resolves nothing on its own, and no protocol or port other than HTTP (80)
70 and HTTPS (443) has any route out: SSH, raw TCP and UDP connections fail.
71- Every HTTP and HTTPS request it makes is handed to g1t's runner Worker
72 before it leaves. The Worker forwards requests to allowed hosts and
73 answers every other with `403` and a line saying the host is not allowed
74 and where to allow it.
75- To see the host of an HTTPS request, the connection is re-encrypted with
76 a certificate the sandbox is given when it starts, which g1t adds to the
77 sandbox's trusted certificates (and points Node.js, Python, curl, Cargo
78 and git at). A program that brings its own fixed list of certificates and
79 ignores the system's cannot connect anywhere, allowed or not.
80
81Nothing running in the sandbox, root included, can change this: the rule
82is applied where the sandbox's traffic leaves it, not inside it.
83
84Each refused host appears once as a step of the run, such as
85`Blocked: example.com (not an allowed domain)`, on the run's page under
86**Agents**. If a run needs a host, allow it and start the work again.
87
88Setting **Only allowed hosts** to Open gives that project's sandboxes the
89whole internet, as before guardrails.
90
91### Builds
92
93GitHub Actions jobs and deploy builds reach the project's list, plus what
94real builds need, which no setting removes:
95
96- GitHub, where `uses:` actions, `actions/checkout`'s helpers and the
97 setup actions' downloads come from: `github.com`, `api.github.com`,
98 `codeload.github.com`, `objects.githubusercontent.com`,
99 `raw.githubusercontent.com`, `release-assets.githubusercontent.com`,
100 `ghcr.io`;
101- toolchains: `nodejs.org`, `go.dev`, `dl.google.com`,
102 `static.rust-lang.org`, `sh.rustup.rs`;
103- every package registry above, whatever the project turned on for its
104 agents, and RubyGems, Packagist, NuGet, Maven Central, Gradle and
105 Debian's mirrors;
106- container registries, for a job's own Docker Engine: Docker Hub
107 (`registry-1.docker.io`, `auth.docker.io` and the CDNs its layers come
108 from), `mirror.gcr.io`, Quay (`quay.io` and its CDNs), and Docker's
109 package repository, `download.docker.com`;
110- for deploy builds, Cloudflare's API, which the build uploads its app to.
111
112The repository itself is cloned from g1t, which is always reachable. A
113project whose guardrails set **Only allowed hosts** to Open runs its jobs
114and builds with an open network too.
115
116The containers a job starts with [Docker](/guides/actions/#docker), its
117services and its build steps share the job's network, so this list is
118theirs too: an image from another registry, or a build step that
119downloads from another host, needs that host allowed, as a step would.
120
121### Workflow-only domains
122
123Some hosts only a workflow should reach: the API a deploy uploads to, a
124release server, a package registry you publish to. Listing them under
125allowed domains would open them to agents as well. List them under
126**Workflow-only domains** instead, one per line:
127
128```
129api.cloudflare.com | deploy.yml | production
130uploads.example.com | release.yml, nightly.yml
131*.internal.example.com
132```
133
134| Part | |
135| --- | --- |
136| The domain | As for allowed domains: `example.com`, or `*.example.com` for its subdomains. |
137| Workflows | Workflow files by name, comma-separated, as they are in `.g1t/workflows/`. Left out: any workflow. |
138| Environments | The environments a job must name with `environment:`, comma-separated. Left out: any job. |
139
140A domain is reached only by:
141
142- jobs of the workflows and environments its line names;
143- in a run that is not of a pull request from a fork, which runs code
144 anyone could write.
145
146Agents, checks, the merge queue and deploy builds never reach these
147hosts, whatever the line says. A job that names its environment with an
148expression (`environment: ${{ inputs.target }}`) matches only lines with
149no environments.
150
151Workflow-only domains are set by the same people as the rest of the page:
152owners for the workspace's, Admin for a project's. Each change
153is recorded in the workspace's [audit log](/guides/audit-log/) as
154`update_guardrails`, saying which domains were added or removed and what
155they were limited to.
156
157## Commands
158
159The agent's harness checks every tool call the agent makes before it runs.
160A refused call does not run; the agent is told it was refused and why, and
161the run shows a step such as
162`Denied: Ran git push --force origin feature (no force-pushing)`.
163
164Built-in rules, each on by default:
165
166| Rule | What it refuses |
167| --- | --- |
168| No force-pushing | `git push` with `--force`, `-f`, `--force-with-lease`, `--mirror`, `--delete` or `--prune`, a `+` refspec, or `:branch` to delete one. |
169| No rewriting the default branch | Pushing to the default branch, `git branch -f/-d/-D/-m/-M` on it, `git update-ref` of it, and `git filter-branch`, `git filter-repo` and `git replace`. |
170| No reading files outside the project | File tools (read, edit, write, search) outside the checked-out project, `/tmp`, and dependency caches (Cargo's registry and git checkouts, Go's module cache, Rust toolchains). Shell commands that touch g1t's own files in the sandbox, or other processes' environments under `/proc`. |
171| No printing the environment | `env` and `printenv`, `export -p`, `set` and `declare -p` on their own, `compgen -e`, reading `/proc/*/environ`, and any command that reads a variable whose name contains `TOKEN`, `KEY`, `SECRET`, `PASSWORD`, `CREDENTIAL` or `AUTH`. |
172| No sudo | `sudo`, `su`, `doas` and `pkexec`. With this on, the sandbox also gives up root before the agent starts, so nothing the agent runs can become root. |
173
174**Also refuse** adds your own rules, one per line, written as permission
175rules:
176
177- `Bash(terraform apply:*)` refuses any shell command that starts with
178 those words, wherever it appears in a line (`cd infra && terraform
179 apply` too). `Bash(rm -rf *)` uses `*` as a wildcard; `Bash(make deploy)`
180 refuses exactly that command.
181- `Read(secrets/**)`, `Edit(//etc/**)`: file paths. `//` starts at the
182 root, `~/` at the home directory, anything else at the project. `**`
183 crosses directories, `*` does not. `Read` covers reading and searching;
184 `Edit` covers every tool that writes a file.
185- `WebFetch(domain:example.com)` refuses fetching that domain and its
186 subdomains.
187- A tool's name on its own, such as `WebSearch`, refuses the tool.
188- Plain text is the start of a shell command: `kubectl delete` is saved as
189 `Bash(kubectl delete:*)`.
190
191### How it is enforced
192
193The rules are written into the harness's managed settings, which no
194settings file in the project or the home directory can override, as a hook
195the harness runs before every tool call and as its permission rules. With
196**No sudo** on, the sandbox then gives up root, so the agent cannot edit
197them or the program the hook runs.
198
199This is a guard against an agent's mistakes, not a sandbox against a
200determined one. Shell commands are matched as text, and a command can
201always be written in a way no rule foresees (built up from variables, or
202run from a script the agent wrote). The hard boundaries are elsewhere:
203
204- The network list, enforced outside the sandbox.
205- The sandbox's credentials. The agent itself holds none of g1t's: the
206 runner clones and pushes with credentials passed per command, and pushes
207 only to the run's own fork or branch, never with force. See
208 [credentials](/guides/working-with-g1t/#credentials).
209- Branch protection on the repository, which g1t enforces when a push
210 arrives, whatever the sandbox did.
211
212### Changes from forks
213
214When a run checks out a fork's head (revising, reviewing or answering on
215any pull request from a fork, including g1t's own, and replying to a
216mention on one), the harness loads nothing from that checkout: no
217`CLAUDE.md`, no `.claude/settings.json` or `settings.local.json` (so none
218of their hooks or permissions), no `.mcp.json` servers, and no commands or
219skills. g1t's guardrails, its tools and the repository's instructions from
220its own branches still apply. The run's session says so at the start. This
221follows the rule g1t uses for
222[repository instructions](/guides/working-with-g1t/#repository-instructions):
223they are read from the repository's own branches, never from a fork.
224
225## Caps
226
227**Cost per run**: the most one run may spend on its model, in US dollars.
228$2.00 by default, the same as the workspace billing's spend cap per run;
2290 means no cap here, though billing's cap still applies; at most $100. The
230harness tracks the run's spend as it goes and stops the agent when it
231reaches the cap.
232
233**Time per run**: how long each kind of run may take, in minutes. By
234default:
235
236| Kind of run | Minutes |
237| --- | --- |
238| Implement | 90 |
239| Revise | 60 |
240| Catch up | 45 |
241| Review | 30 |
242| Plan | 30 |
243| Answer | 20 |
244| Checks | 45 |
245| Merge queue | 45 |
246| Merge check | 10 |
247
248At most 240 minutes, but a run's credentials last two hours, so a longer
249cap does not give an agent more than that to push.
250
251**The workspace's billing** sets caps too. Every workspace has a spend cap
252per run, $2 by default, which owners can set from $0.10 to $100, so a run
253stops at $2 unless an owner raises it (see
254[caps](/guides/usage-and-billing/#caps)). A new paid workspace's first
255month, and the trial, also cap every run's time at 60 minutes (see
256[who can run agents](/guides/working-with-g1t/#who-can-run-agents)). A run gets
257the lower of its guardrails' cap and its plan's, for time and for cost,
258and its page shows the cap it got.
259
260A run that reaches a cap is stopped and marked **Stopped**, with "Stopped
261at its cost cap" or "Stopped at its time cap" on its page. A pull request it
262was working on is left open for you, as when a person stops a run: raise
263the cap if it was too low, then ask for a review, a revision or a catch-up
264to start again. A run of checks or the merge queue that reaches its time
265cap fails, as a sandbox that stops early always has.
266
267The run's page shows its caps under **Guardrails**: the time so far against
268its time cap, live, and its spend against its cost cap. Spend is reported
269when the run ends (or stops at its cap), so while it runs the page shows
270the cap, not a running total.
271
272### How they are enforced
273
274- The cost cap is enforced by the harness, which counts the run's model
275 spend the same way it reports it for billing and stops the agent once
276 the spend reaches the cap. The step in flight when it does can take the
277 run a little past it.
278- g1t's model proxy holds the run to the same cap, whatever happens in the
279 sandbox. It adds up what each of the run's model answers cost, and once
280 the run has spent its cap it refuses the run's model requests with
281 `402` and the error code `run_cap_reached`, which shows in the run's log.
282 The proxy also takes at most 16 of a run's model requests at a time,
283 and a run's model token reaches only `/v1/messages` (with
284 `/v1/messages/count_tokens`) and `/v1/models`. The token stops working
285 when the run ends.
286- The time cap is enforced twice: the harness stops the agent when it
287 passes, and the sandbox itself is stopped three minutes after, whatever
288 is running in it.
289
290## Abuse and mining
291
292g1t does not run cryptocurrency miners, on any plan. Mining needs a mining
293pool and hours of CPU; g1t's sandboxes withhold the first and watch for the
294second:
295
296- **No pool to reach.** No mining pool is on any allowed list, so a
297 restricted sandbox's miner has nowhere to send its work.
298- **Miners by name.** A shell command an agent runs, a check, a build
299 command, a workflow step or a container a job starts whose image or
300 command names a known miner (`xmrig`, `cpuminer`, `t-rex` and others), a
301 pool address (`stratum+tcp://`) or a miner's flags (`--donate-level`,
302 `--algo=rx/0`) is refused, whatever the project's rules. A running process whose command line names one stops
303 the sandbox at once.
304- **The CPU signature.** Every sandbox samples itself every 30 seconds:
305 CPU use, file and disk I/O, network bytes, new processes, and whether the
306 run did anything (a tool call, an agent step, a new check command or
307 workflow step). It is stopped when, for 10 minutes straight, CPU stays at
308 or above 90% (one dip allowed) while file and disk I/O average under
309 64 KB a second, the network under 16 KB a second, fewer than five new
310 processes start, and nothing else happens.
311
312 Compiling and testing are CPU-bound too, but they read sources, write
313 objects and start processes (a `cargo build` or `npm test` starts
314 hundreds), so they do not match. A compiler can spend minutes in code
315 generation with little I/O, so when the busiest process is a known
316 compiler or runtime (`rustc`, `cc1`, `clang`, `go`, `javac`, `node` and
317 others) the sandbox is not stopped for CPU alone.
318
319A sandbox stopped this way ends with "Stopped: unusual CPU use; contact
320support if this was a real job." An agent run shows it under **Agents**
321and leaves its pull request for you, a check or merge queue run fails with
322it, a workflow job fails with it, and a deployment's status says it. g1t's
323staff are told, with the measurements, and look at what ran. If it was a
324real job, write to hey@flagon.io and say which run.
325
326## What is not covered
327
328- **GitHub Actions jobs and deploy builds** get the network list and their
329 time limit, but no command rules or cost cap: they run commands from the
330 repository's workflows and build settings, not an agent.
331- **Merge checks** only merge two commits; they are not given guardrails.
332- The **commit history** an agent produces is reviewed like any other
333 change: guardrails limit what an agent can do while it works, not what
334 its change does once it is merged.