Claude Code
How to Give Claude Code Autonomy Without Losing Control
Useful autonomy is engineered, not granted: bounded authority, deterministic validation, explicit stop conditions, and deploy gates that stay human.
Daniel Dayto
Forward Deployed Engineer · Co-Founder & Technical Lead at Playmaker
- Published
- Reading time
- 12 min read
On This Page
Autonomy is a design problem
On This Page
Autonomy is a design problem
There are two failure modes in how teams run coding agents, and they're mirror images. The first is the babysat agent: every file edit approved by hand, every command inspected — all the cost of supervision with none of the value of automation. The second is the blank check: full permissions, no boundaries, and a quiet prayer. Both come from treating autonomy as a single dial. It isn't. Autonomy that actually works is bounded authority plus deterministic validation plus explicit stop conditions — three separate controls, engineered per task. Get those right and you can walk away from the keyboard for an hour; get them wrong and neither supervision nor luck will save you consistently.
Autonomy is a design problem, not a trust problem
The question "do I trust the agent?" is malformed — it has no stable answer, because the same agent is highly reliable at some operations and unreliable at others, and both change with context. The well-formed question is: what's the blast radius if this specific operation goes wrong, and is that radius contained? A wrong edit on an isolated branch costs a git checkout. A wrong command against a production database costs an incident. Same agent, same session, radically different stakes — which is why authority should attach to operations, not to sessions.
Risk tiers
| Tier | Operations | Blast radius | Policy |
|---|---|---|---|
| T0 — Read | Read files, search, git log, git diff, list directories | None | Always allowed |
| T1 — Reversible write | Edit files on a feature branch, create files, local commits | One git checkout away from undone | Allowed inside branch isolation |
| T2 — Local execution | Run tests, linters, builds, local dev servers | Local environment only | Allowlist the specific commands |
| T3 — Outbound effects | Push branches, open PRs, call external APIs, install dependencies | Visible outside the machine; mostly reversible | Ask, or allowlist narrowly per task |
| T4 — Destructive / stateful | Database mutations, deleting untracked data, force-push, secret access | Real data, real loss | Deny by default; explicit human action |
| T5 — Production | Deploys, infrastructure changes, DNS, production config | Customers notice | Never agent-initiated. Human authorizes from a reviewed artifact |
The five boundaries that make autonomy cheap
- Branch isolation. All agent work happens on a dedicated branch — or, for parallel sessions, in a dedicated git worktree (Claude Code creates these with
claude -w; it's the documented pattern for concurrent sessions). The branch is the undo button that makes T1 nearly free. - Filesystem boundaries. Claude Code's OS-level sandboxing (Seatbelt on macOS, bubblewrap on Linux/WSL2) defaults sandboxed commands to read-only outside the working directory, with writes confined to the project and session temp space. That default is correct; widen it per path, deliberately, or not at all.
- Command permissions.
allow/ask/denyrules in settings files, with rule syntax likeBash(yarn build)orBash(git push *). Allowlists beat denylists: enumerate what the task needs; leave everything else at ask. - Environment separation. The agent's shell should not carry production credentials at all. Development environment variables only; production secrets live where the agent isn't. A permission system can't leak what the process never had.
- Network boundaries. Sandboxed commands prompt on first use of a new domain, and
sandbox.network.allowedDomainsmakes the allowed surface explicit — which converts "the agent could call anything" into a reviewable list.
Permission matrix by task type
| Task type | Mode | Allowed | Ask | Denied |
|---|---|---|---|---|
| Codebase investigation / audit | plan | Reads, searches | — | All writes and state changes (by mode) |
| Feature work (this article's focus) | acceptEdits on a branch | Edits; Bash(yarn lint), Bash(yarn build), test runner | git push, dependency installs, new domains | Prod credentials, DB mutations, force-push |
| Mechanical refactor / codemod | acceptEdits in a worktree | Edits; build + tests | Anything outside the named directories | Everything T3+ |
| CI / headless automation | claude -p with --allowedTools and --max-turns | Exactly the enumerated tools | Nothing — headless can't ask; unlisted = unavailable | Everything else by construction |
| Production incident investigation | plan / read-only | Logs, dashboards, code reads | — | All mutations — diagnosis and remediation are separate sessions |
The mechanisms, mapped to the tool
Claude Code gives you several layered mechanisms, and it's worth knowing which one to reach for. Permission modes set the session's posture: default prompts, plan restricts to reading and proposing, acceptEdits pre-approves file edits, and bypassPermissions disables checks — the docs are blunt that the last one belongs only in isolated containers or VMs without internet access, offers no protection against prompt injection, and it refuses to run as root. I don't use it on development machines, and nothing in this article requires it. Settings files carry the durable policy: project rules in .claude/settings.json (committed, so the team shares one boundary), personal additions in settings.local.json, with rules merging across scopes. Hooks are the deterministic backstop — a PreToolUse hook that exits with code 2 blocks the call unconditionally, which is how you encode "never run this migration command" as machinery instead of prompt language. Headless flags (--allowedTools, --disallowedTools, --max-turns) bound automation that runs with nobody watching.
{
"permissions": {
"allow": [
"Bash(yarn lint)",
"Bash(yarn build)",
"Bash(yarn test *)",
"Bash(git checkout -b *)",
"Bash(git add *)",
"Bash(git commit *)"
],
"ask": [
"Bash(git push *)",
"Bash(yarn add *)"
],
"deny": [
"Bash(git push --force *)",
"Read(./.env)",
"Read(./secrets/**)"
]
}
}Stop conditions: the control nobody writes down
Permissions control what an agent can do; stop conditions control what it should do with an open-ended situation. They're the difference between an agent that plows through ambiguity and one that surfaces it. Every autonomous session I run carries a version of this checklist:
- Stop if an acceptance criterion looks unachievable as scoped — don't redefine the criterion to fit the work.
- Stop if the task seems to require a schema migration, data backfill, or deletion of anything that isn't in version control.
- Stop if you need a credential, account, or external service that wasn't provided.
- Stop if the fix appears to belong outside the agreed scope — name the boundary violation instead of crossing it.
- Stop if validation fails twice for the same cause — the third identical retry is where agents start damaging things to make errors go away.
- Stop if you find something alarming — credentials in the repo, a disabled safety check, evidence of a live bug in production — and report before touching it.
Evidence-based completion
Autonomy's last requirement is that "done" mean something. An autonomous session isn't complete when the agent says so — it's complete when deterministic checks pass and the evidence is presented: the exact commands run and their output, routes verified, artifacts inspected, plus a report of what was not verified and what still needs a human decision. Mandatory tests and the production build are the floor. For visual work, rendered screenshots are part of the evidence — on my own projects, screenshot review has caught defects that every automated check passed. The report format I require is in the companion workflow article; the field that matters most is "claims needing me."
Which tasks deserve full autonomy
| Good candidates for full autonomy | Keep a human in the loop |
|---|---|
| Feature work on an isolated branch with checkable acceptance criteria | Anything touching authentication, authorization, or payment paths |
| Mechanical refactors and codemods with full test coverage | Schema migrations and data backfills |
| Test authoring against existing behavior | Changes to CI/CD pipelines and deploy machinery |
| Read-only investigation, audits, and documentation of current behavior | Security-sensitive code, secret handling, permission systems |
| Build/tooling fixes verifiable by the build itself | Anything where "correct" requires product judgment or unverifiable claims |
A safe autonomous execution prompt
EXECUTION BOUNDARIES
- All work on branch feat/<name>. Never commit to main. Never force-push.
- You may run: yarn lint, yarn build, yarn test — freely and often.
- Ask before: git push, adding dependencies, contacting new domains.
- Do not read .env or anything under secrets/.
- No database mutations. No production config. No deploys.
STOP AND REPORT IF
- An acceptance criterion appears unachievable as scoped
- The task seems to need a migration, backfill, or deletion
- You need a credential or account not provided
- The same validation fails twice for the same cause
- You find credentials, disabled checks, or a live production bug
DONE MEANS
- All acceptance criteria pass, with command output as evidence
- Implementation report delivered (changed / verified / not done /
claims needing me / risks)
- Branch pushed ONLY after I confirm the report.The control you keep
Notice what was never on the table: production. Deploys, infrastructure, customer data — those stay behind a human decision made from reviewed artifacts, and no amount of agent capability changes that. This isn't distrust of the tooling; it's the same reasoning I apply to autonomous voice agents in live operations: the autonomy boundary is drawn conservatively, enforced in machinery rather than in model judgment, and widened only as production behavior earns it. Give a coding agent a contained blast radius, deterministic evidence, and sharp edges to stop at — and the autonomy you get inside those lines is not a risk you're tolerating. It's leverage you engineered.
Key takeaways
- Attach authority to operations, not sessions — tier every operation by blast radius and permission it by tier.
- Branch/worktree isolation makes write autonomy nearly free — one command undoes anything inside the boundary.
- Allowlist commands per task; commit the policy in
.claude/settings.jsonso the whole team shares one boundary; use hooks for the non-negotiables. - Stop conditions are the highest-leverage control — zero interruptions inside the boundary, guaranteed interruption at the edges that matter.
- Completion requires evidence — command output, verified routes, screenshots, and an explicit list of what wasn't verified.
- Production access is not an autonomy tier — it's a human decision made from artifacts the agent prepared.
Sources & further reading
About the author
Daniel Dayto
Forward Deployed Engineer · Co-Founder & Technical Lead at Playmaker
Daniel Dayto builds and deploys production conversational AI systems for customer operations. His work spans voice agents, RAG assistants, CRM and dispatch integrations, multi-tenant infrastructure, and workflow automation.
Related articles
Claude Code · July 24, 2026
How I Use Claude Code to Take a Feature from Discovery to Production
A production Claude Code workflow from operational problem to deployed feature: repository inspection, plan mode, permission boundaries, branch isolation, continuous validation, diff review, and implementation reports.
AI Development Tooling · July 24, 2026
Configuring OpenCode to Work Across Multiple LLM Providers
How to configure OpenCode across multiple LLM providers: global vs. project config, credential handling, provider blocks, model selection, local models via OpenAI-compatible endpoints, and troubleshooting.
Deploying AI into a real operation?
I work with teams shipping voice agents, RAG systems, and workflow automation into production. Open to Forward Deployed Engineering, Applied AI, and founding technical roles.