An autonomous billing agent you deploy on a Debian VM in one command. It runs a reliable deterministic core out of the box, and gets smart when you connect your existing coding-agent subscription - Claude Code, Kimi Code, or Codex - with no API key.
Architecture
-----------------------------------------------------------------------------
| AGENT BILLING v1.0 |
|----------------------------------------------------------------------------|
| +-------------+ +-------------+ +-------------+ +----------+ |
| | Producer |-->| Queue |-->| Dispatcher |-->| Executor | |
| | (cron/CLI) | | (SQLite) | | (OODA loop) | | (LLM/.) | |
| +-------------+ +------+------+ +-------------+ +-----+----+ |
| | | |
| +------+------+ +------+-----+ |
| | Dead Letter |<-------------------| Retry | |
| | Queue | (max 3 attempts) | Policy | |
| +------+------+ +----------+ |
| ^ |
| | |
| +---------------------------------------------------------------------+ |
| | Monitor | |
| | (queue depth / dead-letter / overdue invoices / backpressure) | |
| +---------------------------------------------------------------------+ |
-----------------------------------------------------------------------------
- Producer : cron, CLI (
agent.py enqueue), ou API externe - Queue : SQLite locale par defaut, zero-config, zero-deps
- Dispatcher : boucle OODA - observe, oriente, decide, agit
- Executor : mode deterministe (.) par defaut, mode LLM si CLI connectee
- Retry Policy : backoff exponentiel 10s -> 60s -> 600s
- Dead Letter : taches en echec conservees, replayables
- Monitor : sondes integrees, alertes configurables
One-shot install (Debian/Ubuntu)
unzip agent-billing-v1.zip && cd agent-billing-v1
sudo bash install.sh # system deps + venv + systemd service (enabled)
That's it. The agent starts as a systemd service (agent-billing-v1), survives
reboots, and restarts on failure. Logs: journalctl -u agent-billing-v1 -f.
No root / no systemd?
bash install.sh --no-servicesets up the venv, then runvenv/bin/python agent.py run.
Connect your LLM (optional, no API key)
install.sh auto-detects the first CLI it finds. Install & log in to one:
| CLI | Install | Connect |
|---|---|---|
| Claude Code | npm i -g @anthropic-ai/claude-code |
run claude, /login |
| Kimi Code | see platform.moonshot.ai | kimi-code |
| Codex | npm i -g @openai/codex |
codex login |
Force a specific one with PACK_LLM=claude|kimi|codex. If none is connected,
the agent still runs - see the honesty table below.
What's LLM vs deterministic (honest by design)
| Capability | Without an LLM CLI | With an LLM CLI connected |
|---|---|---|
| Queue, priorities, scheduling | deterministic | deterministic |
| Retry + exponential backoff | deterministic | deterministic |
| Dead-letter + replay | deterministic | deterministic |
| Dependencies (block on failed dep) | deterministic | deterministic |
| Idempotency (at-most-once key) | deterministic | deterministic |
| Task execution / reasoning | built-in handlers (generate_invoice, send_reminder, record_payment, reconcile_billing, cleanup) |
the LLM runs the Executor prompt (PROMPTS.md) on each task |
| Business-state integrity | deterministic (ids never invented) | deterministic guard validates every LLM output |
If a CLI is installed but not logged in, the agent logs a warning and falls back to the deterministic handler for that task - it never gets stuck.
Business-state integrity (no hallucinated invoices)
The LLM reasons, but business ids come from the system, never from the
model. A real invoice_id may only come from (a) your input data, (b) a
deterministic generator, or (c) the billing system's response after a real
creation. The agent enforces this on every LLM output before a task can
complete (validate_no_fabricated_invoice_ids in agent.py):
- An invoice you plan to create is emitted with
invoice_id: null("to_be_generated") — never an inventedINV-2026-0004. - A payment without a real invoice_id is never
invoice_marked_paid; it is parked asawaiting_invoice_creation/candidate_match_pending_creation/manual_review/ignored_duplicate. - Reconciling a payment to an invoice is a separate step that runs only after the invoice has really been created and its id returned.
- Any output that invents an id, or marks paid a non-existing invoice, is rejected: the task fails and goes to the dead-letter / human-review channel. Nothing fabricated is ever silently accepted.
Correct cycle: plan invoice → create it via the deterministic system/API →
get the real invoice_id back → reconcile the payment → log the result.
The reconcile_billing task does this deterministically (no LLM needed):
python agent.py enqueue --type reconcile_billing --payload '{
"existing_invoices":[{"invoice_id":"INV-2026-0003","customer":"Acme","amount":1200}],
"invoices_to_create":[{"customer":"Globex","amount":900}],
"payments":[{"customer":"Globex","amount":900,"status":"settled"}]
}'
Quick commands
python agent.py status
python agent.py enqueue --type generate_invoice --payload '{"customer":"Acme","amount":1200,"due_date":"2026-06-30"}'
python agent.py enqueue --type send_reminder --payload '{"customer":"Acme","invoice_id":"INV-001"}'
python agent.py enqueue --type record_payment --payload '{"customer":"Acme","invoice_id":"INV-001","amount_paid":1200}'
python agent.py enqueue --type cleanup --idempotency-key nightly-2026-06-07
python agent.py run --once # one OODA cycle
python agent.py run --deterministic # force the no-LLM core
python agent.py replay --task t-ab12cd34 # requeue a dead/blocked task
bash smoke_test.sh # offline test suite (no keys)
python EXAMPLE.py # runnable end-to-end demo
Contents
| File | Purpose |
|---|---|
agent.py |
Runnable billing agent - SQLite queue, retry, cron, dead-letter, OODA, BYO-LLM wiring |
llm_adapter.py |
BYO-LLM CLI adapter (claude/kimi/codex), no API key |
install.sh |
One-shot Debian installer (deps + venv + systemd) |
agent-billing-v1.service |
Reference systemd unit (install.sh generates the real one) |
smoke_test.sh / test_agent.py |
Offline test suite (deterministic) |
EXAMPLE.py |
End-to-end runnable demo of the shipped pipeline |
PROMPTS.md |
The Dispatcher / Executor / Monitor prompts the agent actually loads |
SOUL.md |
Agent identity, values, OODA loop |
SPEC.md |
Technical spec: task format, retry, scheduling, interfaces |
CHECKLIST.md |
Deployment checklist |
SUCCESS_METRICS.md |
KPI targets + failure definition |
OPERATING_COST_ESTIMATE.md |
LLM cost estimate (only relevant in LLM mode) |
requirements.txt |
Python deps (stdlib only) |
deploy.sh |
Thin wrapper -> install.sh |