DEV Community

Alex Zhu
Alex Zhu

Posted on

Name a Tool Budget Owner: A One-Page Wiki SOP for Shared Agent Runs

You come back from lunch to a shared lab chat that looks like an incident channel. The agent you started before noon has issued dozens of shell commands against one failing test. A teammate cannot push a hotfix because repeated pytest artifacts have filled the shared workspace disk. Nobody can say who is allowed to kill the process, so the retry loop keeps going.

This is not a model-quality problem in most small teams; it is an ownership problem. Cheap retries feel harmless until the same failing command runs for an hour on a machine other people still need. Without a named Tool Budget Owner, every extra shell call looks reasonable in isolation. You need a one-page wiki SOP before the next shared spike, not another prompt tweak.

What actually burns the shared lab

Most coding agents are a planner wrapped around tools: shell, file edits, test runners, and sometimes git. The planner will keep calling those tools while the transcript still looks like progress. On a laptop you notice the fan. On a shared host you notice a blocked push, a wedged port, or a teammate asking who owns the process.

You should treat tool calls as a budget the same way you treat deploy windows. A budget needs a person, a written cap, and a stop action that does not require a meeting. If you skip those three pieces, the agent becomes an unpaid intern with root-adjacent shell and no timesheet.

Four roles you can paste into the wiki

Keep the roster tiny so a Friday spike still has names attached. Write full names and a backup, not a rotating emoji.

  1. Tool Budget Owner — sets caps, allowlists, and the kill/park/transfer rule for this run.
  2. Runner — starts the agent, records the transcript path, and stays reachable for one working session.
  3. Reviewer — reads tool output that touched git, secrets, or production-shaped config before merge.
  4. Host Steward — owns the shared machine or workspace and can reclaim disk, ports, and processes.

The Tool Budget Owner may be the Runner on a two-person team, but the names still go on the page. When one person holds two hats, write that explicitly so a third teammate does not assume coverage. If the Owner will be offline, transfer the page before the agent starts, not after the first retry storm.

The one-page run (copy this block)

Paste the following into your team wiki and fill the brackets. Do not start the agent until every bracket has a value or an explicit n/a.

# Tool budget run — [date] — [repo]

- Tool Budget Owner: [name] (backup: [name])
- Runner: [name]
- Reviewer: [name]
- Host Steward: [name]
- Workspace / host: [path or hostname]
- Goal (one sentence): [what done looks like]
- Hard stop time: [local time]
- Max tool calls: [n]
- Max consecutive retries of the same command: [n]
- Max files touched: [n]
- Command allowlist file: tool-budget.yaml
- Transcript path: [absolute path]
- On cap hit: kill | park | transfer to [name]
- Secrets rule: no .env, no cloud creds, no production kube contexts
Enter fullscreen mode Exit fullscreen mode

Read the page out loud with the Runner before launch. If you cannot say the stop action in one sentence, the run is not ready. Update the page when you transfer ownership; a stale name is worse than a missing name.

A policy file the Owner can enforce

Proposed example — adapt the numbers to your lab; they are not measured defaults. Keep the file in the repo so the cap travels with the spike.

# tool-budget.yaml
version: 1
run:
  hard_stop_local: "18:00"
  max_tool_calls: 40
  max_same_command_retries: 3
  max_files_touched: 12
allow_commands:
  - pytest
  - ruff
  - python
  - git status
  - git diff
deny_path_globs:
  - ".env"
  - ".env.*"
  - "**/credentials.json"
  - "**/*kubeconfig*"
write_roots:
  - "src/"
  - "tests/"
  - "docs/"
on_cap:
  action: park   # kill | park | transfer
  park_dir: ".agent-park/"
Enter fullscreen mode Exit fullscreen mode

The allowlist is supposed to feel tight. If your agent needs git commit or docker, add those lines in the wiki change, not in a hidden prompt. The Host Steward should reject a run whose policy includes bash -c with no further constraint, because that cap is theater.

A watchdog you run beside the agent

Proposed example — this script does not claim to sandbox the model. It only reads a JSONL transcript your Runner already writes, then prints a stop code the Host Steward can bind to kill.

# tools/check_tool_budget.py
from __future__ import annotations

import json
import sys
from collections import Counter
from pathlib import Path

import yaml

EXIT_OK = 0
EXIT_PARK = 2
EXIT_KILL = 3


def load_policy(path: Path) -> dict:
    return yaml.safe_load(path.read_text())


def load_events(path: Path) -> list[dict]:
    events = []
    for line in path.read_text().splitlines():
        if line.strip():
            events.append(json.loads(line))
    return events


def main() -> int:
    policy = load_policy(Path(sys.argv[1]))
    events = load_events(Path(sys.argv[2]))
    commands = [e.get("command", "") for e in events if e.get("type") == "tool"]
    files = [e.get("path", "") for e in events if e.get("type") == "write"]
    retries = Counter(commands)

    if len(commands) > policy["run"]["max_tool_calls"]:
        print("cap: max_tool_calls")
        return EXIT_PARK
    if retries and retries.most_common(1)[0][1] > policy["run"]["max_same_command_retries"]:
        print("cap: max_same_command_retries")
        return EXIT_PARK
    if len(set(files)) > policy["run"]["max_files_touched"]:
        print("cap: max_files_touched")
        return EXIT_PARK

    denied = tuple(policy["deny_path_globs"])
    for path in files:
        if any(Path(path).match(glob) for glob in denied):
            print(f"kill: denied path {path}")
            return EXIT_KILL
    print("ok")
    return EXIT_OK


if __name__ == "__main__":
    raise SystemExit(main())
Enter fullscreen mode Exit fullscreen mode

Wire it to a loop the Runner already understands. Keep the commands boring so a substitute Host Steward can run them from the wiki.

python3 tools/check_tool_budget.py tool-budget.yaml /tmp/agent-transcript.jsonl
code=$?
if [ "$code" -eq 2 ]; then
  mkdir -p .agent-park
  mv /tmp/agent-transcript.jsonl ".agent-park/$(date +%Y%m%dT%H%M%S).jsonl"
  pkill -f "your-agent-entrypoint" || true
elif [ "$code" -eq 3 ]; then
  pkill -9 -f "your-agent-entrypoint" || true
fi
Enter fullscreen mode Exit fullscreen mode

Label the transcript format in the wiki if your agent SDK uses different keys. The point is a stop code, not a perfect parser. If the agent cannot emit JSONL, have the Runner wrap each tool call with a one-line logger; that wrapper is cheaper than arguing about vendor formats.

Decision table for the stop action

Use this table when the watchdog prints a cap. The Tool Budget Owner picks one cell before the run, not during the storm.

Signal Default action You park when You kill when
Tool call cap hit park Goal is still valid after lunch Host is blocking other work
Same command retried past cap park Flaky test, human will rerun Command mutates git or infra
File-touch cap hit park Extra files are docs or fixtures Writes escaped write_roots
Denied path glob kill Never park on secrets Always kill, then rotate if needed
Hard stop time transfer or kill Owner going offline Steward needs the host back

Park means freeze the transcript and leave a note in the wiki. Kill means terminate the process and reclaim disk. Transfer means a named human takes the page before the next tool call.

Where a free model and free server fit

Shared labs often pick a workspace that already offers free model access and a free server option so a spike does not wait on a procurement thread. If that workspace is MonkeyCode, treat those two options as finite shared capacity: they make the first agent run easy, and they make an unbounded retry loop easy as well. Disclosure: This article was prepared as part of MonkeyCode's product outreach.

The SOP does not depend on one vendor. You still name an Owner, write caps, and store transcripts outside the chat window. The free server is just another host the Steward can reclaim. The free model is just another planner that will keep calling tools until you stop it.

Put the wiki page URL in the workspace README so a guest Runner cannot claim they never saw the caps. If you change allowlists mid-run, stop the agent first; a live policy edit is how two teammates enforce different budgets on one process.

A short launch checklist

Walk these steps in order. If you skip a number, you do not have a run; you have a hope.

  1. Create the wiki page from the template and fill every bracket.
  2. Commit tool-budget.yaml on a branch that is not main.
  3. Confirm the Host Steward can pkill the entrypoint without asking in chat.
  4. Start transcript logging before the first tool call, not after the first failure.
  5. Run the watchdog on an interval the Owner can live with, such as every two minutes.
  6. Stop at the first cap, update the wiki with the stop action, then decide whether to continue.

You can keep a dry-run habit: feed a previous transcript into check_tool_budget.py before you trust the caps. That check is a proposed rehearsal, not a published benchmark. If the script parks a run you still liked, lower the ambition of the goal rather than raising the cap in secret.

Limitations

This playbook does not sandbox the model, and it does not replace code review. A determined agent with unrestricted shell can ignore your YAML unless the Steward wraps the process. The watchdog only sees events you log, so a silent side channel will not trip a cap.

It also does not decide whether the patch is correct. Pair it with whatever review gate you already use for AI-authored diffs. Caps prevent a retry storm; they do not prevent a confident wrong edit that fits inside the budget.

Do not treat the sample numbers as capacity planning. Forty tool calls may be huge for a docs-only spike and tiny for a flaky integration suite. Write numbers your Host Steward can defend on Monday.

Who should not use this approach

Skip this SOP if you are the only person on a personal laptop and you can hear the fans. You still might want a retry cap, but you do not need four wiki roles. Skip it if your company already wraps agents in a job scheduler with quotas, audit logs, and an on-call rotation that pages on runaway processes.

Do not use a free shared server for data you cannot paste into a vendor workspace. This article does not claim retention behavior, isolation, or uptime. If the repo contains production secrets, regulated patient data, or customer exports, keep the agent off that host and off those files.

If your teammates will not name an Owner in writing, stop there. A beautiful YAML file with no human attached is how Friday retry storms start. Name the Tool Budget Owner first, then let the agent touch the repo.

Top comments (0)