8 min read

Locked local vault access: a runbook for agent work

Plan locked local vault access for autonomous agents with clear unlock windows, run approvals, per-call decisions, pauses, and review evidence.

Locked local vault access: a runbook for agent work

Autonomous work fails in a very predictable way when people treat a locked local vault as an inconvenience. The agent encounters a credential boundary in the middle of a task, someone feels pressure to finish, and a secret gets copied into a shell variable, a configuration file, or a chat message. The short-term task completes. The team has also created an untracked credential path that will outlive the task.

A locked vault should shape the work plan before an agent starts. The operator needs to decide three separate things: when to unlock access, which agent process may act during this run, and which individual actions still need a human decision. Teams that collapse those decisions into one vague "go ahead" either drown in prompts or end up bypassing the controls.

This is not a call to keep a person glued to every command. It is a call to put human attention where it changes the outcome. Read-only discovery can often run under a bounded session. A production deletion, permission change, or release publication deserves a fresh decision at the moment it happens. The rest depends on a run plan that an operator can understand before the agent begins.

Unlock windows need an owner and an end time

An operator should unlock a local vault for a defined work window, with one person responsible for the decision and a known condition for closing it. "Keep it open while I am working" sounds practical, but it fails whenever a meeting, lunch, laptop sleep, or context switch interrupts the work. An open vault then becomes authority that no one is actively considering.

The unlock decision grants the broadest form of access in the chain. If the vault stays locked, no agent session and no individual request should pass through it. That makes the lock state useful, but only if the team treats it as an operational boundary rather than a ceremonial login step.

Use a work window that matches the task's natural rhythm. A narrow repair may need one short window. A planned migration may need a window that covers preparation, execution, and verification, with a scheduled pause before any irreversible phase. An investigation that only reads logs should use a separate window from the follow-up that changes production settings.

The operator should write down five facts before opening access:

  • who owns the authorization decision;
  • what work the agent may perform;
  • which environments and accounts the work may touch;
  • the condition that ends the window;
  • the person who reviews the outcome if the owner has to leave.

That record does not need grand ceremony. A ticket comment or run note is enough when it names real boundaries. "Fix deployment issue" is not enough. "Inspect failed staging deployment, then retry the named deployment only if the image digest matches the approved build" gives a reviewer something to test.

Avoid using a clock alone as the end condition. A hard closing time helps, but work often runs late because an agent finds an unexpected dependency. Combine a time limit with a state limit: close after the planned verification, after the first unexpected target appears, or when the owner steps away. A task that overruns should request a new window. That small interruption forces somebody to decide whether the original authorization still fits the work.

The popular alternative is permanent convenience: unlock at the start of the day and lock at the end. Teams choose it because unlocks interrupt flow. It is the wrong default for autonomous work because the agent can continue at machine speed while the human attention that justified access has moved elsewhere. If repeated unlocks feel intolerable, improve the work batching and approval design. Do not remove the boundary.

Vault unlock, run approval, and action approval answer different questions

A locked local vault needs three distinct decisions because each one controls a different risk. Unlocking answers whether credentialed actions may happen at all. Approving a run answers whether this identified agent process may use the available action path for its bounded work. Approving an individual call answers whether this particular use of a particular credential deserves a fresh human choice.

Teams often confuse the first two. They unlock a vault and assume every process on the machine now has permission to act. That turns a physical or local-presence check into a broad software authorization. The other bad pattern is approving each harmless request because the team never stated what a session approval means. Operators then approve dozens of routine reads and eventually stop reading the cards.

The distinction matters most when a task changes shape. Suppose an agent receives approval to inspect a failed build, query a deployment API, and collect logs. It discovers that a missing permission might explain the failure. The original run did not include changing access controls. The agent should stop and request a new decision, even if the vault is open and its process session remains approved. The task's purpose changed from diagnosis to administration.

A sensible split looks like this:

  • Unlock access while a responsible person can supervise the planned work.
  • Approve one identified agent process for the stated run, including ordinary actions that fit the run contract.
  • Require a separate approval for high-consequence calls, such as publishing, deleting, changing permissions, rotating credentials, or writing to production.

The exact action categories vary by team. The point is to classify them by consequence, not by the number of API calls. One request to revoke a production account deserves more attention than fifty requests to fetch build metadata.

This is where Sallyport's fixed decision ladder is intentionally narrow: its vault gate blocks every action while locked, per-session authorization approves a new agent process for its lifetime, and a per-key setting can require approval for every use. The design does not ask operators to write a policy language that becomes another security program to debug during an outage.

Do not claim that a per-call gate makes any credential safe. It only makes a human decision available at the point of use. The operator still needs enough context to judge the request. If the prompt says only "use production token," the control has already lost most of its value. Put target, action, and intended effect in the run plan, then compare the request against that plan.

Schedule access around work states, not office hours

A team should plan agent work as a sequence of states with explicit points where authority starts, pauses, narrows, or ends. Office hours help with staffing, but they do not describe the actual work. A task can begin during staffed hours, wait on an external system, and resume long after the person who approved it has left.

Use four states in the task record: preparation, active execution, held, and review. Preparation has no credentialed actions. The agent can inspect the repository, assemble commands, validate inputs, and explain its intended calls without vault access. Active execution begins only when an operator opens the access window and approves the run. Held means the agent has reached a wait condition, an unexpected decision, or the end of its approved scope. Review closes the loop before the team grants authority for related follow-up.

This simple state model prevents a common failure. An engineer starts an agent on a deployment cleanup at 4:30. The agent runs tests, identifies stale resources, and waits for a cloud operation to finish. At 5:15 it resumes, discovers a different account needs cleanup, and keeps moving because the session still exists. The original operator has left. Even if every API call succeeds, the team has allowed the task to migrate into a different scope without an accountable decision.

Write pause rules before the run. Good pause rules are observable:

  • stop if the target account, host, or environment differs from the run note;
  • stop if the agent needs a credential class not named in the plan;
  • stop before any action that creates, deletes, publishes, or changes permissions;
  • stop after a failed write until the operator reviews the returned error;
  • stop when the named operator becomes unavailable.

A pause is not a failure. It is a clean state transition. The agent should preserve the exact command or request it intended to make, the inputs it gathered, and the reason it stopped. The next operator can then decide whether to continue without reconstructing the task from a noisy chat transcript.

This also keeps urgency honest. If an after-hours job needs an action, someone must decide whether the business impact justifies opening a new access window. Teams sometimes call every blocked task urgent because the agent already did ten minutes of work. That is sunk-cost thinking. A credential boundary should make the human choose again when circumstances change.

Process identity must be visible before a run earns trust

An approval should identify the agent process by more than a terminal label or a user-provided name. A process called "deploy-agent" could be the expected executable, a local script, or something launched by a compromised dependency. The operator needs a meaningful signal about who produced and launched the program asking for authority.

Code-signing identity is useful because it ties the approval decision to an executable authority rather than text that any process can print. It does not prove that every prompt given to the agent was wise. It does establish a stronger answer to a basic incident question: which process received permission to use the vault?

Require the run note to name the agent entry point and the working directory or repository. That gives an operator two checks before approving: the process identity shown by the system and the task context the team expected. When those differ, deny the request and inspect the machine. Do not approve first because the task seems familiar.

A clean approval flow has a modest amount of friction. The first credentialed call from a new process triggers the approval. The operator confirms the process authority and the run purpose. The process can continue within its approved session until it exits, the operator revokes it, or the vault locks. A fresh process asks again.

That last detail blocks a subtle workaround. If a team approves a named terminal session instead of a process, a person can launch an unrelated program in the same terminal and inherit trust that belongs to the earlier run. Make the authorization attach to the actual agent process, not to a window, a user account, or a project folder.

Sallyport presents the process code-signing authority when it asks for per-session authorization, which is the detail an operator needs before approving an agent run. Teams should still keep the written run purpose beside that signal because identity tells you who is asking, while the run contract tells you whether the request belongs.

Per-call gates belong on irreversible authority

Put control on your Mac
Sallyport runs as one signed, always-running macOS menu-bar app with its vault core in-process.

Per-call approval works when it protects actions that a person can judge in seconds and regret for much longer. Put it on credentials that can create external commitments, alter access, destroy data, or affect a production service. Do not put it on every credential by habit.

The standard mistake is to mark a whole production account as "dangerous" and require approval for every request. The agent then makes many harmless reads, the operator approves them rapidly, and the one destructive write arrives among familiar prompts. The control has become a metronome. People are bad at sustaining attention through repetitive, low-information confirmations.

Split authority when the provider permits it. Use a read credential for discovery, a narrowly scoped write credential for ordinary maintenance, and a higher-consequence credential for actions that need a per-call decision. If the provider only offers one broad token, treat every use of that token as broad authority. Do not pretend that an HTTP method alone makes it low risk. A POST can fetch data, and a GET endpoint can trigger work in poorly designed APIs.

RFC 6750 describes a bearer token plainly: any party that possesses it can use it. That property is why giving a token to an agent, even "just for this task," creates a larger problem than the immediate operation. The agent's prompt context, shell history, logs, plugins, and future handoffs can all become places where possession leaks. Keep the token inside the local vault and return the operation result instead.

For SSH, avoid agent forwarding as a shortcut around local control. The OpenSSH ssh_config manual warns that forwarding an authentication agent lets a remote host use the local agent, and it says users must trust the remote host. Autonomous work widens that concern because an agent may connect through a host whose configuration or destination it did not fully inspect. Use a direct SSH action path, name the allowed host in the run contract, and pause when a jump host or new destination appears.

Put a per-call gate on the credential, not on a vague idea of "production mode." That choice remains understandable later. A reviewer can see that this credential always demanded a decision, regardless of which agent requested it or which project supplied the prompt.

A run contract prevents approval by guesswork

A run contract should fit in a short ticket comment and should make the approval decision testable. It is not a project plan. It records the smallest set of facts that lets an operator approve, deny, pause, and review the work without reading an entire agent transcript.

Use this template before the operator unlocks access:

Run ID: 2025-03-incident-cleanup-01
Owner: name of approving operator
Purpose: inspect failed release and remove only the listed temporary resource
Agent process: expected executable and repository directory
Targets: staging account, api.example.internal, named SSH host
Allowed actions: read deployment state; delete resource tmp-4821 after match check
Per-call actions: delete request, any permission change, any production request
Stop conditions: target mismatch; unexpected credential; failed write; owner unavailable
Expected evidence: request IDs, resource IDs, command output, final status
Review owner: name of reviewer

The example uses a date-like identifier for readability, not as a security control. Pick an identifier your team can search in its task system and activity records. The important lines are the targets, allowed actions, and stop conditions. Those lines keep a run from expanding because an agent encountered a plausible next task.

The contract also exposes bad plans early. "Repair permissions" has no target, no allowed change, and no review evidence. An operator cannot responsibly approve it. "Add group X to role Y in staging, then verify the role binding with a read request" is specific enough to review. If the agent discovers that group X does not exist or role Y belongs to production, it must stop.

Do not make the template so detailed that people fill it with invented precision. A long list of endpoints creates a false sense of control when the actual risk is a business operation such as publishing a build or removing an account. Name endpoints when they clarify the boundary. Otherwise name the resource, environment, and effect.

For recurring chores, keep a stable contract with a revision history. A recurring contract does not mean permanent authority. The operator still opens a window and approves the particular process run. The stable text reduces ambiguity; it should not turn into a blanket permission that nobody rereads.

A blocked task needs a safe pause path

Avoid policy rules during incidents
The fixed decision ladder uses a vault gate, session approval, and optional per-key call approval.

Teams create workarounds when a blocked agent has no respectable way to stop. The agent may have gathered half the inputs, the operator may be unavailable, and the task may feel too close to completion to abandon. If the only options seem to be "finish now" or "lose all progress," someone will export the secret.

Build a pause path that preserves context without preserving credentials. The agent records what it observed, the exact external action it wants to take, the nonsecret inputs needed to resume, and the reason the approval boundary stopped it. It should never record a token, private key, authorization header, or command line that embeds a secret.

For an HTTP operation, the pause record can contain the method, host, route, resource identifier, expected status class, and a redacted body shape. For an SSH operation, it can contain the host alias, remote username if that is not sensitive, intended command, expected output, and the host verification result. An operator can inspect that record before opening the next window.

A useful handoff note might read like this:

State: held
Reason: planned cleanup target was absent; agent found a second temporary resource.
Observed: tmp-4821 absent, tmp-5930 created by the same failed release.
Requested next action: delete tmp-5930 after operator confirms it belongs to this incident.
No external write occurred after the original target check failed.
Evidence to review: deployment query result and resource metadata IDs.

This note gives the next operator a real choice. They can authorize the second deletion, reject it, or ask for more discovery. The agent cannot quietly reinterpret "remove the listed temporary resource" to mean "remove anything that looks similar."

Do not let the agent keep retrying a denied operation. A denial may mean the operator spotted a mismatch, the vault locked, or the per-call gate required a decision that never arrived. Retry loops turn a clear pause into a pile of prompts. Treat denial as a stop state unless the operator explicitly reauthorizes the same action.

The same rule applies when an API call times out after a write request. The agent must not assume failure and repeat the request. It should query the resulting state with a safe read where possible, record the ambiguity, and wait if the operation could have succeeded. Duplicate writes cause some of the most tedious incidents because they look harmless in the command log until the external system catches up.

Review evidence before the next access window

Gate serious credential use
Set high-consequence keys to require one-click or Touch ID approval on every use.

A team should review results at the end of a run before it grants new authority for related work. That review catches drift while the operator still remembers why the action happened. If the review waits until the end of the week, the ticket, chat, terminal, and agent transcript will all tell slightly different stories.

The reviewer should compare the evidence against the run contract, not against a general feeling that the task seems complete. Check the actual targets, the actions that succeeded, the actions that failed, returned identifiers, and any calls that fell outside the expected sequence. A failure may be acceptable. An unexplained target is not.

Keep the review short but concrete:

  • Did the agent contact only the approved environments and hosts?
  • Did every write match an allowed action or receive its own approval?
  • Did the external system return the expected resource or request identifiers?
  • Did the agent pause at each stated stop condition?
  • Does a follow-up task need a new contract rather than an extension of this one?

Reviewing output is different from reviewing authority. A session record can show that a process received approval at 10:02 and ended at 10:19. An action record can show the individual API and SSH operations that occurred inside that session. You need both views to answer whether the process did only what the run allowed.

A hash-chained audit log adds a separate property: it makes later alteration detectable. Sallyport keeps session and activity views projected from a write-blind encrypted audit log, and sp audit verify can verify that chain offline over ciphertext without access to the vault key. That is useful when someone needs to establish whether a record changed after an event, but it does not replace an operator reading the result while the facts are fresh.

Use the review to improve the next contract. If every run pauses because a harmless metadata lookup was omitted, include that lookup next time. If a recurring job asks for per-call approval on a read-only endpoint, move that credential to the ordinary session class. If reviewers repeatedly find unexpected writes, narrow the agent instructions and credential scopes before running it again.

Tamper evidence helps after a dispute, not before one

A tamper-evident record gives a team a way to test whether its history still has continuity. It does not decide whether an action was authorized, sensible, or safe. Treating audit evidence as a preventive control leads teams to approve broad runs because they believe they can sort it out later.

The difference matters in a real incident. Imagine an agent session contacts the expected deployment API, then issues a deletion against an unexpected resource. A chained log can help establish that the deletion request appeared in the recorded sequence. It cannot restore the deleted resource, explain why the process received broad authority, or prove that the operator intended that resource to be in scope.

Use audit verification when you need to preserve the record before escalating an incident, handing off an investigation, or reviewing a suspicious run. Run the verifier against the retained log material, record whether it succeeds, and keep that verification result with the incident notes. Do not edit or manually "clean up" activity entries to make a report easier to read. Explanatory notes belong beside the record, not inside it.

The chain also changes how teams should handle access to logs. People sometimes assume encryption makes a record useless without immediate decryption. A verifier that can check chain continuity over ciphertext lets an investigator establish one limited but important fact without opening the vault: whether the retained encrypted record still fits the sequence. Keep that distinction clear. Verification checks integrity continuity; decryption reveals content; neither grants a right to take another action.

A team that plans unlock windows, identifies agent processes, uses per-call gates for serious authority, and reviews results promptly will need audit evidence less often. When it does need the record, the team will also have the run contract and pause notes required to interpret it. A log without an approval context tells you what happened. A log paired with a disciplined work plan tells you whether the team allowed it for a reason.

The first change to make is small: require a written stop condition before anyone unlocks local credentials for an agent. That one line forces the team to decide what the agent should do when the task stops matching the plan. It also removes the usual excuse for exporting a secret when the work becomes inconvenient.

FAQ

Should an operator leave a local credential vault unlocked all day?

No. Unlock the vault only when an accountable operator is available to supervise the class of work the agent will perform. A vault that stays open because someone might need it later turns a deliberate authorization event into background state.

What should a single agent run approval cover?

Treat the session approval as consent for one identified agent process to carry out the stated run. It should expire when that process exits, when the operator revokes it, or when the work changes materially. Do not treat a new prompt in a reused terminal as a new approval without checking what process still owns the session.

Which agent actions need approval every time?

Use per-call approval for actions where a bad result has an immediate external consequence, such as a production write, a release publication, or a destructive administrative request. Do not require it for harmless read calls simply because the system supports it. Constant prompts train operators to approve without reading.

What happens when an autonomous task needs credentials after hours?

The safest response is to pause the task, record its current state, and wait for the next staffed access window. If the work has a genuine deadline, the responsible operator can open a short new window and approve a clearly bounded continuation. Do not solve the delay by copying a token into a file or chat.

What should an AI agent run contract include?

A good run contract names the operator, the purpose, the target environment, allowed action types, stop conditions, expected external changes, and the review point. It gives the operator something concrete to compare against the activity record. A ticket title alone rarely carries enough detail.

Why log agent sessions and individual credentialed calls separately?

You need both because they answer different questions. A session record tells you which agent process received authority and when that authority ended; an action record tells you what that process actually asked a credentialed system to do. One cannot substitute for the other when an incident occurs.

Is SSH agent forwarding safe for autonomous coding agents?

Do not allow it by default. SSH agent forwarding lets a remote machine request signatures from your local agent, which expands the place where an attacker can exercise your authority. Use a direct, named SSH action path with a bounded target instead.

How do I verify that I am approving the intended agent process?

Approve it only when you can identify the executable and its code-signing authority, and when the run has a written purpose and a bounded target. A process name by itself proves very little because any program can choose a friendly name. The approval screen should help the operator answer who launched this process and what it can do now.

When should a team review an agent's results?

Review the results before reopening access for the next related task, especially after writes. Compare changed resources, returned identifiers, failures, and unexpected destinations against the run contract. If the outcome differs, revoke the session and investigate before the agent receives more authority.

Does a tamper-evident audit log prevent bad agent actions?

No. A tamper-evident record helps you establish what happened after a dispute, but it cannot stop an overbroad authorization while it is active. Prevention comes from short unlock windows, bounded run approvals, and per-call gates for actions that deserve human judgment.

Sallyport

Sallyport runs API calls and SSH commands for your AI agent. The keys stay in a local vault on your Mac; you approve each run and every action lands in a sealed journal.

© 2026 Sallyport · Open source under Apache-2.0 · Oleg Sotnikov