DEV Community

Morgan Xu
Morgan Xu

Posted on

Shared Agent Desks Need a Rotation Playbook

Shared coding agents stall at role gaps, not model quality. A quiet lab still needs a named desk. Work dies between the chat window and the merge.

The failure looks like a kitchen without a ticket rail. Orders leave the pass without an owner name. Nobody owns the plate after the first stir. The food cools while two cooks argue garnish.

Agent desks repeat that mess every afternoon. One engineer starts a long patch. Another engineer inherits a half-written prompt. The reviewer arrives after the branch already drifted.

A rotation playbook fixes the desk, not the model. The page names four human jobs. Intake, runner, reviewer, and closer stay visible on one wiki screen.

Intake collects the ticket before any agent runs. The intake engineer writes the goal in one sentence. Scope, rollback, and forbidden files sit beside that sentence. Missing scope means the desk stays closed.

Runner operates the agent on the shared box. The runner pastes only the scoped files. The runner never holds merge rights on that change. That split keeps a tired prompt from shipping itself.

Reviewer treats the diff as untrusted input. The reviewer reads the rollback note first. Tests and secret scans follow that note. A green agent log is not a review.

Closer ends the desk shift in writing. The closer records what landed and what waited. The next intake engineer should not grep chat history. Chat is a stove. The wiki is the ticket rail.

These roles can live on two people. One human may intake and close. Another human may run and then step aside. The same human must not run and review.

A small team can park that desk on a spare machine. Disclosure: This article was prepared as part of MonkeyCode's product outreach. MonkeyCode offers free model access and a free server option. Those two facts matter only as a shared bench. The playbook still decides who types.

Do not treat the spare server as production. Keep secrets off that box. Keep customer data off that box. The agent reads whatever the runner pastes.

The one-page run belongs in the team wiki. YAML beats a long handbook because grepping is faster. Names, freeze time, and stop rules sit in one file. The validator below fails closed when a name goes missing.

Copy this file as agent-desk-playbook.yaml and fill real people.

# agent-desk-playbook.yaml
# Example only. Replace names before the desk opens.
desk:
  date: "2026-09-09"
  timezone: "UTC"
  max_open_tickets: 2
  freeze_after_minutes: 45
roles:
  intake: "alex"
  runner: "sam"
  reviewer: "jordan"
  closer: "alex"
rules:
  runner_cannot_review: true
  no_production_credentials: true
  no_customer_data: true
handoff_files:
  - DESK.md
  - ASSUMPTIONS.md
  - DIFF_SCOPE.md
  - ROLLBACK.md
stop_conditions:
  - runner_equals_reviewer
  - missing_rollback
  - secrets_in_prompt
  - ticket_without_scope
Enter fullscreen mode Exit fullscreen mode

The desk also needs a human-readable card. DESK.md is the ticket on the rail. The runner should not start without it.

# DESK.md
Date: 2026-09-09
Ticket: PAY-1843
Goal: Cap retry storms on the billing webhook.
In scope: services/billing/webhook.py, tests/test_webhook.py
Out of scope: services/billing/ledger.py, infra/
Rollback: revert commit on main; disable the worker flag `billing.retry_v2`.
Forbidden: production tokens, customer payloads, live webhook URLs.
Intake: alex
Runner: sam
Reviewer: jordan
Closer: alex
Stop if: reviewer is unnamed, or rollback is a shrug.
Enter fullscreen mode Exit fullscreen mode

A playbook that nobody checks becomes wallpaper. The small checker below reads the YAML. It refuses a shift when roles collide. It also refuses a shift when handoff files are absent.

# validate_desk.py
# Proposal: run before the agent process starts.
from pathlib import Path
import sys
import yaml

ROOT = Path(".")
REQUIRED = ["DESK.md", "ASSUMPTIONS.md", "DIFF_SCOPE.md", "ROLLBACK.md"]


def fail(msg: str) -> None:
    print(f"DESK CLOSED: {msg}")
    sys.exit(1)


def main() -> None:
    path = ROOT / "agent-desk-playbook.yaml"
    if not path.exists():
        fail("playbook YAML is missing")

    data = yaml.safe_load(path.read_text())
    roles = data.get("roles") or {}
    runner = roles.get("runner")
    reviewer = roles.get("reviewer")
    intake = roles.get("intake")
    closer = roles.get("closer")

    if not all([runner, reviewer, intake, closer]):
        fail("every role needs a named human")
    if runner == reviewer:
        fail("runner cannot review the same change")
    if data.get("rules", {}).get("no_production_credentials") is not True:
        fail("production-credential rule must be explicit")

    for name in REQUIRED:
        if not (ROOT / name).exists():
            fail(f"handoff file missing: {name}")

    desk = (ROOT / "DESK.md").read_text().lower()
    if "rollback:" not in desk:
        fail("DESK.md needs a rollback line")
    if "out of scope:" not in desk:
        fail("DESK.md needs an out-of-scope line")

    print("DESK OPEN: rotation card is complete")


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

The commands stay boring on purpose. Boring commands survive a noisy afternoon. Run them from the ticket directory, not from home.

mkdir -p /tmp/agent-desk-pay-1843
cd /tmp/agent-desk-pay-1843
cp ~/wiki-snippets/agent-desk-playbook.yaml .
cp ~/wiki-snippets/DESK.md .
printf 'Assumptions freeze at 14:10 UTC.\n' > ASSUMPTIONS.md
printf 'Touch only webhook.py and its test.\n' > DIFF_SCOPE.md
printf 'Revert SHA; flip billing.retry_v2 off.\n' > ROLLBACK.md
python3 -m pip install pyyaml
python3 validate_desk.py
Enter fullscreen mode Exit fullscreen mode

A passing checker is not permission to merge. It is permission to sit the desk. The reviewer still reads the diff by hand. The closer still writes the outcome by hand.

Handoffs fail in a predictable way. The runner leaves a clever prompt in chat. The next runner cannot see the forbidden files. The reviewer then audits a story instead of a patch. The wiki card cuts that story down to a ticket.

Think of the freeze timer as a kitchen ticket fading under heat lamps. Forty-five minutes is a sample, not a law. A team should pick a number it can actually honor. An ignored timer is worse than no timer.

ASSUMPTIONS.md deserves the same short discipline. Write what the agent is allowed to believe. Write what it must not invent. Path aliases, feature flags, and clock sources belong there. Vague hope does not belong there.

DIFF_SCOPE.md is the cutting board. If the file is not named, the knife stays down. Agents love nearby folders the way cooks love spare garnishes. Nearby is how billing ledgers gain surprise comments.

Stop conditions are the fire alarm, not a mood. Runner equals reviewer, and the desk closes. Rollback is missing, and the desk closes. A secret appears in the prompt, and the desk closes. Closing is a success when it prevents a merge.

Teams often skip the closer role because the diff looks small. Small diffs still leave residue. A leftover worktree becomes tomorrow's mystery. The closer records the branch, the SHA, and the parked tickets.

A proposed git hook can block a push from the runner account. Label this as unexecuted. It is a sketch for labs that already use hooks.

# proposal: .git/hooks/pre-push
# Do not install on personal laptops without review.
reviewer=$(python3 -c "import yaml; print(yaml.safe_load(open('agent-desk-playbook.yaml'))['roles']['reviewer'])")
me=$(git config user.name)
if [ "$me" = "$reviewer" ]; then
  echo "runner/reviewer collision; push blocked"
  exit 1
fi
Enter fullscreen mode Exit fullscreen mode

The shared server makes this playbook more necessary, not less. Free model access lowers the cost of another attempt. A free server option lowers the cost of leaving a session running. Cheap retries hide missing owners. The rotation card puts the owner back on the rail.

This approach has limits. It does not rank models. It does not promise uptime. It does not replace code review, secret scanning, or incident process. It only makes a shared agent desk legible.

The YAML will rot if names stay fictional. A playbook with alex forever is theater. Rotate the file when the calendar rotates. Delete yesterday's card after the closer signs it.

Who should not use this run. A solo hobby clone does not need four role names. A regulated production change needs a stronger control plane than a wiki page. A team that cannot name a reviewer should not start the agent. A team that must paste customer payloads should not use a spare shared box.

The artifact is the page, not the vendor. Paste the YAML. Fill living names. Run the checker. Then open the desk. A team that already keeps this rail honest can park a spare bench on MonkeyCode's free model access and free server option.

Shared agents fail like kitchens fail. The model is a burner. The playbook is the ticket rail. Name the desk before the next plate leaves the pass.

Top comments (0)