Build Token-Optimised Agent Harness Automations
The central rule: schedule the check, not the LLM. Let code decide whether anything changed; let the model reason only after change or ambiguity is established.
The most expensive cron job is often not the one that writes a lot. It is the one that wakes a full agent hundreds of times to say nothing.
1. The problem: agents optimise for completion, not token efficiency
An LLM is trained and prompted to produce a useful outcome. Unless cost is made part of the architecture, the easiest path is usually to:
wake a full agent on every tick;
load its system prompt, tools, skills, and job prompt;
call APIs to discover that nothing changed;
reason about the empty result;
write “nothing to report”; and
repeat the entire process at the next interval.
This is not the model deliberately trying to waste tokens. It is a mismatch between objectives: the agent optimises the current run for task success, while the operator cares about useful outcomes per token across thousands of runs. The model cannot recover tokens that the scheduler already spent waking it.
The Agent Harness engineering guide makes the underlying cost model explicit:
prompt caching is “sacred” because mutating or rebuilding context multiplies cost;
every core model tool is sent on every API call, so new tools have a permanent token footprint;
capability should therefore live at the edge, as scripts, skills, service-gated tools, plugins, or MCP, before becoming permanent model context.
What we were spending before optimisation
Our audits found three useful baselines. They describe different windows, so they should not be added together:
Active daily fleet audit — ~1.27 million tokens/day. Daily active jobs at the time, excluding the paused high-frequency engagement poller.
Known active jobs — ~10.8 million tokens/week. Measured weekly footprint from jobs with usable run data; incomplete because several jobs had not yet run.
Engagement poller — 115.8 million tokens over 30 days. 760 model-backed polling runs, averaging ~152,000 tokens each, with every retained result silent.
The final local session ledger now contains 117.4 million processed tokens across 782 pre-conversion poller sessions through the switch-over, averaging ~150,000 tokens per run. The 115.8-million figure is retained above because it is the clean 30-day audit snapshot used to make the optimisation decision.
The same engagement poller, if allowed to fire every ten minutes at the then-observed per-run average, implied ~28.6 million tokens/day. That was a schedule-frequency projection, not the measured 30-day total.
The most important number is not the largest one. It is this: 115.8 million tokens in the audit window produced no user-visible output. We were paying an LLM to establish a fact a short script could establish first: “nothing changed.”
2. The right mental model: clock, sensor, reasoner
Treat every automation as three separate components:
Clock — decides when to check.
Sensor — fetches state and decides whether anything material changed.
Reasoner — decides what the change means and what to do about it.
A conventional agent cron collapses all three into one LLM run. A token-efficient automation keeps them separate:
Timer fires
↓
Cheap deterministic sensor
↓
No change? ───────────────→ stop silently, zero LLM tokens
↓ change
Small, evidence-rich payload
↓
LLM reasoning only if needed
↓
Deterministic action + verificationThis changes the cost equation from:
old cost = number of scheduled ticks × full agent costto:
new cost = number of meaningful events × scoped agent costPolling frequency can now increase without model spend increasing at the same rate.
3. First choose the cheapest correct execution mode
Use this decision tree before writing the job:
A. Is the output fully determined by code?
Examples: disk over 85%, an API status changed, three approved posts are due, today is a weekend.
Use script-only cron with no_agent=True.
The script is the job.
Non-empty stdout is delivered verbatim.
Empty stdout is a silent tick.
A non-zero exit becomes an error alert.
There is no model call and therefore zero LLM tokens.
B. Can code detect change, but interpretation needs reasoning?
Examples: a new customer reply, a changed grant page, a materially different analytics snapshot.
Use monitor mode with monitor_script or monitor_url.
The source runs first.
The harness hashes its exact output.
Unchanged output records a silent
no_changetick and skips the agent entirely.Changed output injects a compact diff plus the new state into a normal agent run.
The first tick establishes a baseline and runs the agent.
Monitor comparison, stable hashing, baseline handling, and change-diff construction live in the monitor module; suppression occurs before normal agent setup in the scheduler.
C. Does every run genuinely require judgement?
Examples: rank fresh research, summarise a changing report, draft nuanced outreach.
Use a normal LLM cron, but constrain it:
pass only the relevant skills;
restrict
enabled_toolsetsto the tools it can actually need;inject only compact upstream results with
context_from;pin an appropriate cron model/provider;
set explicit success and stop conditions;
keep deterministic filtering and formatting outside the prompt.
D. Is this an interactive loop rather than unattended work?
Use a session loop only when the work belongs in the current session. Each wakeup is a real agent turn. For unattended work that must survive restarts, use cron.
Self-paced loop mode uses local reply-digest comparison to back off from the minimum cadence toward a ceiling when replies stop changing, and resets to the minimum when they do change. Always keep a stop condition or loops.max_ticks budget.
4. Build a token-optimised cron job step by step
Step 1 — Write the outcome contract
Specify:
what state is being watched;
what counts as material change;
what output should be delivered;
what should happen on no change;
what constitutes failure;
whether the action is read-only, draft-only, or externally committing.
Bad:
Check replies every ten minutes and tell me what happened.
Better:
Every ten minutes, fetch reply IDs newer than the stored cursor. If there are none, emit nothing. If there are new replies, output canonical JSON containing only reply ID, sender, timestamp, and text for an agent to classify. Never send a reply automatically.
Step 2 — Measure the unoptimised baseline
Record, per job:
runs per day/week;
input, cached-input, output, and reasoning tokens;
average and p95 tokens per run;
percentage of runs with a useful output;
percentage of
SILENT/no-op runs;errors and retries;
cost per useful event.
Use:
useful-token efficiency = useful outcomes / total processed tokens
waste ratio = no-op agent runs / all agent runsDo not optimise only the prompt. A 20% smaller prompt still wastes 80% of the cost if 100% of quiet ticks unnecessarily invoke a model.
Step 3 — Move sensing into a deterministic script
A good sensor:
makes the minimum API/database calls;
has bounded timeouts;
normalises ordering;
removes timestamps or volatile metadata that do not represent change;
persists a cursor or hash atomically;
emits machine-readable, minimal evidence;
sends diagnostics to stderr, not stdout;
exits non-zero on genuine failure.
Example watchdog:
#!/usr/bin/env python3
import json
from pathlib import Path
STATE = Path.home() / ".agent-harness" / "state" / "example-cursor.json"
items = fetch_items() # bounded network call
cursor = load_cursor(STATE) # return a safe default if absent
new = sorted(
(x for x in items if x["id"] > cursor),
key=lambda x: x["id"],
)
if not new:
raise SystemExit(0) # empty stdout = silent tick
save_cursor_atomically(STATE, new[-1]["id"])
print(json.dumps(new, sort_keys=True, separators=(",", ":")))For monitor_script, do not include “checked at 12:03” or unstable list ordering. Exact bytes are hashed; volatile output makes every tick look changed.
Step 4 — Decide who owns the message
If stdout already is the final message, choose no-agent mode:
{
"action": "create",
"name": "API status watchdog",
"schedule": "every 10m",
"script": "api_status_watchdog.py",
"no_agent": true,
"deliver": "origin"
}If the model must interpret a changed payload, choose monitor mode:
{
"action": "create",
"name": "New reply triage",
"schedule": "every 10m",
"monitor_script": "new_reply_snapshot.py",
"prompt": "Classify only the changed replies. Return urgency, intent, evidence, and a draft. Never send externally.",
"enabled_toolsets": ["file"],
"deliver": "origin"
}no_agent and monitor mode are intentionally different paths: use one or the other, not both.
Step 5 — Minimise the agent surface
When an agent run is justified:
Attach only the necessary skills. A skill should carry the reusable procedure so the job prompt stays short.
Restrict toolsets. A job that reads a collected artifact does not need browser, GitHub, email, and terminal schemas.
Pass compact data, not history. Use
context_fromto chain jobs through their latest completed outputs rather than rerunning upstream research.Use a stable system/tool prefix. The Agent Harness protects prompt caching by keeping conversation prefixes byte-stable.
Use the cheapest model that passes the quality bar. Pin cron inference deliberately; do not let unattended work drift with an interactive model change.
The scheduler resolves a run model in the order per-job pin → cron.model → global default. Unpinned drift can fail closed before inference, preventing surprise spend.
Step 6 — Make no-op and retry behaviour explicit
For script-only jobs:
empty stdout = successful silence;
non-empty stdout = delivery;
non-zero exit = visible failure alert.
For monitor jobs:
stable unchanged output =
no_changewith no LLM;first successful output = baseline plus first agent run;
failed fetch = failure, not a new baseline;
content change = diff and new state passed to the agent.
For all jobs:
use atomic state writes;
make effects idempotent;
deduplicate by stable external IDs;
separate “already handled” from “failed”;
never make a retry duplicate a post, email, row, or payment.
Step 7 — Verify the real path
Before enabling the schedule, test at least four cases:
No change: exit 0, empty stdout, no delivery, no LLM session.
Material change: one bounded payload and one intended delivery/agent run.
Same change again: idempotent no-op.
Dependency failure: non-zero exit and actionable error, without corrupting state.
Then run the cron manually once, inspect the execution record, and verify the receiving channel. A script that works in your shell may still fail under cron because the working directory, PATH, credentials, or delivery context differs.
Step 8 — Measure after deployment
Track:
scheduled ticks;
suppressed/no-change ticks;
model-backed runs;
useful deliveries;
processed tokens per useful delivery;
false-positive wakeups;
missed events;
duplicate actions;
runtime and API cost outside the LLM.
The target is not merely “fewer tokens.” It is zero model tokens for deterministic no-ops, and bounded model tokens for genuine ambiguity.
5. Build a token-efficient process
A process is broader than a cron job. Model it as a state machine:
SENSE → NORMALISE → COMPARE → DECIDE → ACT → VERIFY → PERSISTAssign each stage deliberately:
Sense — Script/API query: deterministic and cheap.
Normalise — Script: removes noise before hashing or prompting.
Compare — Script/hash/SQL: equality and thresholds do not need language reasoning.
Decide — Rules first, LLM only for ambiguity: keeps judgement scarce.
Act — Deterministic API function: predictable side effects and retries.
Verify — Script/read-back: evidence, not model confidence.
Persist — Database/file cursor: idempotency and auditability.
The escalation ladder
Use the first rung that solves the task:
static rule;
SQL/filter/threshold;
deterministic score or ranking;
compact classifier model;
full agent with tools;
human approval for irreversible or reputational actions.
This is the automation equivalent of the Agent Harness “footprint ladder”: capability at the edge before permanent model surface.
6. Build a token-efficient initiative loop
An initiative loop is a recurring system that does more than report state: it senses opportunities, chooses work, produces an artifact, learns from outcomes, and repeats.
The wasteful version asks a full agent every morning to rediscover the world and invent work. The efficient version turns initiative into a bounded pipeline.
Step 1 — Define the objective and terminal states
Example:
Maintain a pipeline of evidence-backed campaign drafts. Create at most one draft per eligible slot. Never publish. Stop when no campaign passes the rules.
Define terminal states such as:
no eligible input;
artifact already exists;
approval required;
objective achieved;
budget exhausted;
dependency unavailable.
Step 2 — Fetch primary signals once
Collect the small set of sources needed to make the decision. Do not let each downstream stage repeat discovery.
Our initiative process fetches campaign truth, audience signals, and conversion data, then ranks campaigns from those measured inputs.
Step 3 — Encode stable decisions as rules
If a decision is explainable as code, make it code:
exclude expired inputs;
require measurable conversion;
rank by conversion and friction;
route low-friction offers to broad audiences;
reject banned mechanics;
cap outputs per run.
In our initiative loop, ranking, friction, exclusions, lane mapping, and sunset guards are deterministic. The LLM is not repeatedly paid to remember the same policy.
Step 4 — Make creation idempotent
Before writing, check whether the loop already produced an artifact for that date, slot, origin, or external ID. A retry should skip existing work, not duplicate it.
The initiative process queries existing rows and skips slots already created. It also treats “all skipped because they already exist” as a legitimate no-op while treating “candidates existed but none were written” as failure.
Step 5 — Keep human gates at commitment boundaries
Autonomy can prepare evidence, rankings, drafts, and recommendations. Publishing, sending, trading, or other reputational/financial commitments should remain behind explicit approval unless the operator has deliberately authorised them.
Our initiative drafts land at an Initiative status; a separate approval-aware publisher remains between drafting and live publication.
Step 6 — Use an LLM only for the irreducibly fuzzy part
Good uses:
summarising a changed long-form source;
classifying nuanced intent;
drafting language from a bounded evidence packet;
resolving cases where rules conflict.
Bad uses:
checking the date;
testing whether a list is empty;
sorting scores;
comparing IDs;
enforcing banned words;
deciding whether an artifact already exists.
If the loop does need an LLM, send the ranked candidate and evidence, not the full raw universe.
Step 7 — Add cadence control and hard budgets
For session loops:
prefer self-paced backoff when the work itself determines cadence;
use fixed intervals only when an external clock does;
provide
--times N,--until,LOOP_COMPLETE, orloops.max_ticks.
For unattended initiative:
use cron;
gate weekends, empty queues, and unchanged sources before inference;
set per-run output limits;
stop on no eligible work;
alert on repeated errors rather than retrying forever.
7. What changed in our jobs
Engagement polling
Before: a full agent repeatedly loaded context and tools to discover there were no new replies. The 30-day audit found 760 runs and 115.8 million tokens, with all retained outputs silent.
After: a no-agent gate fetches lightweight engagement state, stores a watermark, exits silently when there are no new events, and invokes the agent only when new engagement exists.
Pattern: high-frequency polling should be cheap; event handling may be intelligent.
Scheduled publisher
Before: each slot woke an agent to check whether an approved item existed.
After: deterministic no-agent scripts query the calendar, enforce status/date/slot rules, and publish only when the preconditions are already satisfied. Empty slots cost no model tokens.
Pattern: approval state and time-slot matching are database predicates, not reasoning tasks.
Content pulse
Before: the full content workflow could wake even when a preflight condition made creation impossible.
After: a pulse_gate.py script runs deterministic preflight checks, returns silent on blocked/no-op states, and invokes an isolated agent session only when content work is warranted.
Pattern: move eligibility checks before expensive creative work.
Initiative loop
Before: a broad agent loop repeatedly fetched data, selected campaigns, drafted, and wrote outputs.
After: the process is a deterministic daily pipeline: fetch current truth, rank by measured conversion and friction, reject invalid mechanics, generate bounded drafts, check idempotency, and write to an approval-gated status.
Pattern: “initiative” does not require unconstrained reasoning. It requires a clear objective, fresh signals, encoded policy, bounded outputs, and a feedback loop.
8. Common anti-patterns
“Make the prompt shorter” — Useful, but second-order. First eliminate unnecessary model invocations.
“Return SILENT if nothing changed” — Too late. The model was already loaded and billed before it returned SILENT.
Polling with volatile monitor output — A timestamp, random order, rotating token, or request ID changes the hash every run and defeats suppression.
Loading every skill and tool — More tool schemas and instructions enlarge every model call and make tool choice harder. Scope the job.
One giant agent job — It recollects, reinterprets, and reformats the same state. Split collection from reasoning and action.
LLM-owned idempotency — “Remember not to duplicate this” is not a guarantee. Use stable keys, uniqueness checks, cursors, and read-back verification.
Unlimited loops — Every recurring agent turn is spend. Use stop conditions, run caps, backoff, and a terminal no-op state.
Optimising token count while losing correctness — A cheaper automation that misses replies or publishes duplicates is not efficient. Measure false negatives, false positives, and outcome quality alongside tokens.
9. Production checklist
Before enabling a job:
Is the objective and output contract explicit?
Did we measure runs, tokens, and no-op rate?
Can a script decide whether work exists?
Is output stable and canonical for hashing?
Did we choose
no_agent, monitor mode, or normal agent deliberately?Are skills and
enabled_toolsetsminimal?Are upstream results reused rather than recollected?
Are side effects idempotent?
Are irreversible actions approval-gated?
Do no-change, change, retry, and failure tests pass?
Is the model/provider pinned for unattended runs?
Are loop stop conditions and budgets configured?
Are useful outcomes and tokens measured after launch?
10. The principle to keep
Do not ask, “How do we make the agent cheaper each time it wakes?”
Ask:
What is the cheapest mechanism that can prove the agent needs to wake at all?
Use schedules to create opportunities to check. Use deterministic code to establish whether work exists. Use LLMs where their comparative advantage begins: ambiguity, synthesis, judgement, and language.
That is token efficiency: not a smaller expensive loop, but an architecture in which expensive reasoning happens only when it changes the outcome.