DEV Community

Morgan Xu
Morgan Xu

Posted on

Stop Agent Guesses With a Wiki Shift Card

A free coding agent still needs a named human shift. Teams that skip the handoff inherit silent assumptions. This playbook turns that gap into one wiki page.

Cheap agent patches look finished until Monday review. The model filled every blank with a guess. Those guesses become production debt with no owner.

The fix is a shift card, not another prompt. Three humans share one page before the agent starts. The page travels with the branch until merge.

Three roles on one page

Name the first role as the Assumption Clerk. That person writes what the agent must not invent. Architecture, auth, and data ownership stay in human words.

The clerk does not design a new system on the card. The clerk only records constraints the repo already chose. Blank lines are more dangerous than strict lines.

Name the second role as the Shift Runner. That person starts the agent only after the card exists. The runner never invents missing facts during the session.

If the agent asks for a missing constraint, work pauses. The clerk updates the card in the same hour. The session resumes only after the page changes.

Name the third role as the Merge Signer. That person reads the card against the diff. Unsigned assumptions must not ride into main.

The signer is not a rubber stamp for speed. The signer looks for new files the card never named. Surprise paths mean the agent left the runway.

Think of a two-pilot radio handoff, not a chat log. The departing pilot states fuel, heading, and weather. The arriving pilot repeats the same facts aloud.

Silence is not a transfer in that cockpit. A coding agent behaves like a quiet copilot. It will choose a heading if nobody speaks.

The wiki card is the headset script. Positive transfer means both humans said the same constraints. The agent then flies only inside that corridor.

A card the runner cannot skip

The block below belongs in the team wiki. A copy also belongs on the pull request body. The card works as a gate, not decoration.

# AGENT_SHIFT.yml — paste into the wiki and the branch
ticket: TICKET-ID
branch: feature/short-name
clerk: name
runner: name
signer: name
window:
  start: "2026-09-07T09:00:00Z"
  end: "2026-09-07T13:00:00Z"
must_not_invent:
  auth: "existing session cookie"
  datastore: "current postgres schema only"
  routes: "no new public endpoints"
  errors: "keep problem+json bodies"
known_facts:
  - "service owns /v1/orders only"
  - "background jobs stay on the current queue"
open_questions: []
done_means:
  tests: "make test-orders"
  rollback: "git revert on this branch"
status: "draft"  # draft | live | signed
Enter fullscreen mode Exit fullscreen mode

The file name should stay stable across tickets. AGENT_SHIFT.yml at the repo root is enough. Historical cards belong in docs/shifts after merge.

The Shift Runner still needs a machine that can fail safely. A dedicated workstation can host the runner without extra cost. A shared free server can host the same runner instead.

MonkeyCode is an open-source project with free model access. It also provides a free server option for shared runs. Disclosure: This article was prepared as part of MonkeyCode's product outreach.

The product does not replace the three human roles. It only gives the runner a shared place to work. The shift card still governs what the agent may touch.

The card should sit on the server before any agent command. The snippet below refuses to start without a live card. It is a template, not a production hardening suite.

#!/usr/bin/env bash
# check-shift.sh — run from the repo root
set -euo pipefail

CARD="${1:-AGENT_SHIFT.yml}"

if [[ ! -f "$CARD" ]]; then
  echo "shift card missing: $CARD" >&2
  exit 2
fi

need() {
  local key="$1"
  if ! grep -E "^${key}:" "$CARD" >/dev/null; then
    echo "shift card missing key: $key" >&2
    exit 3
  fi
}

need ticket
need clerk
need runner
need signer
need status

if grep -E '^status: "live"' "$CARD" >/dev/null; then
  if grep -E '^open_questions:' "$CARD" >/dev/null \
     && ! grep -E '^open_questions: \[\]' "$CARD" >/dev/null; then
    echo "live shifts cannot keep open questions" >&2
    exit 4
  fi
fi

if ! grep -E '^status: "live"' "$CARD" >/dev/null; then
  echo "refuse to start: status is not live" >&2
  exit 5
fi

echo "shift card accepted: $CARD"
Enter fullscreen mode Exit fullscreen mode

A runner then wraps the real agent entrypoint. The wrapper below is a local pattern to copy. Teams should try it on a throwaway clone first.

#!/usr/bin/env bash
# run-shift.sh
set -euo pipefail
./check-shift.sh AGENT_SHIFT.yml
# Replace the next line with the team's agent command.
exec "$@"
Enter fullscreen mode Exit fullscreen mode

Sample invocation stays boring on purpose for a reason. Boring commands survive a noisy on-call better than wrappers. Fancy launchers often hide the missing shift card.

chmod +x check-shift.sh run-shift.sh
./run-shift.sh make agent-session
Enter fullscreen mode Exit fullscreen mode

CI should read the same file the runner used. The Python check below fails a pull request on drift. It flags empty owners and leftover open questions.

#!/usr/bin/env python3
"""fail_if_shift_unsigned.py — template for CI."""
from __future__ import annotations

import sys
from pathlib import Path

try:
    import yaml
except ImportError:
    print("install pyyaml in the CI image", file=sys.stderr)
    sys.exit(1)

path = Path("AGENT_SHIFT.yml")
if not path.exists():
    print("AGENT_SHIFT.yml missing from the branch", file=sys.stderr)
    sys.exit(2)

data = yaml.safe_load(path.read_text()) or {}
required = ["ticket", "clerk", "runner", "signer", "must_not_invent", "done_means"]
missing = [key for key in required if not data.get(key)]
if missing:
    print("shift card missing fields:", ", ".join(missing), file=sys.stderr)
    sys.exit(3)

if data.get("open_questions"):
    print("open questions must be empty before merge", file=sys.stderr)
    sys.exit(4)

if data.get("status") != "signed":
    print("merge signer has not marked status signed", file=sys.stderr)
    sys.exit(5)

invent = data.get("must_not_invent") or {}
if not isinstance(invent, dict) or len(invent) < 3:
    print("must_not_invent needs at least three constraints", file=sys.stderr)
    sys.exit(6)

print("shift card signed and complete")
Enter fullscreen mode Exit fullscreen mode

The script belongs in the pipeline as one job. The job should run on every pull request to main. A green agent session with a red card still fails.

# snippet for the team's existing CI
name: shift-card
on:
  pull_request:
    branches: [main]
jobs:
  card:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pip install pyyaml
      - run: python3 fail_if_shift_unsigned.py
Enter fullscreen mode Exit fullscreen mode

Handoff across time zones follows the same page. The departing runner writes the last command into the card. The arriving runner reads that line before any new prompt.

A short amendment log keeps the radio honest. Each change to must_not_invent needs a clerk name. The signer rejects cards that mutated during the session in silence.

amendments:
  - at: "2026-09-07T10:12:00Z"
    by: "clerk-name"
    change: "forbid new redis keys"
Enter fullscreen mode Exit fullscreen mode

The analogy holds when the agent writes tests. Tests that mock a datastore the card forbade are drift. Tests that skip rollback notes are also drift.

Technical debt gets cheap when patches get cheap. The unpaid part is the invented architecture around the patch. The shift card makes that invention visible before merge.

Limits of the playbook

This approach fits small product teams with shared repos. It also fits contractors who rotate through one service. It does not fit a solo spike on a throwaway branch.

This playbook is the wrong tool for incident command. A live outage needs a different script and tighter time. It also fails as a hiding place for missing product decisions.

The card cannot prove the model understood a constraint. Humans still read the diff with the card in view. Free model access does not remove that reading.

The free server option does not add extra isolation by itself. Shared runners can leak secrets if the team is careless. Secrets stay out of prompts and out of the card.

Clock windows on the card are social contracts, not locks. The bash gate does not kill a runaway process at the end. Teams that need hard kills should add their own supervisor.

The wiki page should start on one service only. A second service waits until one merge is signed. A paper process that nobody follows is worse than none.

Teams may try MonkeyCode's free server after the shift card exists.

Top comments (0)