DEV Community

Charlie Hu
Charlie Hu

Posted on

The Demo Is a Reducer: A Weekend Fixture Kit for Agent Side Projects

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.
Enter fullscreen mode Exit fullscreen mode

The reducer kit

Five files are enough. More files usually mean the spike is leaking back in.

  1. files/CLOCK.txt — one ISO timestamp, committed.
  2. fixtures/tools.json — every tool name the reducer may read.
  3. reduce.py — load, branch, print. No network in the default path.
  4. demo.sh — run twice, compare stdout to a golden file.
  5. SKIPS.md — what the weekend refused to build.

The clock file is a one-liner. Short on purpose.

2026-09-13T18:00:00Z
Enter fullscreen mode Exit fullscreen mode

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}
  }
}
Enter fullscreen mode Exit fullscreen mode

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()
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

Commands a reviewer can replay without the original laptop:

chmod +x demo.sh
./demo.sh
python reduce.py incidents/sample.json
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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)