A weekend agent demo is finished when one named path returns a checked result. A larger prompt does not finish it. Free model access and a free server option lower the cost of a trial, and they leave the failure mode unchanged: the side project dies in unfinished scope.
Disclosure: This article was prepared as part of MonkeyCode's product outreach. The only product claims used here are operator-supplied: free model access and a free server option. Model names, token quotas, hardware, duration, and permanence are omitted because they were not verified for this draft. Current docs should be checked before either option is treated as a fixed budget.
The public posts on this account already cover small controls around agent side projects: merge gates, tool allowlists, call envelopes, circuit breakers, dry-run staging, and worker heartbeats. This note does not rebuild those controls. It covers the cut that has to happen before any of them earn a place in a two-day repo. The audience is a developer shipping a narrow demo, not a team designing a platform.
Cut first, then host
The working demo is a local command. It reads a scope card, accepts one intent, and prints a fixture result plus an explicit skip ledger. A live call stays behind a flag that defaults to off.
A free server can host that same process later. It is not required to prove the slice. Saturday defines the card. Sunday runs the fixture path and writes down what was refused.
Anything that needs a model token is a follow-up slice, and only if the fixture cannot show the response shape honestly. That order is the method. Hosting is a later convenience, not the proof.
Scope card
The card is JSON so the draft runner has no parser dependency. Field names stay blunt on purpose. A reader should see the cut without a diagram.
{
"slice_id": "invoice-status-v0",
"allowed_intents": ["lookup_invoice_status"],
"fixture": {
"tool": "billing.lookup",
"input": {"invoice_id": "INV-1042"},
"output": {"status": "open", "currency": "USD", "amount_cents": 4200}
},
"skipped": [
"multi-invoice search",
"refunds and other writes",
"a browser UI",
"retries, workers, and cron",
"a second model call to explain the status"
],
"live": {
"enabled_by_default": false,
"env_base_url": "AGENT_SLICE_BASE_URL",
"path": "/v0/slice",
"timeout_seconds": 10
}
}
slice_id names the demo. allowed_intents is a closed set. fixture is the result a reviewer can rerun without an account. skipped is the scope cut, stored as data so it shows up in the command output.
live records how a later call would be addressed. The path /v0/slice is a local contract for this side project. It is not a documented vendor endpoint, and it should not be copied into a client as if it were one.
Runner
The module below is a proposal. It has not been timed, load-tested, or pointed at a hosted offer. It refuses unknown intents before any network call. It replays the fixture unless --live is set. It prints the skip list on every exit path so a green demo cannot hide the cut.
#!/usr/bin/env python3
"""Unexecuted proposal: one-intent scope runner for a weekend demo."""
from __future__ import annotations
import argparse
import json
import os
import sys
import urllib.error
import urllib.request
from pathlib import Path
def load_card(path: Path) -> dict:
try:
card = json.loads(path.read_text(encoding="utf-8"))
except json.JSONDecodeError as exc:
raise SystemExit(f"card_not_json: {exc}") from exc
for key in ("slice_id", "allowed_intents", "fixture", "skipped", "live"):
if key not in card:
raise SystemExit(f"card_missing_field: {key}")
if not isinstance(card["allowed_intents"], list) or not card["allowed_intents"]:
raise SystemExit("card_needs_one_intent")
return card
def decide(card: dict, intent: str, live: bool) -> dict:
skipped = list(card.get("skipped") or [])
allowed = set(card["allowed_intents"])
if intent not in allowed:
return {
"ok": False,
"slice_id": card["slice_id"],
"reason": "intent_outside_slice",
"skipped": skipped,
}
if not live:
return {
"ok": True,
"slice_id": card["slice_id"],
"mode": "fixture",
"result": card["fixture"]["output"],
"skipped": skipped,
}
env_name = card["live"]["env_base_url"]
base = os.environ.get(env_name, "").rstrip("/")
if not base:
return {
"ok": False,
"slice_id": card["slice_id"],
"reason": "live_requested_but_base_url_missing",
"skipped": skipped,
}
payload = json.dumps(
{
"slice_id": card["slice_id"],
"intent": intent,
"input": card["fixture"]["input"],
}
).encode("utf-8")
timeout = int(card["live"].get("timeout_seconds", 10))
req = urllib.request.Request(
base + card["live"]["path"],
data=payload,
headers={"content-type": "application/json"},
method="POST",
)
try:
with urllib.request.urlopen(req, timeout=timeout) as resp:
body = json.loads(resp.read().decode("utf-8"))
except (urllib.error.URLError, TimeoutError, json.JSONDecodeError) as exc:
return {
"ok": False,
"slice_id": card["slice_id"],
"reason": "live_call_failed",
"detail": type(exc).__name__,
"skipped": skipped,
}
return {
"ok": True,
"slice_id": card["slice_id"],
"mode": "live",
"result": body,
"skipped": skipped,
}
def main() -> int:
parser = argparse.ArgumentParser(description="Run one scoped demo path")
parser.add_argument("--card", required=True)
parser.add_argument("--intent", required=True)
parser.add_argument("--live", action="store_true")
args = parser.parse_args()
report = decide(load_card(Path(args.card)), args.intent, args.live)
json.dump(report, sys.stdout, indent=2)
sys.stdout.write("\n")
return 0 if report.get("ok") else 2
if __name__ == "__main__":
raise SystemExit(main())
Two behaviors are deliberate. The live failure returns an error type, not the exception text, so a URL or upstream body is less likely to land in a pasted demo log. The fixture path never reads AGENT_SLICE_BASE_URL.
A configured host cannot change the default demo. That split is what makes the weekend rerunnable after a laptop reboot, with or without a network.
Commands and expected reports
Save the card as scope.invoice.json and the module as slice_runner.py. Then run the dry path:
python3 slice_runner.py \
--card scope.invoice.json \
--intent lookup_invoice_status
The expected report shape is:
{
"ok": true,
"slice_id": "invoice-status-v0",
"mode": "fixture",
"result": {"status": "open", "currency": "USD", "amount_cents": 4200},
"skipped": ["multi-invoice search", "refunds and other writes"]
}
An intent outside the card must fail closed, with no socket:
python3 slice_runner.py \
--card scope.invoice.json \
--intent refund_invoice
echo "exit=$?"
reason should be intent_outside_slice, and the exit code should be 2. The skip list should still print. A reviewer who asks for refunds gets a recorded refusal, not a silent success.
Requesting a live call without the env var is the third check:
python3 slice_runner.py \
--card scope.invoice.json \
--intent lookup_invoice_status \
--live
Expected reason: live_requested_but_base_url_missing. The runner must not guess a host, and it must not fall back to the fixture while claiming a live result. Those are different failures. Mixing them makes the demo look healthier than the setup is.
Decision table
| Weekend pressure | Keep in v0 | Replace with the fixture | Write into skipped
|
|---|---|---|---|
| Add one more intent | Only if the sentence still names one path | — | The extra intent |
| Show a model answer | Only for a field the fixture cannot shape | Status, amount, currency | Explanations and chat |
| Put it on a server | One process, one route, after the local command works | A checked-in JSON file | Queues and background jobs |
| Make it look finished | The skip list in the output | — | A UI that hides skips |
| Handle failure | Non-zero exit and a reason code | — | Retries and backoff trees |
Use the table as a review checklist, not as a slogan. If a row cannot be filled without inventing a metric, the row stays blank and the work stays skipped.
Where a free route actually helps
Free model access is relevant on the step a fixture would fake. In this invoice slice, that step does not exist yet. Status, currency, and amount are canned. A later card might allow one intent, classify_invoice_note, whose input is a short ambiguous string and whose output is a label plus a reason code.
That is the first honest use of a model. It is still one request, still checked against allowed_intents, and still off unless --live is passed. A free server option is relevant after that local command is boring.
Copy the same three files to the host, set the base URL only for the live flag, and keep the fixture command as the regression check. Region, size, and how long the offer lasts are not known here. If the host is unavailable on demo day, the fixture path still runs on a laptop. That fallback is the reason the card exists.
Do not treat either option as a capacity plan. This draft measured nothing: no latency, no token count, no concurrency. A number copied from an older post would be worse than a blank. Confirm the current terms in the product docs before spending a weekend on a live flag.
What the weekend skips
The skip list is the build log. It is not a backlog disguised as humility.
- No planner loop. One intent in, one result out. Turn caps belong to a different note.
- No tool bus. The fixture names one tool string. It does not route, stage, or allowlist a catalog.
- No receipt book and no heartbeat. Those mechanisms answer other questions. Pulling them in would erase the cut.
- No write path. Refunds stay skipped because a demo mutation is how a side project stops being a demo.
- No second model call to explain the status. Explanation text is how scope leaks back in.
- No claim about a token pool, a machine size, or an end date. Unverified numbers stay out of the README as well as this page.
Failure notes worth keeping
A few failures are more instructive than the happy path.
- A card with an empty
allowed_intentslist should exit on load. A slice that allows everything is not a slice. - A live timeout should surface as
live_call_failedwithdetailset to the exception type. The demo script can then say the host did not answer, which is a true statement. - A fixture output that omits a field the reviewer expects should be fixed in the card, not patched in the runner. Hidden defaults recreate the unfinished product.
- Editing
skippedwithout editing the spoken demo is a process bug. The command output is the script.
Clear field names do more work here than a comment. If skipped needs a paragraph to explain itself, the cut is still fuzzy and the card is not ready to demo.
Test plan before calling it a demo
These checks are local and manual until they are pasted into a real file and run. Until then they are a plan, not a result.
- Parse failure: truncate the JSON and confirm a non-zero exit with
card_not_json. - Missing field: delete
skippedand confirmcard_missing_field. - Fixture path: allowed intent, no
--live,resultequalsfixture.output. - Reject path: unknown intent, no socket, exit code
2. - Live guard:
--liveand an empty base URL, no guessed host, no fixture fallback. - Skip visibility: every string in
skippedappears in the report for both success and refusal. - Timeout lock:
timeout_secondsstays at 10. A hung process must not become the demo.
A single assertion can lock check 3 once the function is imported:
def test_fixture_path():
card = {
"slice_id": "invoice-status-v0",
"allowed_intents": ["lookup_invoice_status"],
"fixture": {"output": {"status": "open"}},
"skipped": ["refunds and other writes"],
"live": {"env_base_url": "AGENT_SLICE_BASE_URL", "path": "/v0/slice"},
}
report = decide(card, "lookup_invoice_status", live=False)
assert report["mode"] == "fixture"
assert report["result"]["status"] == "open"
assert report["skipped"] == ["refunds and other writes"]
Run it only after the file exists in the repo. A pasted assertion is not a passing suite. Record the command and the exit code in the README next to the skip list, so the next session does not have to reconstruct the demo from memory.
Who should not use this
This runner is a scope fence for a side project. It is not authentication, not authorization, and not a sandbox. A person who can edit the card can widen the slice. A person who can set the base URL can send the payload to an unintended host.
Skip the approach when any of these are true:
- The demo must mutate real billing data or other customer state.
- A reviewer has already been promised several intents. Cut the promise before writing code.
- The audience needs a latency, cost, or uptime figure. None were measured.
- The host must stay up unattended. This draft does not establish that.
- Secrets need more care than one env var that is never printed. The example does not redact arbitrary logs.
- The work is a multi-tenant product. A JSON card in a repo root is the wrong boundary.
Clear fields beat a cleaner abstraction that hides the skip list. If a comment is required to explain skipped, the field name is wrong, not the reader.
After the card is boring
Leave the card in the repo root. Add a second intent only by copying the card to a new slice_id and deleting the old promises from the spoken demo. If a free model route and a free server are still available for that next slice, spend them on the one step the fixture cannot show, and confirm the current terms before relying on either. The weekend result is the cut. A longer catalog can wait.
Top comments (0)