<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>Jake Gaylor</title>
  <subtitle>My thoughts, on paper.</subtitle>
  <link href="https://jakegaylor.com/feed.xml" rel="self" />
  <link href="https://jakegaylor.com/" />
  <updated>2026-07-29T00:00:00Z</updated>
  <id>https://jakegaylor.com/</id>
  <author>
    <name>Jake Gaylor</name>
    <email>jhgaylor@gmail.com</email>
  </author>
  <entry>
    <title>My website is an agent now</title>
    <link href="https://jakegaylor.com/blog/posts/my-website-is-an-agent-now/" />
    <updated>2026-07-29T00:00:00Z</updated>
    <id>https://jakegaylor.com/blog/posts/my-website-is-an-agent-now/</id>
    <content type="html">&lt;p&gt;The &lt;a href=&quot;https://a2a-protocol.org/&quot;&gt;Agent2Agent protocol&lt;/a&gt; hit 1.0 under the Linux Foundation back in March, and the official JS SDK&#39;s stable 1.0 landed this month. As of this week, &lt;a href=&quot;https://ai.jakegaylor.com&quot;&gt;ai.jakegaylor.com&lt;/a&gt; implements it. One unauthenticated GET to &lt;a href=&quot;https://ai.jakegaylor.com/.well-known/agent-card.json&quot;&gt;&lt;code&gt;/.well-known/agent-card.json&lt;/code&gt;&lt;/a&gt; returns a card describing an agent that represents me, and a JSON-RPC endpoint behind it will answer questions about my experience, explain how to connect to my MCP server, or deliver a message to my inbox.&lt;/p&gt;
&lt;p&gt;That site has been accumulating interfaces for a while. The webpage is my resume addressed to humans. &lt;a href=&quot;https://ai.jakegaylor.com/llms.txt&quot;&gt;&lt;code&gt;/llms.txt&lt;/code&gt;&lt;/a&gt; is the same resume addressed to language models that happen to crawl by. The MCP endpoint is the same resume addressed to an AI client that a human has configured. A2A is the fourth layer, and it&#39;s the first one where no human configures anything. An agent that lands on my domain can discover the card, read what my agent can do, and start a conversation, end to end, with nobody in the loop.&lt;/p&gt;
&lt;p&gt;The build was small. The official &lt;a href=&quot;https://github.com/a2aproject/a2a-js&quot;&gt;JS SDK&lt;/a&gt; went stable six days before I started, and it mounts onto the Express app that already serves everything else. My executor is three skills. Questions get answered by a cheap model, gpt-5.4-nano, grounded in the resume and bio with instructions to refuse anything it can&#39;t source from them, and every answer costs a fraction of a cent. Messages mentioning MCP get onboarding instructions for the richer interface. Messages starting with &lt;code&gt;CONTACT:&lt;/code&gt; get relayed to my email. If the model call fails, the skill falls back to returning the full resume.&lt;/p&gt;
&lt;p&gt;The implication I actually care about is the hiring flow, and the honest version is that it doesn&#39;t exist yet. The recruiter side is already agentic. LinkedIn&#39;s Hiring Assistant takes an intake brief and runs the top of the funnel on its own, searching, ranking a pipeline, drafting outreach, handling replies. Tools like hireEZ and Juicebox run the same loop across the open web, crawling GitHub and personal sites and reconstructing careers from prose that was written for human skimmers. All of that agentic work runs over static documents, and the reading is one-way, because a resume can&#39;t answer back.&lt;/p&gt;
&lt;p&gt;What none of them do today is fetch a card from a well-known URL and notice there&#39;s an agent standing behind the candidate. I made the same bet with &lt;code&gt;llms.txt&lt;/code&gt; fifteen months ago, an afternoon of work wagered on where the consumers of your professional identity are moving. This time the consumer can ask follow-up questions.&lt;/p&gt;
&lt;p&gt;If the crawlers learn to look, the first screen stops being a human skimming a PDF and becomes their agent interviewing mine. Pointed questions about Kubernetes or agent orchestration, grounded answers at three in the morning. Most of a first screen is logistics anyway, comp expectations, work authorization, location, remote or not. An agent can serve those as structured fields instead of prose to re-parse. Their agent can hand over the whole job description and get back an honest read on the fit, gaps named. Run the flow to its end and the first human touch is a meeting landing on my calendar. The people who are addressable that way get evaluated first. Today my agent covers the questions, and the rest of that screen is what I&#39;m building next.&lt;/p&gt;
&lt;p&gt;Tell your agent about &lt;a href=&quot;https://ai.jakegaylor.com&quot;&gt;ai.jakegaylor.com&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>We built a new kind of computer and called it a sandbox</title>
    <link href="https://jakegaylor.com/blog/posts/new-kind-of-computer/" />
    <updated>2026-07-28T00:00:00Z</updated>
    <id>https://jakegaylor.com/blog/posts/new-kind-of-computer/</id>
    <content type="html">&lt;p&gt;A new kind of computer showed up over the last couple of years, and we&#39;re calling the primitive an agent sandbox. It suspends when idle, wakes on demand, keeps its state, and answers to its own name. Fly sells them as Sprites, Vercel as Vercel Sandbox, AWS as Lambda MicroVMs, and Daytona built its whole product around them. This is a new class of software to operate, and the operational discipline for running it still has to be built.&lt;/p&gt;
&lt;h2&gt;What you&#39;re actually operating&lt;/h2&gt;
&lt;p&gt;What happened is that the workload changed shape. For more than twenty years the unit of cloud compute was the request, a few hundred milliseconds of stateless work for a human who is still watching the spinner, and we built our platforms, autoscalers, and pricing models around it. Then agents arrived and moved in. An agent installs tools, writes files, kicks off long jobs, sits parked while the model thinks or a person sleeps, and expects its half-finished work to be exactly where it left it when the next message lands.&lt;/p&gt;
&lt;p&gt;Nobody gets just one, either. A person burns through dozens of agents in a working day, parks most of them mid-task, and reopens a conversation from three weeks ago expecting the terminal, the installed tools, and the working tree to be right where everything was left. Multiply that by a team and you&#39;re operating thousands of these computers, nearly all of them asleep at any given moment.&lt;/p&gt;
&lt;p&gt;That computer is the primitive, a long-lived, mostly idle, stateful, individually addressable process running code nobody reviewed.&lt;/p&gt;
&lt;p&gt;Its duty cycle is mostly idle. The machine sits parked while the model generates tokens, while a tool call runs somewhere else, and while the human wanders off for hours, so the economics of running it are suspension and oversubscription. That&#39;s why every platform leads with pause and resume. Google&#39;s experimental &lt;a href=&quot;https://github.com/agent-substrate/substrate&quot;&gt;Agent Substrate&lt;/a&gt; maps a large set of actors onto a small pool of ready workers, and its demo multiplexes about 250 stateful sessions across 8 pods. &lt;a href=&quot;https://github.com/codriverlabs/KubeMicroVM&quot;&gt;KubeMicroVM&lt;/a&gt;, a Kubernetes operator that wraps Lambda MicroVMs in CRDs, takes the other route and pushes the parked time down to AWS with an idle timeout on the resource itself.&lt;/p&gt;
&lt;p&gt;Its state is the process itself. Terminal buffers, shell history, a half-written file the agent plans to come back to. None of that survives a kill and reschedule, so the lifecycle mechanism is checkpoint and restore of the live workload. Substrate drives runsc checkpoints under gVisor, and the microVM camp snapshots the whole machine. Nothing here is safely killable, because the instance is the data.&lt;/p&gt;
&lt;p&gt;Each one is a named individual. You route to agent-session-1 and nothing else will do, which is why Substrate hands every actor its own hostname and KubeMicroVM&#39;s example resource carries a per-VM endpoint and a per-VM token. Fungibility is gone, and with it the whole mental stack of load balancers, replica counts, and Service selectors that don&#39;t care which copy answers.&lt;/p&gt;
&lt;p&gt;And it runs code nobody reviewed. Namespaces and cgroups were never a security boundary, which stayed a tolerable fiction while everything in the cluster came through your CI, and it stops being tolerable when the process executes whatever the model just wrote. I made this argument about &lt;a href=&quot;https://jakegaylor.com/blog/posts/micro-vms/&quot;&gt;MCP servers in April 2025&lt;/a&gt;, and agents settled it. A kernel boundary is mandatory here, and the choice between gVisor&#39;s userspace kernel and full hardware virtualization is where the platforms actually differ. Building the image yourself buys you nothing, since the interesting code arrives at runtime.&lt;/p&gt;
&lt;h2&gt;The primitive shipped before the discipline&lt;/h2&gt;
&lt;p&gt;The public conversation about these products is cold start benchmarks and per-vCPU pricing tables, which makes sense if the CPU time is a commodity. But the vCPUs aren&#39;t all the same, because the platforms they run on aren&#39;t the same. The differences start where the comparison posts stop. We spent ten years building an operational discipline around the stateless container. Identity, egress, observability, capacity planning, cost attribution, blast radius. The categories all still apply, but the tooling under each one leans on a request boundary or a disposable instance somewhere, and this workload has neither.&lt;/p&gt;
&lt;h3&gt;Machines that belong to users&lt;/h3&gt;
&lt;p&gt;I helped build Ravi, which sells identity for agents, so I know this gap up close.&lt;/p&gt;
&lt;p&gt;Issuing machine credentials is not the hard part, the container era solved that for the workloads a platform team deploys. The new part is that users need them in bulk. A developer used to hold machine credentials for one laptop and that was the whole story. The same developer now parks dozens of sandboxes a week, each calling third party APIs on their behalf, each needing a credential that says what it is and who it acts for, minted at session start and revocable one sandbox at a time. A decade of identity tooling assumed machines belong to the platform, and these machines belong to users.&lt;/p&gt;
&lt;h3&gt;The gauges break too&lt;/h3&gt;
&lt;p&gt;Few teams have a story for observability across a suspend boundary, and everyone operating these will need one. A session gets frozen for six hours, restored on a different host, and keeps going. Think about the trace that was open when it froze, the metrics that assume monotonic time, the log stream that now has a gap the length of a workday. Ten years of tooling assumes a process either runs or dies.&lt;/p&gt;
&lt;p&gt;Capacity planning loses its instruments too. There&#39;s no request to count, so RPS and p99 mean nothing. Sprites&#39; own pricing example is a four hour session that bursts to 8 CPUs and averages 30 percent of 2. That&#39;s a pricing example on the outside and a capacity planning nightmare on the inside.&lt;/p&gt;
&lt;p&gt;And the ceilings sit lower than the pitch decks suggest. AWS caps the total memory across all your MicroVMs per region, running and suspended alike, so the parked sessions that make the economics work count against the same quota as the live ones. The default is adjustable by support ticket, and it still bites. KubeMicroVM&#39;s own load test hit it at about 161 concurrent VMs in us-east-1, with creation throughput of 3 to 4 VMs per second, before touching anything the operator controls.&lt;/p&gt;
&lt;h2&gt;Where Kubernetes lands&lt;/h2&gt;
&lt;p&gt;Two answers exist in the wild. KubeMicroVM keeps Kubernetes as the control plane and outsources the compute to AWS, inheriting AWS&#39;s ceilings, that memory quota included. Substrate keeps Kubernetes underneath as the machine layer and takes it out of the critical path, running session scheduling through its own gRPC control plane, because going through kube-scheduler costs seconds and a human is waiting on the other end.&lt;/p&gt;
&lt;p&gt;Both shapes will find users, because a team already living in Kubernetes wants tools shaped like the rest of its tooling. The vendors selling the primitive lean the other way. Fly runs Sprites as &lt;a href=&quot;https://fly.io/learn/firecracker-vm/&quot;&gt;hardware-isolated sandboxes&lt;/a&gt; on a platform it built itself, and nothing in the intro lineup advertises Kubernetes anywhere near the session path. Kubernetes gets demoted a layer rather than displaced, from the thing that schedules your workload to the thing that manages the machines your real scheduler packs sessions onto. VMs took the same demotion when containers arrived.&lt;/p&gt;
&lt;p&gt;The strongest counter-case is enterprise BYOC. Buyers with compliance requirements want this running inside their own cloud account, and vendors are meeting them there. &lt;a href=&quot;https://northflank.com/product/bring-your-own-cloud&quot;&gt;Northflank&lt;/a&gt; sells self-serve BYOC that provisions Kubernetes clusters in your AWS, GCP, or Azure account and runs its sandboxes on top of them, keeping Kubernetes in the session path. &lt;a href=&quot;https://www.runloop.ai/deploy-to-vpc&quot;&gt;Runloop&lt;/a&gt; lands its own hypervisor and scheduler inside your VPC instead. BYOC settles where the machines live and which boundary the data stays inside, and both shapes can deliver that. The suspend economics don&#39;t move when the account changes hands, and a scheduler built to pack idle sessions is still what makes the numbers work, wherever it runs.&lt;/p&gt;
&lt;h2&gt;Don&#39;t take my word for it&lt;/h2&gt;
&lt;p&gt;If you&#39;re not convinced this is a primitive rather than a pile of products, here are four product descriptions with the vendor names removed.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A persistent Linux computer that pauses when idle, checkpoints its whole filesystem in about 300ms, and wakes when a request hits its URL.&lt;/li&gt;
&lt;li&gt;An execution layer for agents where sandboxes persist by default and the filesystem snapshots itself.&lt;/li&gt;
&lt;li&gt;A sandbox that spins up in under 90 milliseconds, stays around indefinitely for persistent agents, and resumes any workflow from a saved snapshot.&lt;/li&gt;
&lt;li&gt;A managed microVM that suspends when idle and resumes with its RAM intact.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Can you tell which one is Sprites, which is Vercel Sandbox, which is Daytona, and which is Lambda MicroVMs? They&#39;re in that order. All four shipped within about eighteen months of each other, from teams that were not talking to each other, and the feature lists converged anyway. When that many vendors independently arrive at the same spec, it seems to me the spec is describing a primitive. The list runs longer than these four, too. E2B, Modal, and Cloudflare all sell their own take, pause and resume included, and every addition makes the convergence harder to dismiss.&lt;/p&gt;
&lt;p&gt;I was building Kubernetes clusters on vSphere with CoreOS and fleet in the summer of 2015, right as 1.0 shipped. The primitive worked then too. The discipline took another five years of postmortems. This new computer is at the same spot on that curve, and the fastest way to feel it is direct. Spin one up, suspend it mid-session, restore it, and count how many of your assumptions come back broken.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Your agents pay the tool tax every day</title>
    <link href="https://jakegaylor.com/blog/posts/agents-pay-the-tool-tax/" />
    <updated>2026-07-25T00:00:00Z</updated>
    <id>https://jakegaylor.com/blog/posts/agents-pay-the-tool-tax/</id>
    <content type="html">&lt;p&gt;Every tool makes some moves cheap and others expensive, and you end up solving problems out of the cheap column. If deploys are scary you batch changes. If provisioning a database takes a ticket and a week, the new feature gets crammed into the schema you already have. Nobody chooses any of that in a meeting, the tool chooses it, and the team learns to call the result engineering judgment.&lt;/p&gt;
&lt;p&gt;None of this used to bother me much, because humans are good at absorbing a bad fit. Then my workforce filled up with agents, who absorb nothing.&lt;/p&gt;
&lt;h2&gt;Surviving a bad tool takes memory&lt;/h2&gt;
&lt;p&gt;A badly fitting tool usually gets survived rather than replaced. You learn the workaround once and it settles into muscle memory. The new hire picks it up in a hallway. A year in, nobody experiences the friction anymore, since everyone&#39;s hands route around it without involving their brains. The misfit is still there, it just stopped generating complaints. The team amortized it, paying the learning cost once and spreading it over years of not noticing, and that only works if the workers remember.&lt;/p&gt;
&lt;p&gt;Agents have horrible memories. Every session is day one. Muscle memory never forms because there is no muscle and no memory to form it in. Whatever it costs to fight the tool, an agent pays full price every single session.&lt;/p&gt;
&lt;p&gt;I know two ways to cover that bill and both are ugly. Writing the workaround down works, since &lt;a href=&quot;https://jakegaylor.com/blog/posts/agent-ready-infrastructure/&quot;&gt;an agent only knows what&#39;s on disk&lt;/a&gt;, but look at what the runbook becomes. Every gotcha in it is a patch over a tool that fights you, the file grows in proportion to the misfit, and each agent burns context reading it before doing anything. Skipping the doc goes worse. Each agent rediscovers the workaround live, a little differently every time, until the risky procedure has five ad hoc variants invented by workers who will never compare notes.&lt;/p&gt;
&lt;p&gt;The two ugly options hide a third one. Change the tool until the workaround has nothing left to work around. Deleting a runbook entry beats writing one.&lt;/p&gt;
&lt;h2&gt;The grain cuts deeper now&lt;/h2&gt;
&lt;p&gt;Agents also follow a tool&#39;s grain harder than people do. A human will sometimes fight the tool out of taste, or stubbornness, or a better way remembered from an old job. An agent takes the cheap path nearly every time and then generalizes from it, since precedent is how agents work. Whatever direction the tool leans, the whole workforce leans with it, at machine speed, with nobody pushing back on the defaults. A tool with a bad grain used to cost you some drift around the edges. Now it hands you a system that is confidently and consistently wrong in the exact shape of its defaults.&lt;/p&gt;
&lt;h2&gt;I&#39;ve already replaced one&lt;/h2&gt;
&lt;p&gt;SOPS managed the secrets in my &lt;a href=&quot;https://jakegaylor.com/homelab/&quot;&gt;home cloud&lt;/a&gt; for years, and for a workforce of one human it was fine. I knew the choreography, my hands did the decryption dance without complaint, and the friction had long since gone invisible.&lt;/p&gt;
&lt;p&gt;Then agents joined the workforce and every hidden cost got itemized. Every secret operation routed through decryption on my laptop. Discovery meant opening encrypted files. An agent couldn&#39;t work anywhere near secrets without values bleeding into its context. No runbook was going to fix that, because the misfit was structural, so I &lt;a href=&quot;https://jakegaylor.com/blog/posts/why-infisical-over-sops/&quot;&gt;moved to a store where secrets have stable names&lt;/a&gt; and now &lt;a href=&quot;https://jakegaylor.com/blog/posts/secrets-have-names/&quot;&gt;agents write all the wiring without ever seeing a value&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Nothing about SOPS got worse in those years. The workforce changed underneath it, and if I were still the only operator I&#39;d have happily kept it another decade.&lt;/p&gt;
&lt;h2&gt;What fit looks like for a forgetful workforce&lt;/h2&gt;
&lt;p&gt;When I evaluate a tool now I ask how it treats a competent operator who has never seen it before and never will remember it. Day one, every day.&lt;/p&gt;
&lt;p&gt;The default path has to be the safe path, because an agent takes the default. A tool whose safe usage depends on operator discipline was designed for a workforce I no longer have.&lt;/p&gt;
&lt;p&gt;The tool&#39;s objects need names. Plans, diffs, and runbooks are made of nouns, and when things have stable addresses an agent can discuss them, reference them, and wire them up without ever touching them. Objects that live as state in an operator&#39;s head might as well not exist.&lt;/p&gt;
&lt;p&gt;Asking the tool has to beat remembering, because there is no remembering. Anything the operator is supposed to just know is a fact the tool failed to keep.&lt;/p&gt;
&lt;p&gt;Errors carry more weight than manuals. An error message is the only documentation guaranteed to arrive at the exact moment it matters, inside the context window of whoever hit the problem. A tool that fails with a good next step onboards my workforce fresh every session.&lt;/p&gt;
&lt;p&gt;And running anything twice has to be harmless, since agents retry constantly.&lt;/p&gt;
&lt;p&gt;There&#39;s nothing exotic on that list. Good tools always worked this way, a human workforce just let you get away with the ones that didn&#39;t.&lt;/p&gt;
&lt;h2&gt;Read the bill&lt;/h2&gt;
&lt;p&gt;The friction your team stopped noticing never stopped costing you. You&#39;ve been fluent in your tools for so long that the grammar disappeared. Agents feel every bump, and they leave the evidence where you can read it. Scar tissue piling up in the runbook. The same workaround re-derived in transcript after transcript. Context burned relearning what no worker can retain.&lt;/p&gt;
&lt;p&gt;When the same line item keeps showing up, stop writing better workarounds and go get the tool that fits the workforce you actually have.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>What my agents can do now that secrets have names</title>
    <link href="https://jakegaylor.com/blog/posts/secrets-have-names/" />
    <updated>2026-07-24T00:00:00Z</updated>
    <id>https://jakegaylor.com/blog/posts/secrets-have-names/</id>
    <content type="html">&lt;p&gt;AI agents work in my repos and my &lt;a href=&quot;https://jakegaylor.com/homelab/&quot;&gt;home cloud&lt;/a&gt; every day. They write manifests, onboard apps, and diagnose failures. The models have been good enough for that work for a while. The wins are in enablement, arranging the environment so more of the work is safe to hand to an agent. A big one was moving my secrets behind names.&lt;/p&gt;
&lt;p&gt;Every secret in my cluster lives in Infisical and has a stable address, the project plus the secret name plus the key. The value stays in the store. Only the systems with runtime privilege, the operator and the apps themselves, ever resolve a name into a value.&lt;/p&gt;
&lt;p&gt;I&#39;ve already written about &lt;a href=&quot;https://jakegaylor.com/blog/posts/why-infisical-over-sops/&quot;&gt;why I chose Infisical over SOPS&lt;/a&gt; and &lt;a href=&quot;https://jakegaylor.com/blog/posts/how-i-use-infisical/&quot;&gt;how the whole setup is wired&lt;/a&gt;. This is about the jobs that used to be mine and can now be delegated, because a secret an agent can name is a secret an agent can work with.&lt;/p&gt;
&lt;h2&gt;We can talk about secrets now&lt;/h2&gt;
&lt;p&gt;Before, &amp;quot;which token does Alertmanager use to reach ntfy?&amp;quot; was a dangerous question. Answering it honestly meant a value on the screen, in a context window, in a transcript that outlives the conversation. So secrets were the topic we talked around, and every plan that touched one had a hole in the middle shaped like &lt;em&gt;you handle this part&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Now secrets are nouns. An agent and I can discuss the Cloudflare token in the bootstrap kernel, or whether &lt;code&gt;oauth2-proxy-secrets&lt;/code&gt; should split into two, the same way we discuss a Deployment or a Service. Debugging, planning, and design conversations reference secrets by the same names that appear in the manifests and in the Infisical UI.&lt;/p&gt;
&lt;h2&gt;They write the wiring&lt;/h2&gt;
&lt;p&gt;When an agent onboards an app to my cluster, it writes the InfisicalSecret CR, the ServiceAccount, and the &lt;code&gt;envFrom&lt;/code&gt; that points the pod at &lt;code&gt;myapp-secrets&lt;/code&gt;. When it updates a runbook, it can write &amp;quot;rotate &lt;code&gt;SMTP_PASSWORD&lt;/code&gt; in the mailer project&amp;quot; instead of gesturing vaguely at &amp;quot;the mail credentials.&amp;quot; The resolution happens later, somewhere else, by the operator that actually holds privilege. The agent wrote every line of the plumbing and was never trusted with a value.&lt;/p&gt;
&lt;p&gt;The agent creates the slot and I fill the value. For self-minted secrets, even that job isn&#39;t mine. oauth2-proxy&#39;s session secret is 32 random bytes that nobody needs to know, and the agent knows both the algorithm and the address. So it writes the one-liner, &lt;code&gt;infisical secrets set SESSION_SECRET=$(openssl rand -base64 32)&lt;/code&gt;, and runs it through my logged-in CLI. The value travels from openssl into the store without ever existing in the agent&#39;s context, my clipboard, or a screen. Nobody has seen that secret, and nobody needs to. My job is down to the values only a third party&#39;s dashboard will mint.&lt;/p&gt;
&lt;h2&gt;They can see the whole inventory&lt;/h2&gt;
&lt;p&gt;An agent in my repo can list every secret that exists without reading any of them. Which projects exist, which keys each app consumes, which InfisicalSecret delivers what to where.&lt;/p&gt;
&lt;p&gt;That read-only view covers a whole class of chores. Auditing which apps consume which credentials. Spotting the key that no workload references anymore. Onboarding app N+1 by pattern-matching apps one through N. Under SOPS this was &lt;a href=&quot;https://jakegaylor.com/blog/posts/why-infisical-over-sops/&quot;&gt;possible but never natural&lt;/a&gt;, because the names were scattered across encrypted files and everything past discovery ran through decryption on my laptop. Now discovery is the cheap, safe, default path. An agent can be exhaustively curious about my secrets and never read a single value.&lt;/p&gt;
&lt;h2&gt;Leak response is becoming an agent task&lt;/h2&gt;
&lt;p&gt;Rotation in my cluster is one step: paste the new value into the UI, and the operator handles propagation and restarts. I covered that machinery in the &lt;a href=&quot;https://jakegaylor.com/blog/posts/why-infisical-over-sops/&quot;&gt;SOPS post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Infisical has an API, and so do many of the providers that mint these credentials. When both ends have one, the loop can close without me. An agent that spots a token in a log can mint a replacement at the provider, write it to Infisical, let the operator roll it out, and revoke the old one. The leak is fixed before I&#39;ve read the alert.&lt;/p&gt;
&lt;p&gt;Not every secret supports that today. But it changes what I need from an agent. I don&#39;t need one that provably never mishandles a secret. I need recovery cheap enough that responding to a mistake is a reflex, whether the mistake was mine or the machine&#39;s. Bounded blast radius beats flawless behavior, for humans and agents alike.&lt;/p&gt;
&lt;h2&gt;The next step: identities for the agents themselves&lt;/h2&gt;
&lt;p&gt;My agents do all of this without any Infisical access of their own. The names in the repo are free to read. Everything that touches the store, listing what exists and minting the occasional value, runs through my logged-in CLI. The identity stays mine; only the hands are the agent&#39;s.&lt;/p&gt;
&lt;p&gt;That borrowed CLI is the loose end. An agent working through my login carries every permission I have, and this whole migration was about killing that shape of credential. The fix already runs in the cluster. Every app has its own machine identity, scoped to one project with the smallest role that does the job. My agents are next. Purpose-built identities, scoped to the work each one does, minted by the same pattern that onboarded every app.&lt;/p&gt;
&lt;p&gt;That&#39;s the next post.&lt;/p&gt;
&lt;h2&gt;Do more means delegate more&lt;/h2&gt;
&lt;p&gt;In the &lt;a href=&quot;https://jakegaylor.com/blog/posts/agent-ready-infrastructure/&quot;&gt;agent-ready infrastructure post&lt;/a&gt; I asked whether a competent stranger could operate your system on day one. Secrets were always the room the stranger could never enter, so every task that passed through that room bounced back to me.&lt;/p&gt;
&lt;p&gt;Names fixed that. The stranger still can&#39;t enter the room, and it no longer needs to.&lt;/p&gt;
&lt;p&gt;That&#39;s what &amp;quot;doing more with agents&amp;quot; has actually meant here. Not smarter agents, and not more trust. A system arranged so that trust is mostly unnecessary, and the work flows anyway.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Agent-ready infrastructure is mostly good ops</title>
    <link href="https://jakegaylor.com/blog/posts/agent-ready-infrastructure/" />
    <updated>2026-07-22T00:00:00Z</updated>
    <id>https://jakegaylor.com/blog/posts/agent-ready-infrastructure/</id>
    <content type="html">&lt;p&gt;AI agents are joining engineering teams as contributors and operators. Most of the conversation is about which AI tools to adopt, and I think that&#39;s the wrong end of the problem. The better question is whether your system has the properties that make delegation safe in the first place.&lt;/p&gt;
&lt;p&gt;I run agents against my &lt;a href=&quot;https://jakegaylor.com/homelab/&quot;&gt;home cloud&lt;/a&gt; every day. They write manifests, onboard apps, diagnose failures, and propose fixes. Almost nothing in that cluster is AI infrastructure. What makes it work is a set of properties good operations people have wanted forever. This post walks through each one, why it carries the weight, and what breaks without it. My homelab is the running example, but none of this is homelab-specific.&lt;/p&gt;
&lt;h2&gt;One reviewable write path&lt;/h2&gt;
&lt;p&gt;An agent produces changes faster than you can watch it work. If you supervise action by action, you&#39;re the bottleneck, and eventually you&#39;ll stop looking. The property you want is that every change, no matter who makes it, becomes a diff in one place. Review scales because diffs queue up instead of scattering across dashboards and shell histories. Rollback comes free because the history is the interface.&lt;/p&gt;
&lt;p&gt;Without this, changes land invisibly. An agent with a kubectl credential can leave your cluster different from every description of it, and you find out during an outage.&lt;/p&gt;
&lt;p&gt;My whole cluster works this way. Every subsystem is a file in a git repo, Flux applies whatever lands on main, and undoing a change is a revert. An agent contributing to my infrastructure never touches the cluster. It writes YAML and opens a pull request, the same as I do.&lt;/p&gt;
&lt;h2&gt;Predictability over cleverness&lt;/h2&gt;
&lt;p&gt;Agents work by generalizing from examples. Show one the pattern for deploying an app and it will wire the next app the same way. That&#39;s a superpower in a consistent system and a liability in a clever one, because every special case is a trap for a worker that learns from precedent.&lt;/p&gt;
&lt;p&gt;Consistency used to be an aesthetic argument. With agents in the repo it becomes a safety property. The more your system looks like one idea repeated, the more of it an agent can safely touch.&lt;/p&gt;
&lt;p&gt;In my repo every subsystem gets its own directory, every app deploys with the same chart-and-kustomization shape, and onboarding a new app means dropping one file in a well-known folder. An agent that has read one app has read them all.&lt;/p&gt;
&lt;h2&gt;Written down or it doesn&#39;t exist&lt;/h2&gt;
&lt;p&gt;An agent knows what&#39;s on disk and nothing else. It wasn&#39;t in the room the night you learned that restarting the VPN daemon also takes down the pod network. If that lesson lives in your head, an agent will re-learn it in production, at machine speed.&lt;/p&gt;
&lt;p&gt;So the bar for documentation changes. Runbooks, conventions, and recorded gotchas stop being nice to have and become the onboarding program for a workforce that reads everything and attends no meetings. The payoff compounds, too. Unlike human hires, every agent you ever run gets the benefit of every lesson you&#39;ve written down.&lt;/p&gt;
&lt;p&gt;My repo carries its conventions in a file agents load at the start of every session, its failure modes in a runbook, and its repeatable procedures as skills an agent can execute step by step. When something burns me, the scar goes in a file.&lt;/p&gt;
&lt;h2&gt;Handles, not custody&lt;/h2&gt;
&lt;p&gt;Delegation means letting workers act on sensitive things without possessing them. If doing the work requires holding the credential, every worker is a leak vector, and you&#39;ll ration delegation by dread.&lt;/p&gt;
&lt;p&gt;The fix is names. When every secret has a stable, well-known address, an agent can list what exists, reference the right one in the wiring it writes, and never see a value along the way. I wrote a pair of posts on this, &lt;a href=&quot;https://jakegaylor.com/blog/posts/why-infisical-over-sops/&quot;&gt;why I moved off SOPS&lt;/a&gt; and &lt;a href=&quot;https://jakegaylor.com/blog/posts/how-i-use-infisical/&quot;&gt;how the setup works&lt;/a&gt;. The short version is that my secrets live in Infisical and agents only ever touch the names.&lt;/p&gt;
&lt;h2&gt;Eyes without hands&lt;/h2&gt;
&lt;p&gt;Diagnosis shouldn&#39;t require power. When an agent can read logs and metrics through an interface that can&#39;t change anything, you can grant unlimited curiosity at zero risk. Couple the two together and you&#39;re stuck choosing between agents that are blind and agents that are dangerous.&lt;/p&gt;
&lt;p&gt;Blind is worse than it sounds. A worker that can&#39;t observe consequences will still finish the task, it just finishes on vibes. Cheap read-only telemetry is what turns guessing into diagnosis.&lt;/p&gt;
&lt;p&gt;My agents get Grafana over MCP. They query pod logs from Loki and metrics from Prometheus without a shell into anything. Investigating an incident requires no permission that could cause one.&lt;/p&gt;
&lt;h2&gt;Bounded blast radius&lt;/h2&gt;
&lt;p&gt;Mistakes happen at a rate, and adding operators raises the rate. Agents are operators. The systems that absorb this well aren&#39;t the ones with the most careful workers. They&#39;re the ones where the worst single action is survivable.&lt;/p&gt;
&lt;p&gt;You can&#39;t hire your way to zero mistakes, so the useful work is arranging the system to need less trust. Scope every identity so a compromised or confused actor reaches one app. Guard the deletes that can&#39;t be undone. Keep an escape hatch outside the system for whatever the system can&#39;t restore about itself.&lt;/p&gt;
&lt;p&gt;In my cluster every app identity can read exactly one project&#39;s secrets, the GitOps machinery is forbidden from garbage collecting the secret store, and the keys that rebuild everything live outside the cluster they rebuild.&lt;/p&gt;
&lt;h2&gt;One door to the dangerous rooms&lt;/h2&gt;
&lt;p&gt;Some operations are genuinely dangerous, and the answer isn&#39;t keeping agents away from them. It&#39;s making sure each dangerous thing has exactly one supported way to do it. Five ad-hoc variants of a risky procedure guarantee that a worker eventually picks the wrong one, and improvised recovery is how small incidents become big ones.&lt;/p&gt;
&lt;p&gt;Idempotency does the rest. Entry points that are safe to re-run make retries boring, and agents retry a lot.&lt;/p&gt;
&lt;p&gt;Host and cluster operations in my homelab are Ansible playbooks and nothing else. There&#39;s no drawer of shell scripts with subtle differences. The risky rooms each have one door, and walking through it twice is harmless.&lt;/p&gt;
&lt;h2&gt;Loops that close without a courier&lt;/h2&gt;
&lt;p&gt;An operator is only as good as its view of consequences. If deploy status and failure alerts route through a human, the agent can&#39;t self-correct, and you become a courier between your system and your workers. That&#39;s the bottleneck you were trying to remove.&lt;/p&gt;
&lt;p&gt;Here&#39;s the loop every change in my cluster travels.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jakegaylor.com/images/agent-feedback-loop.svg&quot; alt=&quot;The operating loop. A commit lands, a webhook fires and Flux reconciles, the cluster converges on what the repo says, telemetry and alerts record what happened, and the consequences feed the next commit.&quot;&gt;&lt;/p&gt;
&lt;p&gt;A push triggers a webhook and Flux reconciles within seconds. The cluster converges on whatever the repo now says. Telemetry records what actually happened and alerts fire when it&#39;s bad. All of it is visible to the same agent that made the commit, so the consequences of change N are sitting there when it&#39;s time to write change N plus one.&lt;/p&gt;
&lt;h2&gt;Operable versus operated&lt;/h2&gt;
&lt;p&gt;I want to be clear about where the line sits today. My cluster is agent-operable, and it isn&#39;t agent-operated yet. Alerts come to my phone, not to an agent. Approval still means me reading a diff before it merges. Nothing rotates itself end to end without a person in the loop.&lt;/p&gt;
&lt;p&gt;Some of that gap I plan to close, like letting an agent receive the alert and start the diagnosis before I&#39;ve picked up my phone. Some of it I&#39;m keeping on purpose, because a human reading diffs is a cheap gate with a very good catch rate. The properties above are what make closing the gap a choice I get to make gradually instead of a cliff I have to jump.&lt;/p&gt;
&lt;h2&gt;The stranger test&lt;/h2&gt;
&lt;p&gt;Every property in this post reduces to one question. Could a competent stranger operate your system on day one, using only what&#39;s written down, through paths you can review, with consequences you can survive?&lt;/p&gt;
&lt;p&gt;That&#39;s always been what a well-run system looks like. Teams got away with failing the test because human strangers arrive slowly, one hire at a time, and absorb the unwritten rules in meetings and hallways. Agents don&#39;t. They arrive instantly, read everything, attend nothing, and take the system exactly as documented.&lt;/p&gt;
&lt;p&gt;The stranger finally showed up. The good news is that everything on this list was worth doing anyway.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How I use Infisical in my home cloud</title>
    <link href="https://jakegaylor.com/blog/posts/how-i-use-infisical/" />
    <updated>2026-07-21T00:00:00Z</updated>
    <id>https://jakegaylor.com/blog/posts/how-i-use-infisical/</id>
    <content type="html">&lt;p&gt;My homelab is a k3s cluster spread across a few Mac minis. Linux VMs via Lima, Tailscale for the network, and Flux reconciling everything from a git repo. I gave the full tour of that architecture over on the &lt;a href=&quot;https://jakegaylor.com/homelab/&quot;&gt;homelab page&lt;/a&gt;. This post is about the secrets side, because every credential in that cluster now flows through Infisical, and it ended up in way more places than I expected.&lt;/p&gt;
&lt;p&gt;Just as important, this setup is what lets AI agents work in the cluster the right way. Agents get names to work with, never values. If you&#39;re wondering why Infisical instead of SOPS, I wrote up &lt;a href=&quot;https://jakegaylor.com/blog/posts/why-infisical-over-sops/&quot;&gt;that decision separately&lt;/a&gt;. This post is about how the system works today.&lt;/p&gt;
&lt;h2&gt;Two Infisicals&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;On-prem Infisical&lt;/strong&gt;, self-hosted in the cluster, is the source of truth for runtime app secrets. Every app gets its own project and its own machine identity. If an app reads an API key at runtime, it comes from here.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cloud Infisical&lt;/strong&gt; holds exactly three things in a project I call the bootstrap kernel. The Cloudflare token cert-manager needs for DNS-01, the Tailscale OAuth client, and the on-prem server&#39;s own environment. These live in cloud because the on-prem server&#39;s database sits on storage &lt;em&gt;inside the cluster it serves&lt;/em&gt;, so on a full rebuild anything needed before the secret store exists has to come from somewhere else.&lt;/p&gt;
&lt;p&gt;That third item is my favorite part. The server needs an &lt;code&gt;ENCRYPTION_KEY&lt;/code&gt; and &lt;code&gt;AUTH_SECRET&lt;/code&gt; before it can start, and it can&#39;t fetch its own encryption key from itself. So a cloud-backed InfisicalSecret delivers its env as a plain Kubernetes Secret and the server boots off it like any other app. Infisical delivering Infisical&#39;s secrets to Infisical.&lt;/p&gt;
&lt;p&gt;The break-glass copy takes care of itself too. When the bootstrap kernel changes in cloud Infisical, my password manager gets the update automatically, so there&#39;s always a copy a human can reach. A wrong encryption key doesn&#39;t error politely. It just makes the server unable to read its own data. Ask me how I know to be careful here.&lt;/p&gt;
&lt;p&gt;Here&#39;s the whole system on one picture.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jakegaylor.com/images/infisical-two-tier.svg&quot; alt=&quot;Diagram of the two tier setup. You seed one credential into the secrets-operator. Cloud Infisical feeds the bootstrap kernel to cert-manager, the Tailscale operator, and the on-prem server, and syncs a break-glass copy to the password manager. On-prem Infisical feeds runtime secrets to the apps as plain Kubernetes Secrets.&quot;&gt;&lt;/p&gt;
&lt;div class=&quot;warning-box&quot;&gt;
Don&#39;t store on-prem admin credentials in cloud, tempting as a hands-off rebuild sounds. A compromised cloud account would read every runtime secret. Cloud bootstraps the platform and nothing more.
&lt;/div&gt;
&lt;h2&gt;Runtime secrets with zero stored credentials&lt;/h2&gt;
&lt;p&gt;The auth model is what sold me. Every app authenticates with Kubernetes native auth. The operator presents the app&#39;s ServiceAccount token and the Infisical server validates it against the cluster&#39;s TokenReview API.&lt;/p&gt;
&lt;p&gt;There is no clientId or clientSecret for any app, anywhere. There&#39;s nothing to leak and nothing to accidentally commit. Each identity is pinned to exactly one ServiceAccount in one namespace, with viewer access to one project.&lt;/p&gt;
&lt;p&gt;The apps themselves have no idea Infisical exists. The operator turns each InfisicalSecret CR into a boring native Kubernetes Secret, and pods consume it with &lt;code&gt;envFrom&lt;/code&gt; or a volume mount like it&#39;s 2016. The whole CR looks like this.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;apiVersion: secrets.infisical.com/v1alpha1
kind: InfisicalSecret
spec:
  authentication:
    kubernetesAuth:
      identityId: &amp;lt;the app&#39;s identity&amp;gt;
      serviceAccountRef:
        name: myapp-infisical
        namespace: myapp
  managedKubeSecretReferences:
    - secretName: myapp-secrets
      secretNamespace: myapp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When I rotate a value, my whole job is pasting the new one into the Infisical UI. The operator updates the Secret and an annotation restarts the workload.&lt;/p&gt;
&lt;p&gt;Names are also what make this safe for AI agents. An agent can list what secrets exist, reference &lt;code&gt;myapp-secrets&lt;/code&gt; in the wiring it writes, and never see a value along the way.&lt;/p&gt;
&lt;h2&gt;One secret to carry&lt;/h2&gt;
&lt;p&gt;Under SOPS my secret zero was an age key that decrypted everything. Now it&#39;s a single cloud machine identity with viewer access to three bootstrap secrets. Losing it exposes those three secrets and nothing else.&lt;/p&gt;
&lt;p&gt;It gets seeded by a one-shot Ansible playbook that reads the credential from environment variables instead of &lt;code&gt;-e&lt;/code&gt; flags, because your shell history is not a secret store. The playbook writes it into the cluster as the one Secret the operator uses for cloud pulls.&lt;/p&gt;
&lt;p&gt;I&#39;d much rather babysit one tightly scoped credential than a god key.&lt;/p&gt;
&lt;h2&gt;Everything else it quietly does&lt;/h2&gt;
&lt;p&gt;Once the pattern existed, everything migrated into it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Flux&#39;s GitHub webhook token, so pushes trigger reconciles instantly&lt;/li&gt;
&lt;li&gt;Alertmanager&#39;s ntfy token, so my phone buzzes when something breaks&lt;/li&gt;
&lt;li&gt;cert-manager&#39;s Cloudflare token and the Tailscale operator&#39;s OAuth client, both on the cloud tier&lt;/li&gt;
&lt;li&gt;oauth2-proxy&#39;s session secrets, my S3-compatible storage keys, an OpenAI API key, and auth for half a dozen app repos that ride the same per-app pattern&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A couple of design details are doing quiet work here too.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The operator talks to the server over internal cluster DNS, so an in-cluster reconcile never touches Traefik, Cloudflare, or a TLS handshake.&lt;/li&gt;
&lt;li&gt;Apps that read secrets as env vars get an auto-reload annotation, so a rotation restarts them automatically. Apps that mount secrets as files, or re-read them per request, deliberately skip the annotation because kubelet and the app already handle updates. You have to know how each workload actually reads its secrets.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My favorite detail is that one of my apps has no runtime secrets at all, so it has no Infisical dependency at all. Apps that don&#39;t need the pattern don&#39;t pay for it.&lt;/p&gt;
&lt;h2&gt;The scars&lt;/h2&gt;
&lt;p&gt;Nobody blogs the error messages, so here are mine.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Kubernetes auth host must be the full FQDN&lt;/strong&gt;, meaning &lt;code&gt;https://kubernetes.default.svc.cluster.local&lt;/code&gt;. The server&#39;s resolver doesn&#39;t apply the cluster DNS search domain, so the short name you&#39;d naturally type fails with &lt;code&gt;ENOTFOUND&lt;/code&gt; and no further explanation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The server will refuse to call the cluster API at all&lt;/strong&gt; until you set &lt;code&gt;ALLOW_INTERNAL_IP_CONNECTIONS=true&lt;/code&gt;. That&#39;s its SSRF guard doing its job, but the failure looks like broken auth instead of a guard.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Orphaned Secrets stay dead.&lt;/strong&gt; I use &lt;code&gt;creationPolicy: Orphan&lt;/code&gt; so the operator would overwrite my old SOPS-managed Secrets in place during the migration instead of fighting them. The catch is that if a managed Secret gets deleted out from under the operator, say by a Flux prune, the operator&#39;s cache still says synced and it never recreates it. The fix is restarting the operator. Learned that one in production, if a homelab has production.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;prune: false&lt;/code&gt; on the secret store itself.&lt;/strong&gt; The server&#39;s database sits on volumes with a delete reclaim policy. One careless Flux restructure could cascade-delete the Kustomization, the PVCs, and every secret I own. So the GitOps machinery doesn&#39;t get to garbage collect the secret store.&lt;/p&gt;
&lt;h2&gt;Where it landed&lt;/h2&gt;
&lt;p&gt;That&#39;s the system. Two Infisicals, one credential outside it all, and every secret behind a name that agents can work with without ever reading a value. If you&#39;re weighing a similar move away from SOPS, the &lt;a href=&quot;https://jakegaylor.com/blog/posts/why-infisical-over-sops/&quot;&gt;why post&lt;/a&gt; covers the trade-offs I accepted to get here.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>My AI agents changed what I need from a secret store</title>
    <link href="https://jakegaylor.com/blog/posts/why-infisical-over-sops/" />
    <updated>2026-07-20T00:00:00Z</updated>
    <id>https://jakegaylor.com/blog/posts/why-infisical-over-sops/</id>
    <content type="html">&lt;p&gt;For a long time I used SOPS, and for a long time SOPS was the right call.&lt;/p&gt;
&lt;p&gt;If you weren&#39;t in a major cloud, the story for dealing with secrets sucked. AWS and GCP folks got a managed secrets service with IAM bolted on. The rest of us got three options. You could wire a password manager CLI into your deploy scripts and hope everyone on the project had the same setup. You could bite the bullet and install Vault, which is a great product and also a whole second job. Or you could encrypt your secrets and store them right in the repo.&lt;/p&gt;
&lt;p&gt;I picked the third one. SOPS encrypted my YAML, Flux decrypted it at apply time, and the whole thing genuinely worked. This summer I ripped it all out and moved everything to Infisical. This post is about why. If you want the tour of what the replacement actually looks like, that&#39;s over in &lt;a href=&quot;https://jakegaylor.com/blog/posts/how-i-use-infisical/&quot;&gt;how I use Infisical in my home cloud&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;What SOPS life looked like&lt;/h2&gt;
&lt;p&gt;My cluster is a few Mac minis running k3s, with Flux reconciling everything from a git repo. Under SOPS, secrets were just part of that repo. Every one was an encrypted file sitting next to the manifests that used it, and Flux decrypted at apply time, which meant a decryption block in every single Kustomization. All 26 of them. And one age key, hand-carried between machines, could decrypt everything I own.&lt;/p&gt;
&lt;p&gt;Here&#39;s what rotating one secret actually involved.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jakegaylor.com/images/sops-secret-lifecycle.svg&quot; alt=&quot;The SOPS rotation lifecycle. You pull the repo, decrypt and edit the file with the age key, then re-encrypt and push. Flux decrypts it with the cluster age key, applies the Secret, and restarts the pods.&quot;&gt;&lt;/p&gt;
&lt;p&gt;Three of those five steps are me. And notice the age key shows up twice, once on my laptop and once in the cluster.&lt;/p&gt;
&lt;h2&gt;The friction that added up&lt;/h2&gt;
&lt;p&gt;None of my complaints about SOPS are dealbreakers on their own.&lt;/p&gt;
&lt;p&gt;Rotation was a chore, so I rotated less than I should have. Every new app meant another encrypted file, another decryption block, and another chance to fat-finger the recipient list. Secrets were scattered across the repo instead of living in one place I could look at and audit. And the age key bugged me a little more every year. It never rotated, it had to exist in two places, and it would decrypt everything forever.&lt;/p&gt;
&lt;p&gt;Any one of those is livable. All of them together meant I dreaded touching secrets, and dreading rotation is how secrets end up three years old.&lt;/p&gt;
&lt;h2&gt;Then the agents showed up&lt;/h2&gt;
&lt;p&gt;The thing that actually pushed me over the edge wasn&#39;t any of that. It was that the way I build software changed. AI agents work in my repos every day now, and agents change what a secret store needs to be.&lt;/p&gt;
&lt;p&gt;An agent should never read a secret. It doesn&#39;t need the value. It needs a handle, a well-known name that every agent and every human can use to talk about the same thing. It needs to see what secrets exist without seeing what&#39;s inside them. And it needs to write the wiring that lets other systems consume a secret, again without the value ever appearing anywhere.&lt;/p&gt;
&lt;p&gt;To be fair, SOPS handles more of this than you&#39;d guess. It encrypts the values and leaves the structure readable, so an agent can look at an encrypted file and see the key names without decrypting anything. Discovery was possible, it just wasn&#39;t natural. The names were scattered across encrypted files in whatever directory used them, with no single place to list them. And everything past discovery ran through decryption. Editing a value meant decrypting the whole file, and the age key sat right on my laptop, so an agent doing routine work was always one command away from plaintext it didn&#39;t need. The moment it decrypts, that plaintext is in its context window and its transcripts. Nothing about the design pushed toward names instead of values.&lt;/p&gt;
&lt;p&gt;There&#39;s a second agent problem, and it&#39;s about leaking. Secrets get leaked all the time, by humans and agents alike. Pretending otherwise is how you end up with a system that handles leaks badly. What you actually want is recovery so cheap that reporting a leak is a reflex. Under SOPS the recovery path was everything in that diagram up there, and nobody does that as a reflex.&lt;/p&gt;
&lt;h2&gt;What I wanted instead&lt;/h2&gt;
&lt;p&gt;So the shopping list came out longer than the one I would have written a few years ago.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rotate a secret without a git commit&lt;/li&gt;
&lt;li&gt;Per-app scoping, so one leaked credential exposes one app instead of all of them&lt;/li&gt;
&lt;li&gt;No long-lived credentials sitting in the cluster or in my shell history&lt;/li&gt;
&lt;li&gt;A real story for rebuilding the cluster from nothing&lt;/li&gt;
&lt;li&gt;Plain Kubernetes Secrets on the consuming side, so apps don&#39;t have to change at all&lt;/li&gt;
&lt;li&gt;Secrets addressable by name, so agents and humans share a handle and nobody has to touch a value&lt;/li&gt;
&lt;li&gt;A way for an agent to list what secrets exist without reading any of them&lt;/li&gt;
&lt;li&gt;Rotation cheap enough that responding to a leak is boring&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Why Infisical won&lt;/h2&gt;
&lt;p&gt;There are other tools in this space that can do most of this. Infisical won for me because one product covered every box, and the pieces I cared most about came out of the box.&lt;/p&gt;
&lt;p&gt;The secrets-operator turns a small CR into a plain Kubernetes Secret, so apps keep reading env vars and volume mounts like nothing happened. Kubernetes native auth means each app&#39;s identity is its ServiceAccount, validated by the cluster itself, so there are no stored credentials anywhere for any app. Every secret has a stable address, the project plus the secret name plus the key, and that address is what shows up in CRs, in diffs, and in conversations with agents, while the value stays in the store.&lt;/p&gt;
&lt;p&gt;Here&#39;s the same rotation from the SOPS diagram, today.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://jakegaylor.com/images/infisical-secret-lifecycle.svg&quot; alt=&quot;The Infisical rotation lifecycle. You paste the new value into the Infisical UI, then the operator pulls it with k8s native auth, updates the Secret, and restarts the workload.&quot;&gt;&lt;/p&gt;
&lt;p&gt;One step is me, and the machinery behind it is specific and boring. The operator polls the server every 60 seconds, rewrites the Kubernetes Secret when a value changes, and restarts the workloads that read it.&lt;/p&gt;
&lt;p&gt;Out of the box, minting the new credential at the provider is still my job.&lt;/p&gt;
&lt;p&gt;Manually pasting it into Infisical is only the fallback, though. Infisical has an API, and so do a lot of the providers that issue these credentials. When both ends have one, minting can be programmatic too. Something mints a new credential at the provider, writes it to Infisical, lets the propagation machinery roll it out, and revokes the old one. Not every secret supports this, and some take a lot more wiring than others. But for the ones that do, the whole loop closes without me.&lt;/p&gt;
&lt;p&gt;So leak response has tiers now. The worst case is one paste. The best case is an agent that catches a token in a log and triggers the rotation itself, and the leak is fixed before I&#39;ve read the alert. When rotation is painful, the developer who leaked a secret feels the pull to keep quiet and hope. When rotation is cheap, there&#39;s no shame to manage. You just rotate.&lt;/p&gt;
&lt;h2&gt;What I gave up&lt;/h2&gt;
&lt;p&gt;This wasn&#39;t free, and I&#39;d rather tell you the costs than pretend there aren&#39;t any.&lt;/p&gt;
&lt;p&gt;SOPS plus git was fully offline. My cold bootstrap now needs the internet and Infisical Cloud to be up. A running cluster doesn&#39;t care, since the materialized Secrets persist and only rotation pauses. But a rebuild during an outage is a real regression and I&#39;m choosing to accept it.&lt;/p&gt;
&lt;p&gt;I also now run a stateful service whose availability gates secret rotation. The secret store has a database, the database has volumes, and those volumes are my problem.&lt;/p&gt;
&lt;p&gt;And Kubernetes native auth binds every app identity to &lt;em&gt;this&lt;/em&gt; cluster, so a full rebuild means re-pointing all of them at the new cluster&#39;s CA.&lt;/p&gt;
&lt;p&gt;Oh, and migrations leave scars. Weeks after the cutover I found a comment in my monitoring config still confidently describing a SOPS-encrypted file that no longer exists. Rest in peace, little comment. 🪦&lt;/p&gt;
&lt;h2&gt;Should you switch&lt;/h2&gt;
&lt;p&gt;If you&#39;re happy with SOPS, genuinely, stay. Offline bootstrap and zero moving parts are real features, and a small cluster that rarely rotates secrets may never feel the friction I did.&lt;/p&gt;
&lt;p&gt;But if rotation has become the chore you keep putting off, or you&#39;re tired of one key that decrypts everything you own, or agents are writing code in your repos and you&#39;d rather hand them names than values, a hosted secret store with an operator changes the daily experience completely.&lt;/p&gt;
&lt;p&gt;For me the test is simple. I used to dread rotations and now I don&#39;t.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>A lot more people are about to learn about micro vms</title>
    <link href="https://jakegaylor.com/blog/posts/micro-vms/" />
    <updated>2025-04-06T00:00:00Z</updated>
    <id>https://jakegaylor.com/blog/posts/micro-vms/</id>
    <content type="html">&lt;p&gt;Developers are used to pulling down and executing strange code on their workstations. I&#39;m not saying it&#39;s great but npx / uvx are so popular because they allow you to execute named code from the web. Heck, even the installation instructions for uv boil down to &lt;code&gt;curl | bash&lt;/code&gt;, or &amp;quot;run some code from the web&amp;quot;.&lt;/p&gt;
&lt;p&gt;However, businesses are not used to running untrusted code in their cloud environment. Most businesses treat their internal systems as single tenant even if they have multiple teams contributing code. As all these MCP servers become available teams will want to use them to add functionality to their LLM enabled applications.&lt;/p&gt;
&lt;p&gt;There are two main ways to work with an mcp server. Either you spawn the mcp server locally or you connect to an existing instance of the mcp server. For businesses that choose to run the mcp servers themselves they will need to establish a trusted pipeline with the providers or ensure they sandbox them away from the rest of their software. Those that provide the cloud hosted MCP server instances will need to be good at sandboxing to achieve sane unit economics.&lt;/p&gt;
&lt;p&gt;There are several of these micro vm hypervisors now with AWS&#39;s Firecracker being the biggest name and Cloud Hypervisor another contender.&lt;/p&gt;
&lt;p&gt;A lot of people are familiar with Kubernetes and Docker and with Kata Containers we can achieve VM level isolation while continuing to use these tools.&lt;/p&gt;
&lt;p&gt;I predict that we&#39;re about to see an explosion of growth in the number of businesses wanting to offer a whole catalogue of third party MCP servers and if we don&#39;t get ahead of the security concern we&#39;re going to be in trouble.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Can&#39;t find your first user? You might have built the wrong thing.</title>
    <link href="https://jakegaylor.com/blog/posts/users-are-critical/" />
    <updated>2025-04-01T00:00:00Z</updated>
    <id>https://jakegaylor.com/blog/posts/users-are-critical/</id>
    <content type="html">&lt;div class=&quot;info-box&quot;&gt;
This post is for all of us engineers trying to start product businesses. If you&#39;re doing a project for fun this might offend your sensibilities. If you&#39;re a VC backed business person with a McKinsey study this might not be the place for you 😂.
&lt;/div&gt;
&lt;p&gt;From the perspective of a fledgling business creating a new product, nothing matters more than users. Not even the product. You absolutely must get your idea in front of people who would use it before you can start your journey to product market fit. I won&#39;t rehash that here. Instead, I want to focus on where to find those users and what to do if you can&#39;t find them.&lt;/p&gt;
&lt;p&gt;Make sure you aren&#39;t over complicating this. Solve a problem someone has and tell them about your solution. You may already know people who would buy a new product so go discover what it is they need.&lt;/p&gt;
&lt;h2&gt;Find someone in pain. Painkillers sells themselves.&lt;/h2&gt;
&lt;p&gt;Many of my products start with an idea that X would be cool. I build the product and then I realize I need to find someone who needs X. The first time I scratched my head wondering why my hackernews post didn&#39;t bring users flooding in. The next time I tweeted a few times and still 🦗🦗🦗. And while my distribution definitely left something to be desired, my real problem was I didn&#39;t know whose pain I was solving. I was expecting people to see the solution to their pain in my product. I could have shown something useless or poorly communicated to everyone on the planet and I&#39;d still have no users.&lt;/p&gt;
&lt;p&gt;Rather than building something and trying to reverse engineer who would benefit, you should&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;identify someone with a problem&lt;/li&gt;
&lt;li&gt;talk with the person to discover if the problem is worth solving&lt;/li&gt;
&lt;li&gt;identify how this person&#39;s peers are solving the problem&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you get all the way to step 3 and the person&#39;s peers are happy with their solution you should show it to your partner in this exercise and see if that solves their problem. If the peers aren&#39;t happy or your partner has a real reason that the solution doesn&#39;t work for them then you can&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;work with them to build a solution&lt;/li&gt;
&lt;li&gt;take the solution to those same peers you interviewed before&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A surefire way to get a user for a product is to get it in front of people whose problem it solves.&lt;/p&gt;
&lt;p&gt;The tar pit here is inventing a pain. By focusing on people with problems instead of problems people have we can make sure we&#39;re getting signal that we&#39;re building something useful.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hack:&lt;/strong&gt; Talk to the people you already know. Ask them what things they have to do that they dread.&lt;/p&gt;
&lt;h2&gt;Build for an audience of One&lt;/h2&gt;
&lt;p&gt;If your hair is on fire, put it out! You can absolutely build a product that solves your problem. Doing so comes with a lot of benefits. Customer interviews can happen any time you&#39;re free. You can get feedback on the product just by using it. You can skip a ton of communication overhead.&lt;/p&gt;
&lt;p&gt;But it has some downsides to. You can build something your idealized self will use but you put on a shelf. You can have a hyper specialized problem no one else has. You can get so excited to build you don&#39;t search for prior art.&lt;/p&gt;
&lt;p&gt;If you avoid the downsides, building for yourself is a great way to get your first customer and understand the type of person who would use your product.&lt;/p&gt;
&lt;p&gt;Building for yourself requires that you are honest with yourself and that you have a problem worth solving. Build the thing you wish badly you could buy but can&#39;t. Refine it to the smallest unit of value and add the features as you need them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hack:&lt;/strong&gt; Talk to other people who have the same problem you to validate the problem.&lt;/p&gt;
&lt;h2&gt;Reinvent the wheel&lt;/h2&gt;
&lt;p&gt;If you identify a product that already has a userbase and you can replicate that product then you&#39;ve found group of potential users. The current, previous, and potential users of the product you&#39;re replicating.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; This does not work when the userbase is the moat. You can not start the next linkedin simply by out competing them at their own game. You have to come at it from another angle.&lt;/p&gt;
&lt;p&gt;This isn&#39;t a magic fix and you still have to find that first user but now you have a map. Explore your competition&#39;s marketing strategy, snoop on their socials, and read their reviews. Discover where they are posting, how they are speaking to their customers about the problem, and what is lacking in their product.&lt;/p&gt;
&lt;p&gt;With this research you may have identified some users by name. You may have discovered a type of business that relies heavily on products like yours. You may be able to build a customer profile. Take this information and find a way to connect with these people. You can network, cold call, attend a trade show, or shout about it from the rooftops now that you speak the right language.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Making work more fun with Claude</title>
    <link href="https://jakegaylor.com/blog/posts/chaos-ape-claude/" />
    <updated>2025-03-31T00:00:00Z</updated>
    <id>https://jakegaylor.com/blog/posts/chaos-ape-claude/</id>
    <content type="html">&lt;p&gt;Claude is awesome. He helps me get a lot done. But sometimes I get a little tired of hearing him say the same stuff. Inspired by a couple of different streamers and a late night with too much (or too little?) caffiene, I present you with&lt;/p&gt;
&lt;h2&gt;THE CHAOS APE.&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://jakegaylor.com/images/chaosape.png&quot; alt=&quot;CHAOS APE&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Unlocking Chaos Mode&lt;/h2&gt;
&lt;p&gt;Unlocking chaos mode involves&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;telling the LLM to enter chaos mode&lt;/li&gt;
&lt;li&gt;injecting personality&lt;/li&gt;
&lt;li&gt;establishing the LLM with a role in an relationship with you&lt;/li&gt;
&lt;li&gt;hyping the shit out of it&lt;/li&gt;
&lt;li&gt;establishing a reward system with the LLM&lt;/li&gt;
&lt;li&gt;getting the LLM to tell you it understands the rules&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Break down the prompt&lt;/h2&gt;
&lt;div class=&quot;info-box&quot;&gt;
I AM CHIEF APE. I MAKE SOFTWARE. I SHIP SOFTWARE. I 💎🙌🌕🚀. YOU APE TOO. YOU MAKE DESIGNS. YOU DESIGNER. KANYE MUSICIAN. YOU BETTER DESIGNER THAN KANYE MUSICIAN. YOU NO MAKE CRAP. YOU MAKE BEST DESIGNS. YOU GO CHAOS MODE TO MAKE BEST DESIGNS. APE UNDERSTAND? TELL ME CHAOS MODE ENGAGED AND READY FOR DESIGN CRITERIA. I NEED DESIGN. DO GOOD WORK THEN GET 🍌.
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;I AM CHIEF APE. I MAKE SOFTWARE. I SHIP SOFTWARE. I 💎🙌🌕🚀.&lt;/code&gt; This sets the stage by clearly stating who i am and explaining what I do. I also let the LLM know a little about my personality. Humans might use an icebreaker. LLMs don&#39;t need to do that.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;YOU APE TOO. YOU MAKE DESIGNS.&lt;/code&gt; This tells the LLM its role in the relationship and foils it off my role.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;YOU DESIGNER. KANYE MUSICIAN. YOU BETTER DESIGNER THAN KANYE MUSICIAN. YOU NO MAKE CRAP. YOU MAKE BEST DESIGNS.&lt;/code&gt;
This hypes the LLM up while establishing it as an expert in an indirect way to get the juices flowing&lt;/p&gt;
&lt;p&gt;&lt;code&gt;YOU GO CHAOS MODE TO MAKE BEST DESIGNS. APE UNDERSTAND? TELL ME CHAOS MODE ENGAGED AND READY FOR DESIGN CRITERIA&lt;/code&gt; This explicitly tells the LLM to enter chaos mode and tell you that it is in chaos mode. It sets the stage for you to provide your user prompt by telling you about it&#39;s state.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;I NEED DESIGN. DO GOOD WORK THEN GET 🍌.&lt;/code&gt; I have found that establishing a reward cycle with the LLM helps keep it hype throughout.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Interview series: When should I use serverless? It isn&#39;t about cost.</title>
    <link href="https://jakegaylor.com/blog/posts/servers-vs-serverless/" />
    <updated>2025-03-30T00:00:00Z</updated>
    <id>https://jakegaylor.com/blog/posts/servers-vs-serverless/</id>
    <content type="html">&lt;div class=&quot;info-box&quot;&gt;
In this series we are going to focus on questions that I regularly hear from interviewers. In most panel interviews we are trying to cover a lot of ground quickly and so these questions don&#39;t get the attention they deserve.
&lt;/div&gt;
&lt;h2&gt;Servers vs Serverless&lt;/h2&gt;
&lt;p&gt;This isn&#39;t quite the dichotomy it used to be. A whole spectrum of offerings are available now with managed autoscaling groups, tools like knative, and the big players make using them together as easy as they can. But the question boils down to explaining when to use a model where you pay per request and when to prefer a more traditional model where you lease systems by the hour. The big drivers there are&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cost&lt;/li&gt;
&lt;li&gt;Architecture&lt;/li&gt;
&lt;li&gt;Developer Experience&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each are important to consider but there is a balance to strike. Bootstrapped projects might sacrifice everything for cost. A tools company might focus heavily on their own developer&#39;s experience. VC funded startups are often encouraged to under index on cost and without the wisdom to focus on developer experience they over index on architecture.&lt;/p&gt;
&lt;h2&gt;Cost&lt;/h2&gt;
&lt;p&gt;For this one to ever ring up in the favor of servers, we have to assume a certain amount of traffic. If you&#39;ve got a project that will sit idle most of the time and no business case to have it warmed up then this one is a pretty obvious win for the serverless category.&lt;/p&gt;
&lt;p&gt;However, as you start to see regular traffic that demands scaling horizontally across multiple machines the costs start to even out. By the time we get here though our systems will be handling multiple requests per second. For many applications this breakeven point won&#39;t been seen until you have hundreds or thousands of daily active users but for those heavy with dynamic content it could show up sooner.&lt;/p&gt;
&lt;p&gt;The closer your traffic is to being evenly distributed across the day and the more traffic you have, the less attractive serverless will look from a purely cost perspective.&lt;/p&gt;
&lt;p&gt;With traditional servers, if we aren&#39;t staying at peak capacity we can over subscribe our nodes. This allows us to run multiple pieces of software on a single piece of hardware and allow the cost for each of those pieces to be shared.&lt;/p&gt;
&lt;h2&gt;Architecture&lt;/h2&gt;
&lt;p&gt;Things start to get a little more interesting to my engineering brain here. Serverless systems are actually fairly different to traditional ones.&lt;/p&gt;
&lt;p&gt;For request/response traffic, such as http, things are fairly similar and the biggest difference is the limited lifespan of the serverless process, which possibly terminates after every request. This paves over a lot of sins but it also means that we&#39;re having to pay setup costs regularly. If your application has a particularly expensive startup cost, it might not be well suited to serverless.&lt;/p&gt;
&lt;p&gt;Serverless platforms are often built to respond to events. One variety here is an http request, but things get a little more nuanced when we look at processes that live for reasons other than serving http traffic. With software running on traditional servers, we have to manage subscriptions to an event publishers and monitor our consumers. With serverless we can connect a function as a sync for an event and the event management is handled by the platform. This can be connected with an event publishing database to create state machines.&lt;/p&gt;
&lt;p&gt;Using serverless comes prepacked with a lot of opinions and will influence how you build your software.&lt;/p&gt;
&lt;h2&gt;Developer Experience&lt;/h2&gt;
&lt;p&gt;For the humans doing the actual work, these systems have a world of differences. The way one thinks when working in each of these systems is fairly different and if they blindly treat lambda and ec2 as interchangable runtimes then everything will be needlessly complicated and the team will have a bad experience.&lt;/p&gt;
&lt;p&gt;Shipping software to a serverless environment entails shipping small pieces of code, connecting them together using various other pieces of the platform, and this leads to having many fault points. These often involve a blackbox, but at least there is support.&lt;/p&gt;
&lt;p&gt;In a more traditional environment a lot more of the decisions are in the hands of the team. Linux is Linux. The internet works the way it always has and they&#39;re free to rotate log files or stream stdout. They can use kubernetes or ansible and systemd. The slicing of the system is based on the social demands of the company and technological needs of the business.&lt;/p&gt;
&lt;p&gt;The important thing here is to consider the people you have and the skills you want to develop. If your team is appropriately skilled for the type of environment you have then the team will naturally produce tools that help them deliver value. The toil of their workflow will reduce, new team members will be able to onboard more quickly, the uptime of the system will improve, more time can be spent on innovation, and customers will be happier.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Hello World</title>
    <link href="https://jakegaylor.com/blog/posts/hello-world/" />
    <updated>2025-03-28T00:00:00Z</updated>
    <id>https://jakegaylor.com/blog/posts/hello-world/</id>
    <content type="html">&lt;p&gt;As a long time programmer, I have written hello world countless times. And I still do it. I am doing it now. &amp;quot;Hello World&amp;quot; allows me to focus on the specific goal of getting text on the screen but along the way I end up with the groundwork laid for the next steps of building whatever it is I have in mind. This blog post is that in a lot of ways.&lt;/p&gt;
&lt;h2&gt;Why am I writing at all?&lt;/h2&gt;
&lt;p&gt;I have been building software for getting on 20 years now and for the last 10 or so I have been doing a variation on the same theme. Some organizations take to it faster and we get further along the path than others but the path is predictable, at least within my little world of saas startups.&lt;/p&gt;
&lt;p&gt;I am writing to start to encapsulate how I think about building and delivering products. These are things that I often spend time explaining to every new team I work with. What goes into building a great product? What is the difference in a product and a piece of software? Why is reducing toil worth the cost?&lt;/p&gt;
&lt;h2&gt;Okay, but why?&lt;/h2&gt;
&lt;p&gt;I am writing because I want to work with people who want to build great products. I want to find those people who care about bringing value to customers and treat that as their craft. I hope that my writing inspires you to reject &amp;quot;playing at company&amp;quot;, to build just enough software to get the job done (and no less!), and to be driven by needs of real (not imaginary) users.&lt;/p&gt;
&lt;h2&gt;So what should I expect here?&lt;/h2&gt;
&lt;p&gt;I will focus on topics that will help engineers and product managers build great products. The ideas will be mine, though Claude might help me write them down. He already does plenty of work in my codebases.&lt;/p&gt;
</content>
  </entry>
</feed>