Concepts.
The decision before the tool. What to weigh before you pick a technology: the construct, its trade-offs, and when the answer changes with scale.
Choosing a technology is rarely the hardest call. Choosing the construct is: a queue or a log, a rule or a model, paying for the work or paying to be ready. Get that right and the tool follows; get it wrong and no tool saves you.
Each page here teaches one of those decisions. It starts with the problem in plain words, compares the options on a concrete scenario, gives the rule of thumb and how the answer changes with scale, and ends with the technology I'd use for each answer, from The Stack. Every page opens with what you'll be able to decide after reading it.
Moving data between services
Events, messages and records travelling from the code that knows to the code that acts.
- 01 Messaging or streaming? Should the pipe remember a message after it has been delivered? Messaging (SQS, SNS, EventBridge) delivers each message and forgets it, so your database is the memory. A stream (Kinesis, Kafka) is a log: it keeps every record in order, and each consumer reads at its own position, replay included. A topic with an S3 archive sits between them: a log without a stream. Start with messaging; move to a stream when ordering, replay and several readers are the job itself.
- 02 At least once, and idempotency Every pipe on AWS can deliver the same message twice. How does the consumer stay correct when it does? SQS, SNS, EventBridge, Kinesis and Lambda's retries all deliver at least once: a message can arrive twice. Exactly-once delivery isn't on offer, except as deduplication in an SQS FIFO queue for five minutes, or as transactions inside Kafka. The fix is in the consumer: give every message a key, and make the second write change nothing (a unique constraint, an upsert, a version check).
Putting AI into software
Which kind of intelligence each step of a feature needs, and what happens when it's unsure.
- 03 Ask an LLM, or call a decision API? When my app needs a yes, a no, a label or a score, should it prompt a general model or call a model built to decide? Most AI calls in business apps are decisions: urgent or not, which team, how severe. A decision model (Jev, Cloudflare's Clef, OpenAI's Decisions API) takes your data and typed questions and returns probabilities with a confidence, in milliseconds, for cents per million tokens, and never writes text. Your code acts above a threshold and sends the rest to a bigger model or a person. The category is weeks old, so I'm watching it, with an adapter in front.
- 04 System 1 or System 2? Which steps of an AI feature should be fast and cheap, which should think, and how does one hand over to the other? System 1 is fast and cheap: code, a decision model or a small model, one call, at volume. System 2 is slow and deliberate: a top model at high reasoning effort, or an agent that loops with tools. Route per step, not per app: start each step on a top model, move it to the fast path once a replay of real cases proves the fast path does as well, and from then on everything takes the fast path first, checks in code catch what it got wrong, and only those cases climb. A person keeps the last word where the stakes or the law require it.
- 05 How much freedom should an AI step get? Should each AI step act on its own, ask someone first, or not be AI at all, and what decides it? Models in late 2026 are neither untrustworthy nor made deterministic by a good harness: they're highly reliable, not perfect. Design for exactly that, one step at a time. Three questions set a step's freedom: can code verify the result (then let it loop until the checks pass, within a number of attempts); if not, who can judge it (ideally the user, consenting at each critical fork, with no support person in between); and is a wrong result critical and impossible to undo (then it isn't a job for AI yet). Whatever does the work shouldn't be what checks it: checks in code first, then other agents with a different job.
- 06 How should a model get your company's knowledge? Do you put your documents in the prompt, build retrieval, fine-tune a model, or let it find what it needs? Knowledge isn't a system prompt. The system prompt is always loaded, because it sets how the agent thinks; knowledge depends on the need, and no situation needs all of it. So understand the need first, then disclose progressively: an entry point (a README of at most 750 lines, or an llms.txt map) whose links each say what's behind them, followed only where the question leads. The same goes beyond documents: some specific emails, some rows, some passages found by meaning. Retrieval is one source the agent can query, not the strategy. Cache what's always read, check with real questions that it finds the right source, and leave fine-tuning for format.
Paying for it
Where the money goes before a single request arrives, and when that's worth it.
Security, access and residency
Where the data may go, who can reach it, and what runs where it can't do harm.
- 08 Where may the data go? Must the data, the prompts and the logs stay in Australia, and what does each service do with them by default? Residency is a property of every hop a request takes, not of the app: the database, the files, the email, the analytics, the logs and the model. Most global platforms send data wherever they like by default; some keep it in Australia if you choose a region or a profile, sometimes for a premium; some have only a best-effort hint, or nothing. List every hop, check each one, and the answer is the weakest hop. Where it must stay, keep it in the client's own AWS account in Sydney; where it needn't, the global tools are simpler.
- 09 Where should code nobody reviewed run? Where does code written by a model or a customer run, so it can't reach your credentials, your network or the next user's files? A sandbox is for code nobody on your team reviewed: code a model writes at runtime, or code a customer uploads. Reviewed code, even an agent's, runs in a normal Lambda, Worker or Fargate task. Unreviewed code must never run where your credentials live: a Lambda carries its role and environment variables, and its /tmp survives into the next invocation. Give each session its own walls (a container on Cloudflare Sandbox by default; a microVM on Lambda MicroVMs when the code must stay in Australia, reach a private VPC, use a bigger machine or keep its processes for hours) and put nothing secret inside: its traffic leaves through a proxy that adds the credentials, to the destinations it needs and no others.
- 10 One AWS account, or many? Should everything run in one AWS account with careful policies, or behind walls of accounts, one per environment and workload, with the backups in an account of their own? An account is the hardest wall AWS has: two accounts can't touch each other unless someone allows it. Inside one account, only IAM policies stand between a leaked key or a wrong command and production, and some limits are shared by everything in it: Lambda's concurrency pool, SES's sending reputation. So put a wall wherever one thing must not be able to hurt another: production apart from dev and staging, a workload that can damage a shared limit in its own account, a client's systems in the client's accounts, and the backups in an account production can't write over. Organizations costs nothing extra and Savings Plans still apply across the accounts, so the cost of the walls is setup, not the bill.
- 11 Who holds your keys, and for how long? Should people, pipelines and apps carry long-lived keys or borrow short-lived roles, where does each secret live, and which code you didn't write runs next to them? Every credential answers three questions, usually by accident: who holds it, how long it works, and what else runs next to it. A long-lived key works from anywhere until someone revokes it, and outlives the person who made it. A borrowed role works for one session: a person through SSO, a pipeline through OIDC, a function through its own role, so there's nothing stored to leak. The secrets that can't be a role (a database password, a Stripe key, a model provider's key) go in the secret store, one job per key, read at runtime by reference. And the code you pull runs with all of them: a tag can be moved, so pin it to a SHA, a digest or a hash.
- 12 Coming in, or going out? Should your people come into the private network, or should one service go out to the public, and is anything still listening on a public address? Private access is a question of direction. What the public must reach gets a public endpoint, on purpose, and only one per job. Your own machines (laptops, CI runners, agent boxes) come in over a mesh network that opens no port; a VPN or a bastion does the same job at more cost and with more to run. A service the public or a client's staff must see, on a box with no open port, goes out through a tunnel: the box calls out, nobody calls in. Decide the direction per connection, then list what still answers on a public address. Most boxes need a way in and a way out, and the two don't compete.
Want this stack in your AWS account?
Cloudless Labs is a Sydney consultancy. We migrate on-premises systems to AWS, build serverless apps on this stack, and coach teams to ship with Claude Code and Codex.
Talk to us