Local action control for AI coding workflows: where it fits
Local action control helps AI coding agents act without exposing secrets. Learn when developer approvals fit and when server-side controls must decide.

Local action control fits an AI coding workflow when one developer owns the machine, remains present enough to authorize a run, and needs an agent to act outside the repository without receiving the underlying secrets. It is a good answer to a narrow, common problem: an agent can edit code safely enough in a workspace, but it also needs to query an API, fetch a private artifact, or run a command over SSH.
It is a poor answer when people try to promote it into fleet authorization. A Mac-side approval can establish that a particular local process may act with a credential. It cannot tell a production service which tenant, environment, change window, or business rule should permit the resulting request. Those decisions belong where the resource lives.
The useful boundary is straightforward: local control protects credentials and restores human intent at the developer machine. Server-side control protects shared resources and continues working when no developer is sitting at that machine. Teams get into trouble when they ask either side to do the other's job.
Local control belongs to a person-owned execution point
Local action control makes sense when the machine that launches the agent has a clear owner who can recognize the work and interrupt it. That usually means a developer Mac running an interactive coding session, not an unattended build worker with a friendly hostname.
The ownership question sounds obvious until a team looks at how work actually runs. A laptop may be personally assigned but routinely accessed through remote desktop. A shared lab Mac may have several engineers logged in across a week. A managed build host may run under a developer's account but execute jobs triggered by a pull request. None of those facts alone creates meaningful human control.
Ask four concrete questions before you add local approvals:
- Who can physically unlock the machine and approve a request?
- Which executable launches the agent, and can the owner identify its code-signing authority?
- Does the agent's work stay within an interactive session, or can it continue after the person walks away?
- If the machine is compromised, what limits the credential's reach at the remote service?
The first two questions establish whether approval has a human subject. The last two establish whether approval has a sensible blast radius. If a developer clicks approve for a process that can run overnight and deploy to every environment, the click carries far more authority than the person probably intended.
A local gateway should hold the secret and perform the outbound action itself. Giving an agent a token through an environment variable, a config file, or a tool response makes the local gate mostly ceremonial. The agent may echo it into a transcript, write it into a patch, place it in a shell history file, or send it to another tool. You cannot reliably retrieve a credential after it has entered an agent's context.
This is why a proxy-like arrangement is not enough by itself. An HTTP proxy can route traffic, but routing does not prove that secrets never enter the client process. The design must ensure that the agent asks for an action, the local component injects the credential, and the agent receives only the remote result.
Machine ownership is more than a login name
A developer account name does not prove that the approved process is the process doing the work. On macOS, a coding agent may be launched by a terminal, an editor extension, a helper process, or a script written into the repository. Those origins carry very different levels of trust.
Start by examining the actual process tree during a harmless run. This command lists process IDs, parents, users, elapsed time, and command lines:
ps -axo pid,ppid,user,etime,command | grep -i '[a]gent'
The output should show a chain you recognize. For example, an interactive terminal may appear as the parent of the approved agent process. A shell script inside an untrusted repository, a background launch item, or an unknown helper should change your decision. Do not approve a process merely because its command line contains the name of a tool you expected.
Then inspect the executable rather than trusting its filename:
codesign -dv --verbose=4 /path/to/executable 2>&1 | \
grep -E '^(Identifier|TeamIdentifier|Authority)='
A signed binary can still contain bugs, but signing authority gives an operator a stable thing to recognize. A bare path under a writable project directory does not. A session approval that leads with the code-signing authority is much better than a dialog that says only "agent wants access." It helps the person reject a copied binary, a local wrapper, or an unexpected update before it gets a credentialed action.
This is also why shell aliases and wrapper scripts deserve attention. They are useful for work, but an alias can launch something other than the executable the person believes they approved. Keep action-gateway launch commands outside agent-writable repositories. If an agent can edit the script that defines its own access path, the gate no longer expresses an operator's decision.
The Model Context Protocol specification defines how an MCP client and server exchange tool calls. It does not establish that a tool caller is an approved local process. MCP compatibility answers an interface question. Process identity, credential custody, and authorization remain separate work.
Session approval works when a run has a natural boundary
Per-session approval is a practical default for an interactive coding run because it asks once when a new agent process begins and then gets out of the way. It avoids a confirmation dialog for every harmless read while preserving a point where the person can inspect who is asking.
The boundary must be an actual process lifetime, not a vague idea of "this afternoon's work." A session ends when the process exits. That rule is easy to explain, easy to revoke, and difficult for an agent to reinterpret. If the process restarts, it asks again. If a person revokes it, future calls fail instead of inheriting trust from an earlier click.
Approval fatigue tells you the boundary is wrong. If a developer sees a request each time an agent checks an issue tracker, fetches a package, and reads a staging API, they will approve mechanically. Repeated warnings do not produce better judgment. They train people to clear windows so work can continue.
A session approval has a narrower purpose than a policy engine. It says, "I recognize this local process and permit it to use the allowed action path while it is alive." It should not attempt to infer whether a SQL query is safe, whether a ticket title sounds legitimate, or whether the current branch deserves production access. Those are remote authorization decisions or workflow rules, and natural-language prompts are a dreadful place to store them.
There are cases where even an interactive session should not receive a blanket grant. An agent that opens arbitrary local workspaces, accepts tasks from chat, or runs plug-ins from unreviewed repositories has a wider input surface than a tightly scoped repository session. In that setting, either reduce the action set available to the run or demand approval for the specific credential that carries risk.
Approval dialogs also need a reliable failure behavior. If the vault is locked, every action should fail. If the approval UI cannot appear because the Mac is locked or asleep, every action should fail. A hidden fallback that lets requests proceed during a UI error turns a human gate into decoration.
Per-call approval is for actions with costly consequences
Per-call approval fits a credential whose use can create a production change, spend money, delete data, or cross a boundary a developer should actively consider each time. It does not fit every credential with an intimidating name.
Classify the action by consequence, not by protocol. An HTTP POST may only create a disposable preview record. An SSH command may only read a deployment log. A GET request may export an entire customer dataset. The method and transport do not decide the approval mode.
Use a per-call gate when the action has one or more of these properties:
- The remote service cannot reliably undo the result.
- The credential can affect a shared production resource.
- The request can transfer sensitive data outside an expected destination.
- The operation is rare enough that a deliberate confirmation will not become routine.
The fourth point matters. Per-call confirmation on a high-frequency action produces the same mechanical clicking as an overactive session prompt. Split credentials when you can. Give routine development work a credential constrained to development resources, and reserve the production-capable credential for the small number of actions that justify interruption.
An agent should never decide which of its own calls need confirmation. If the agent can label a request "read only" or select the credential class itself, a prompt injection or a simple implementation mistake can steer it toward the easier route. The person who owns the account must set the approval requirement outside the agent's workspace.
Make the confirmation readable enough to support an actual decision. A person needs the credential name or purpose, destination, request method or command form, and the process identity that initiated the call. Showing raw request bodies can expose secrets or overwhelm the person. Showing only "Approve action?" gives no useful context. Good confirmation design does less, but tells the operator enough to reject an unexpected call.
Keeping secrets local solves one problem, not all of them
A local vault prevents the agent from holding API keys and private SSH keys in plaintext. That sharply reduces accidental disclosure through prompts, transcripts, tool logs, copied files, and agent-written code. It also lets the operator revoke an active run without rotating the credential immediately.
It does not change what the remote credential can do. If an API token can delete every project, the service will accept a delete request after a local approval. If an SSH account has broad sudo rights, protecting the private key does not turn that account into a narrow deployment identity. Remote least privilege still decides the maximum damage.
Keep two distinctions clear:
- Credential custody asks whether the agent can obtain or reproduce a secret. A local vault can answer this well.
- Resource authorization asks whether the service should accept an action under current conditions. The API, host, identity provider, or deployment system must answer this.
Teams often blur these because both topics appear when an agent calls an API. The consequence is predictable. They install a local secret holder, then leave a long-lived administrator token behind it. The token no longer leaks as easily, but the action path remains far too broad.
SSH makes the distinction painfully concrete. The local machine can protect the private key, but the host decides what the public key's account may execute. Create separate accounts or forced-command restrictions for automation where possible. Limit host access. Avoid using an engineer's personal administrator key as the agent's general-purpose key. Personal keys accumulate exceptions over time, and those exceptions are exactly what an autonomous process should not inherit.
Sallyport uses this local model by keeping API and SSH credentials in an encrypted app vault and performing the HTTP or SSH action without passing the secret into the agent. That property helps on a developer machine, but teams still need narrow credentials and server-side permissions.
Verify the action path before you trust it
You should test an action gateway with a harmless endpoint and a temporary credential before connecting it to a production capability. The test must show three things: the agent did not receive the secret, the gateway recorded the call, and the remote service saw the expected identity.
Make a temporary HTTP credential that can call a non-sensitive endpoint, such as a test resource that returns the caller identity. Ask the agent to perform that one action. Inspect its transcript and tool result for the literal token and for token-shaped strings. The agent should receive the response body or a redacted error, never the header value used to authenticate the request.
Then test denial on purpose. Lock the local vault and repeat the action. Kill the approved agent process and start a fresh one. Revoke the live session if the gateway supports revocation, then retry from the original process. Each retry should fail at the local boundary. If calls still succeed, find out whether a separate process retained the credential, an environment variable bypasses the gateway, or the remote service has another cached authorization path.
A useful audit record needs enough information to reconstruct an event without preserving the secret itself. For an HTTP action, record a timestamp, process or session identity, credential label, destination, method, result status, and a request identifier where the remote service provides one. For SSH, record the destination, account label, command outcome, and a command representation appropriate for your sensitivity rules. Do not log bearer values, private keys, or full sensitive payloads to make an audit trail feel complete.
Hash chaining helps detect a rewritten local history, but it does not prove that the original action was wise. Keep the gateway's record alongside the receiving service's audit log. If they disagree, treat that as an investigation, not as a reason to declare one source automatically correct.
Sallyport projects session and activity journals from an encrypted, hash-chained audit log, and sp audit verify can check that chain offline without a vault key. Run verification as part of incident review or a release handoff, but do not mistake integrity checking for authorization.
Server-side controls take over when people are absent or resources are shared
Server-side controls are required when the action must continue without a specific developer available to approve it. That includes CI jobs, scheduled remediation, server-hosted agents, shared runners, and deployment workers. A local Mac cannot be the final authority for work that must survive a laptop battery, travel, sleep, or a person leaving the company.
Put the authorization decision close to the protected resource when any of these conditions applies:
- Multiple people or systems can trigger the same workflow.
- The target is production, customer data, financial activity, or a regulated system.
- An agent runs on infrastructure rather than a person-owned interactive machine.
- The service must enforce tenant boundaries, change windows, environment rules, or separation of duties.
- The workflow needs high availability without a person approving a dialog.
For those cases, use a workload identity with narrow permissions, short validity where the identity system supports it, and server-side audit records. Enforce environment boundaries in the deployment system or API. Require a change record or human approval there if the organization needs one. The local machine may still help a developer prepare and inspect a change, but it cannot be the enforcement point for the production action.
NIST Special Publication 800-207 describes zero trust as a model where access decisions focus on protecting resources rather than trusting network location. The useful lesson for agent workflows is not that every local tool needs a complicated policy language. It is that the production API or host must make its own decision about the caller and requested resource. A Mac-side approval cannot substitute for that decision.
Do not solve this by forwarding a developer's local credential into CI. That turns a human-controlled credential into an unattended service credential while preserving none of the clarity of either model. Create a distinct workload identity and give it only the permissions the job needs.
Do not rebuild a policy engine inside approval prompts
Teams often ask for rules such as "allow GET requests except after hours" or "permit SSH only when the branch name contains release." The request is popular because it appears to reduce clicks while keeping control local. It usually creates a fragile policy system that nobody can explain under pressure.
Local action control should have a small, visible decision ladder: vault locked or unlocked, session approved or not, credential requires per-call approval or not. Each state has a direct operator action. A person can predict what will happen, test it, and revoke it.
Once a local tool begins parsing branch names, prompt text, URL patterns, ticket labels, and agent-provided intent, it starts making authorization decisions from inputs the agent can influence. The rules grow exceptions. The exceptions become permissions. Before long, a developer has built a partial server authorization system on a laptop, without the service context needed to do the job well.
Keep local decisions tied to facts the local machine can establish: whether the vault is open, which signed process requested an action, whether its session is approved, and whether this credential needs a fresh confirmation. Keep remote decisions tied to facts the service can establish: target resource, caller identity, tenant, current environment, request contents, and organizational controls.
This separation also makes failures easier to diagnose. A denied local call means the vault, session, or per-call gate stopped it. A denied server call means the remote policy rejected it. When a denial can come from a maze of overlapping local rules, developers disable controls rather than repair them.
A mixed workflow gives each control a defined job
Most teams need both local and server-side controls. The practical design is not an all-or-nothing choice.
A developer can run an interactive agent locally to inspect a staging API, read private package metadata, or execute narrow SSH diagnostics. The developer approves the run after checking its process identity. The local vault supplies a credential that the agent never sees. Activity records make later review possible.
The same agent can prepare a deployment change without receiving authority to deploy it. A server-side pipeline then runs with its own workload identity, applies production restrictions, and records the resulting deployment. If the pipeline needs human approval, put that approval in the system that owns the production change, where it remains visible to the people responsible for that environment.
Treat the handoff as a boundary worth preserving. The local agent can produce a patch, a test result, or a signed request for review. It should not smuggle a developer's session authority into an unattended job. The server job should not depend on an unlocked laptop to complete work.
Start by drawing every credentialed action in one current workflow. Write down the process that initiates it, the machine that holds the secret, the resource that receives it, the person who can stop it, and whether the job must run without that person. You will quickly find the actions that fit local control, the ones that require server enforcement, and the uncomfortable ones that currently have neither.
FAQ
When should I use local action control for an AI coding agent?
Use local control when the agent runs on a developer-owned Mac and must call a small set of APIs or SSH destinations using credentials that should stay off the agent's context. It works best when a person can approve a new agent process and can respond if the machine asks for confirmation.
Does a local credential vault make AI agents safe?
A local vault keeps credentials out of the agent process, which removes a major exposure path. It does not make a compromised developer machine trustworthy, and it cannot replace authorization rules enforced by the service that receives the request.
What should I check before approving an AI agent session?
Approve a session when you recognize the launching process, its signing authority, and the work it is about to do. Do not approve a session just because the prompt mentions a familiar project name; prompts do not establish process identity.
Which agent actions need approval every time?
Use per-call approval for credentials that can create irreversible effects, such as a production deployment token, a payment action, or a destructive administrative API. Routine read-only calls become unusable if they need the same interruption every time.
Is SSH through an agent action gateway safe?
No. SSH command execution is only local control when the destination, account, command scope, and host trust are constrained somewhere. A protected private key can still authorize a dangerous command on a host that gives the account broad permissions.
Can local action control replace server-side authorization?
No. Service accounts, CI runners, production automation, and shared build machines need controls that remain available when no individual developer is at a Mac. Put authorization and audit enforcement near the service or workload in those cases.
How can I test whether an agent process is the one I approved?
Start with ps to identify the process hierarchy and codesign to inspect the executable's signing details. Then run one harmless call and inspect what the agent receives, what the action gateway records, and what the receiving service logs.
Does MCP provide approval controls for agent tools?
No. An MCP server describes a tool interface and request protocol; it does not decide where credentials live or whether a human approves an action. Treat transport compatibility and action authorization as separate design questions.
Is a tamper-evident audit log enough for agent accountability?
A tamper-evident log helps you detect altered history and reconstruct what ran, but it cannot undo an action or decide whether the action was authorized. Keep the gateway journal, the service audit log, and deployment records because each answers a different question.
What local agent controls should never be left to the agent?
Do not allow the agent to choose the approval mode, destination scope, or credential class in its own prompt or configuration. The operator must set those boundaries outside the agent's writable workspace, then test denial and revocation before relying on them.