A weekend agent spike is not a demo. The demo is a command that reads frozen time, canned tool results, and one input file, then prints the same bytes on the second run. Chat stays off the critical path. The loop that looked clever on Friday night is, by Sunday, a reducer with a skip list.
This article is a worked example, not a production run log. No live traffic, customer counts, or unpublished benchmarks are claimed. The kit below is labeled as a proposal a side project can copy, run, and throw away.
The failure the weekend actually hits
Agent tutorials reward a live loop. A model plans, a tool runs, another model summarizes, and the terminal looks busy. That loop is a poor weekend demo. Time drifts. Search results change. The second run cannot match the first. Reviewers cannot tell a real tool call from a story the model invented.
A tighter rule fits a side project with a clock that expires on Monday. Freeze every input the loop is allowed to see. Keep policy in code. Leave at most one labeled generative step, and make that step optional. If the fixture path cannot produce the demo, the spike is not ready.
Recent discussion around “agents” often collapses to the same engineering fact. Many prototypes are a classifier plus a handful of branches. Treat that as a feature. The weekend job is to make the branches visible, testable, and boring.
Scope cut before any model call
The project for this log is a receipt reducer, not a general assistant. It accepts a small JSON incident, decides a severity, and prints a four-line receipt. That is the whole ship.
In scope:
- One command:
python reduce.py incidents/sample.json - Frozen clock file, not
datetime.now() - Tool results loaded from
fixtures/tools.json - Deterministic severity table in code
- A second run that diffs clean against
fixtures/demo.stdout
Out of scope on purpose:
- Multi-turn chat
- Live HTTP, live shell, live calendar
- Memory across runs
- A UI, a queue, or a dashboard
- Retry storms and “just one more tool”
Write the cut down where a later self will not negotiate it away.
# SCOPE.md
Ship: print a four-line incident receipt from one JSON file.
Proof: ./demo.sh exits 0 twice with an empty diff against fixtures/demo.stdout.
Non-goals: chat UI, live tools, retries, persistence.
Clock: files/CLOCK.txt is the only time source.
The reducer kit
Five files are enough. More files usually mean the spike is leaking back in.
-
files/CLOCK.txt— one ISO timestamp, committed. -
fixtures/tools.json— every tool name the reducer may read. -
reduce.py— load, branch, print. No network in the default path. -
demo.sh— run twice, compare stdout to a golden file. -
SKIPS.md— what the weekend refused to build.
The clock file is a one-liner. Short on purpose.
2026-09-13T18:00:00Z
The fixture file is the entire tool universe. If a name is missing here, the reducer must fail closed.
{
"get_service_health": {
"api-gateway": {"ok": false, "code": 503},
"billing": {"ok": true, "code": 200}
},
"get_error_budget": {
"api-gateway": {"remaining_pct": 4},
"billing": {"remaining_pct": 67}
}
}
Policy in code, not in a prompt
The interesting part of most weekend agents is a table. Put the table in Python where a diff can see it. The model, if used at all, only proposes a label that the table already knows how to reject.
# reduce.py — worked example, not a measured production service
from __future__ import annotations
import json
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent
CLOCK = (ROOT / "files" / "CLOCK.txt").read_text(encoding="utf-8").strip()
TOOLS = json.loads((ROOT / "fixtures" / "tools.json").read_text(encoding="utf-8"))
SEVERITY = {
(False, True): "sev1",
(False, False): "sev2",
(True, True): "sev3",
(True, False): "ok",
}
def tool(name: str, key: str):
table = TOOLS.get(name)
if table is None or key not in table:
raise SystemExit(f"missing fixture: {name}:{key}")
return table[key]
def reduce_incident(path: Path) -> str:
incident = json.loads(path.read_text(encoding="utf-8"))
service = incident["service"]
health = tool("get_service_health", service)
budget = tool("get_error_budget", service)
budget_low = budget["remaining_pct"] < 10
sev = SEVERITY[(health["ok"], budget_low)]
lines = [
f"clock: {CLOCK}",
f"service: {service}",
f"health: {health['code']}",
f"severity: {sev}",
]
return "\n".join(lines) + "\n"
def main() -> None:
if len(sys.argv) != 2:
raise SystemExit("usage: python reduce.py <incident.json>")
sys.stdout.write(reduce_incident(Path(sys.argv[1])))
if __name__ == "__main__":
main()
The branches are ugly and honest. A 503 plus a thin error budget is sev1. A healthy service with budget to spare is ok. Nothing in that table requires a chat transcript.
Sample input stays tiny.
{
"service": "api-gateway",
"note": "synthetic weekend fixture; not a real outage"
}
Expected stdout is another fixture. Commit it. That file is the demo.
clock: 2026-09-13T18:00:00Z
service: api-gateway
health: 503
severity: sev1
The demo is a script, not a screenshot
demo.sh runs the reducer twice. The second run exists to catch hidden clocks, hidden caches, and accidental network. A screenshot of a chat window cannot do that.
#!/usr/bin/env bash
set -euo pipefail
root="$(cd "$(dirname "$0")" && pwd)"
cd "$root"
python reduce.py incidents/sample.json > /tmp/reducer-out.txt
diff -u fixtures/demo.stdout /tmp/reducer-out.txt
python reduce.py incidents/sample.json > /tmp/reducer-out2.txt
diff -u /tmp/reducer-out.txt /tmp/reducer-out2.txt
echo "demo ok"
Commands a reviewer can replay without the original laptop:
chmod +x demo.sh
./demo.sh
python reduce.py incidents/sample.json
If diff is noisy, the spike is still a spike. Do not “fix” it by widening the golden file. Find the unfrozen input.
Optional generative step, plugged in last
Some weekends still want a model. Keep it behind an explicit flag and a contract. The model may return one of {sev1, sev2, sev3, ok}. Any other string is a hard fail. The fixture path remains the merge gate.
# proposal only: optional labeler, default off
ALLOWED = {"sev1", "sev2", "sev3", "ok"}
def maybe_relabel(base: str, raw: str | None) -> str:
if raw is None:
return base
label = raw.strip().lower()
if label not in ALLOWED:
raise SystemExit(f"model label not in contract: {raw!r}")
return label
A decision table keeps the flag from becoming a second product.
| Situation | Path | Why |
|---|---|---|
| Golden demo, CI, code review | fixtures only | Bytes must match |
| Exploring a new severity name | model flag, still schema-checked | Contract stays smaller than the prompt |
| Live tools or mutating APIs | out of scope | Weekend side project, not an on-call bot |
| Unlabeled logs with no fixture | skip the feature | Do not invent tools at runtime |
The model does not fetch health. The model does not invent a service name. Those values already live in JSON.
When the remaining step is not on the laptop
Disclosure: This article was prepared as part of MonkeyCode's product outreach.
A laptop-only run is enough for the reducer. Some side projects still want the optional labeler off-laptop so the demo machine stays small. MonkeyCode is an open-source project that currently offers free model access and a free server option. Those two availability notes are the only product claims in this log. No model names, token quotas, hardware, uptime, or speed figures are assumed here, because those numbers go stale and do not change the kit.
The remote box, if used, should run the same demo.sh with the model flag off first. A server that cannot reproduce the fixture receipt is not a demo host. It is another chat window.
A minimal remote check, still a proposal:
# proposal: same repo, same fixtures, no hidden env
export REDUCER_MODE=fixtures
./demo.sh
If that fails, stop. Do not debug the model until the frozen path is green.
What this weekend skips
SKIPS.md is part of the ship, not an apology. Recording the skips keeps Monday from reopening Friday's argument.
# SKIPS.md
- Live get_service_health. Would break the golden file.
- Multi-service fan-out. Scope is one incident file.
- Prompt-only severity. The table in reduce.py is the policy.
- Streaming tokens in the demo. Reviewers need a closed byte string.
- Auto-paging. No on-call rotation in a weekend spike.
Each skip maps to a missing fixture or a missing row in SEVERITY. If a skip cannot be named in one line, it is probably still in the code.
Limitations, and who should not use this
The reducer is a clamp, not an architecture. It will not discover unknown services. It will not notice that production health has drifted from fixtures/tools.json. It will not replace tracing, auth, or an incident commander.
Do not use this approach when:
- Tools have real side effects (refunds, deploys, mail).
- The point of the work is a conversational product.
- Fixtures cannot be collected without leaking secrets.
- Severity policy is legally or contractually load-bearing and needs a reviewed rules engine.
- The team cannot explain a branch without pasting a prompt.
Time-sensitive product claims around any hosted model should be re-checked on the project’s own site before a public post. This log does not snapshot quotas, regions, or hardware, and it should not be cited as if it did.
Closing the weekend
The useful artifact is the empty diff. A four-line receipt, a frozen clock, and a skip list beat a longer agent transcript that nobody can replay. Keep the optional model behind a contract. Keep the server, if any, honest enough to run demo.sh without it.
If the remaining generative step needs a remote box, MonkeyCode’s free model access and free server option are available to try on that narrow path. The reducer still has to pass with the model unplugged.
Top comments (0)