JJoeven

Curriculum/Production Agents

The Smallest Prod-Shaped Stack

Day one is not Kubernetes. Day one is a queue, a job table, a trace table, and a practiced way to stop the agent — even if those are a list and two dicts.

intermediate19 min5 / 24

You do not need Kubernetes on day one. You do need boundaries you can name and a stop button someone has actually pressed. Even on a laptop you can fake the boxes: a dict as the job store, a list as the queue, functions as tool services. The point is not the brand of orchestrator. The point is that a god function with the union of all keys is not a stack, and a demo with a domain name is not production-shaped.

Staging should share those boundaries: real (scoped) keys, a second tenant, the same kill switches. If staging is “run the loop in the request with the prod prompt,” you are rehearsing the wrong play.

When you add a second region, jobs must not assume in-memory state. If that sentence surprises you, you are not ready to multi-region. The smallest stack is the one that survives a process restart. Orchestrators come after the queue, not before the blog post.

How the box actually works

Four stores and one lever, as a minimum you can operate:

PieceLaptop stand-inWhat “done” means
QueueA list of job idsA second process can pop work
Job storeA dict of job rowsRestart does not lose status / checkpoint / versions
Trace storeA list of spansYou can answer why a job cost money
Flags / kill switchA dict of booleansYou can stop refunds or all agents without a deploy
Blobs (soon)Files keyed by job idScreenshots and PDFs not stuffed into traces
Smallest stack that survives restart
QueueJob storeTraceKill switch

Four stores and a stop button. Kubernetes is not day one.

Smallest stack that survives restart

Owners can be one person at the start. Write the name anyway. “Stop the agent” needs a human who has flipped the flag in staging this month.

Contrast a god worker: one process imports the database, mail, Stripe, and the model SDK. It works in a demo. It has the union of privileges. A production-shaped split calls search_kb as a tool and never sees Stripe. You already saw confused deputy. This lesson is the inventory: if you cannot list the four tables, you will rebuild them during an incident.

You may run all four on one VM. Colocation is allowed. Mixing keys and skipping the queue is not.

Day-one operator loop, even on a laptop:

  1. Enqueue a job (dict + list).
  2. Kill the process.
  3. Start a new process, load the dict from disk (JSON file is enough).
  4. Pop the queue, run one slice, write a trace row with a dollar field.
  5. Flip agents.disabled, prove the next slice does not call tools.

If step 3 is “uh, it was in RAM,” you do not have a job store. If step 5 is “restart the app with a different env,” you do not have a kill switch. Orchestrators, autoscalers, and service meshes do not replace those two sentences.

Name the four tables in the README of the agent repo. New hires should find jobs, traces, blobs, flags before they find a vector index.

A “we have Kubernetes” ticket

A team said they were in production because they had a cluster, a vector index, and a public URL. There was no job table — state lived in the pod. There was no trace table — logs went to stdout and rotated. There was no kill switch — the runbook said “scale to zero,” which killed in-flight refunds without checkpoints. A node drain on a Tuesday looked like a random outage to users.

The smallest-stack review took an afternoon: Redis list as queue, Postgres table as jobs, Postgres table as traces, a flag in the same database. Kubernetes stayed. It was no longer pretending to be the architecture. The stop button became UPDATE flags SET agents_disabled = true and a worker that checked it at the start of each slice. They practiced it on Thursday. Friday’s model-vendor 503 was a pause, not a hero night.

Live PythonOpen full playgroundpython
Output
Run to execute this in your browser. Nothing is sent to a server.

GOD prints privileges that include db, mail, stripe, and model — the union. SPLIT prints an answer from search only, privileges ["model"], and the tenant from the job. The split path did not hold Stripe. That is the smallest production-shaped lesson in one screen: search did not need the union. Add refund later as a service, not as another import in the god worker.

What goes wrong

Buying a platform before a job id. Using the vector database as the job store. Using chat history in the vendor’s cloud as the only checkpoint. Calling the stack “prod” because SSO is on, while flags are a Google Doc. Adding a second region by running two god workers with two memories and one Stripe key.

Another failure: kill switch that requires a full deploy. That is a stop button made of molasses. Flags must change faster than images.

How to test it

Write a ready(ops) checklist and fail CI if staging cannot tick the boxes (you will see this again at the end of the track). Minimum:

  • Enqueue, restart the process, job still listed.
  • Flip agents.disabled, next slice does not call tools.
  • Trace row exists for a fake job with a dollar field.
  • God-worker privilege set is not used by the default path.

Do not test “kubectl apply succeeds.” Test that a killed process does not kill the job.

How agents use this

Start with four tables you can name: jobs, traces, blobs, flags. Name an owner for “stop the agent.” Add Kubernetes when the queue depth, not the blog post, demands it. Add a vector index when retrieval needs it — it is a tool backend, not a substitute for jobs.

Joeven’s tryit boxes are this stack on purpose: dicts and lists. When you go to cloud, keep the same names. If the cloud diagram cannot map onto queue / job / trace / flag, you bought a maze.

Ship a narrow workflow on this stack (handbook question, one tenant, one write tool off by default). Practice the stop button. Then widen the allow-list. The other way around is a public URL with no brakes.

Resist the urge to add a second region, a second model vendor, and a second agent persona in the same quarter as the first job table. Each of those is a box. Each box needs an owner and a stop path. The smallest stack is a discipline: you may not add a write tool until refund (or whatever writes) has a key, a flag, and a trace field.

When a vendor sales deck offers “agent orchestration,” map their nouns onto queue, job, trace, flag. If they cannot, you would be buying a maze. Keep the laptop stand-ins in CI so the boundaries stay testable when the maze arrives anyway.

Watch out:A demo with a custom domain and a god worker is not a small prod stack. It is a large blast radius with DNS.

Check your understanding

What is the smallest production-shaped stack?