AI · Oct 26, 2026 · 10 min read
Fundaia is the deployment platform we built for ourselves: it takes a GitHub repository to its own domain, with a database. When a deployment fails, there is a button in its menu that reads Fix with Claude. Pressing it hands the failure to Claude Code, which reads the log and the repository, writes a test that fails because of the bug, fixes it and leaves the change as a pull request. This post is about that button and, above all, about everything around it: what the agent can touch, who approves the change and what happens when it cannot fix anything.
A project in Fundaia holds services. A service usually comes from a GitHub repository: the platform builds an image, starts it in a rootless podman container and publishes it at its own address. Variables can point at each other, so an application reads its database address from the Postgres next to it without anyone copying it by hand.
Every deployment goes through the same six stages: queue, code checkout, build, start, health check and going live. The new container only takes traffic once it passes the health check. If a deployment fails on the way, the previous one keeps serving, so a red deployment is a problem to solve, not an outage. That is what makes it reasonable to let an agent look at it calmly.
Before any model, there is a diagnosis made of plain rules. It reads the state of the service and answers with a verdict (healthy, needs attention, failing, asleep or idle), its findings ordered by severity and, for each one, the next command to run. It calls no model, so it costs nothing and gives the same answer twice.
Many failures end here: a variable that points at nothing does not need an agent. Claude Code comes in when the cause is in the code or in the build recipe, and only if a person asks for it.
The failed deployment becomes an incident: its failure message is the sample (up to 2,000 characters) and the last 60 lines of its log are the context. From there the run follows four steps, each one visible live in the panel: gather the context, diagnose, reproduce and fix, plus a fifth, opening the pull request, that belongs to the platform and not to the agent.
From a failed deployment to a pull request: the platform sends the log to a Claude Code container that only edits a throwaway clone, checks the diff, opens the pull request itself and leaves the merge to a person; if the agent cannot fix it, it stops and the person can open an issue.
Each step is a separate call to the Claude Code component, which runs claude in non-interactive mode with a ten-minute limit per prompt. The platform reads the answer of each step and decides whether to go on. These are the checks, taken from the code:
const diagnosis = parseAnswer<Diagnosis>(answer)
if (diagnosis === null) throw new Error('El agente no devolvió un diagnóstico legible')
if (diagnosis.confidence === 'low') {
throw new RunStopped(
'rejected',
'El agente no encontró la causa con los logs disponibles, y no ha tocado nada',
)
}
// ...
if (!reproduction.reproduced) {
throw new RunStopped(
'notReproducible',
reproduction.note === ''
? 'No se pudo reproducir el fallo, así que no se ha cambiado nada'
: reproduction.note,
)
}
// ...
if (!fix.fixed) throw new RunStopped('rejected', 'El agente no consiguió arreglarlo')
if (diff.trim() === '') throw new Error('El agente dijo haberlo arreglado sin cambiar nada')Inside its container, Claude Code runs with permission prompts turned off, because nobody is there to answer them. That only makes sense if the container itself is the limit, so the limit is built in layers:
const clone = Bun.spawn([
'git',
'-c', 'credential.helper=',
'-c', 'core.hooksPath=/dev/null',
'clone', '--depth', '1', '--single-branch', '--branch', branch,
// ...
])
// ...
await git(target, ['remote', 'remove', 'origin'])There is no network credential here that can push: the platform takes your changes as a patch, validates them, and opens the pull request itself. Editing files is the whole of what you can do, and it is enough.
The text every one of the three prompts starts with
Before anything reaches GitHub, the platform checks the diff with its own validator, without a model. Some things stop the run. Others the validator classes as needing a person: they do not stop it and they reach the pull request, which nobody merges automatically. The prompt already asks the agent to leave CI workflows, git hooks and install scripts alone unless the failure is literally in one of them:
| The change | What the platform does |
|---|---|
| A path that points outside the repository | Stops the run |
| A file that looks like a credential (.env, private keys, .pem, .key…) | Stops the run |
| An added line shaped like a secret (Anthropic, GitHub or AWS keys, private keys) | Stops the run |
| CI workflows, git hooks, .npmrc or other files that decide where dependencies come from | Lets it through to the pull request |
| An install script in package.json (preinstall, postinstall…) | Lets it through to the pull request |
| Binary files, more than 40 files or more than 2,000 added lines | Lets it through to the pull request |
const credentialLike = [
/(^|\/)\.env(\..+)?$/,
/(^|\/)id_(rsa|dsa|ecdsa|ed25519)$/,
/\.(pem|key|p12|pfx|keystore)$/,
// ...
]
const secretPatterns = [
/\bsk-ant-[A-Za-z0-9_-]{16,}/,
/\bgh[pousr]_[A-Za-z0-9]{16,}/,
/\bAKIA[0-9A-Z]{16}\b/,
// ...
]Only after that does the platform apply the patch on its side, commit it and push the branch with a second token, one that can write contents and pull requests and never leaves the platform's process. It travels in the environment, not on the command line, where any user on the machine could read it.
A person, always. The platform opens the pull request on a branch of its own, labels it autofix and writes the body for whoever has to review it: what was failing, why, the command and the output of the test that failed before the change, what changed and what could still go wrong. It opens with a plain sentence: nobody has reviewed this yet, that is your job.
Fundaia never merges these pull requests. When someone on the team merges one, the branch moves and the platform deploys it like any other push. The platform also looks at who is behind that push: the commit's author is its own bot, Fundaia Autofix, but a merge by a member of the workspace vouches for it. A push that nobody in the workspace vouches for waits until a member approves it.
Most of the design is about this case. Every way of stopping has its own name, and in all of them the incident goes back to open, so nothing is left half-claimed:
| What happened | How it ends |
|---|---|
| The agent opened the pull request | Done, and the incident waits for a person to review the fix |
| The log is not enough to find the cause (low confidence) | Discarded, without touching anything |
| It could not write a test that fails | Not reproducible, with the agent's reason in one sentence |
| It tried and could not fix it | Discarded |
| It said it had fixed it but the diff is empty | Failed |
| The diff touches something it cannot touch | Discarded, naming the file and the reason |
| It reached the cost ceiling | Discarded |
From the same menu, a failed deployment can become a GitHub issue with its evidence: the commit, the failure message and the last lines of the log. The token for that can only write issues. Asking twice links the same issue instead of opening another, so a team that prefers to fix things by hand loses nothing by trying the agent first.
An agent that loops on a stubborn bug can spend a lot. These are the defaults of each service:
We have had the autofix on runtime errors since August 2026 and on failed deployments since September. The part that uses AI is three prompts. The rest is code that does not trust it: a deterministic diagnosis first, a container that can only edit files, a validator that reads the diff, a ceiling on money and a person who decides.
That is the same split we use when we build AI agents for a client's processes: the model proposes, plain code checks what it proposed, and the step that cannot be undone is a person's. It is also how we think about software maintenance: the agent saves the first hour of reading logs, not the review. If you are choosing the model for that kind of work, we compared the current ones in Opus 5.5, GPT-6 Astra or GPT-6.1 Sol.
No. It edits files in a throwaway clone and hands back a diff. The platform validates it and opens a pull request, which it never merges. A change only reaches production when a person on the team merges it and the usual deployment picks it up.
It receives the repository, the failure message and the last lines of the log, not the service's variables. If the application prints a secret in its own logs, that line travels like any other, which is a reason not to log secrets. Going the other way, a change that adds a credential file or a line shaped like a key stops the run before it reaches GitHub.
That is why it has to reproduce first. If its diagnosis has low confidence, or it cannot write a test that fails because of the bug, the run stops without changing anything. If it gets through, the pull request carries the test and its output, so the reviewer can check the claim instead of trusting it.
It depends on the model and on how much it has to read, so we do not give an average. What is fixed is the ceiling: each incident has a cost limit (2 € by default), checked after every prompt, and the agent runs on prepaid credit that stops it when it runs out.
AI · Oct 25, 2026 · 9 min read
There is no winner for everything. Opus 5.5 scores best on long, hard changes, GPT-6.1 Sol does nearly as well for a twelfth of the cost per task and GPT-6 Astra leads on operations. How we split the work between them, what happens to your company's data and what October's other models bring.
Case studies · Oct 26, 2026 · 11 min read
Leaderbrock's sales team works across Europe and America. How we replaced a shared spreadsheet, an envelope of receipts and the lack of any map with one reactive Java backend, an Expo app and a web panel: expenses from a photo that AI drafts and a person files, an agenda in the phone's time zone and a GPS route that tells a flight from noise.
Case studies · Oct 26, 2026 · 12 min read
ReservPark notices through the car's Bluetooth that you parked, asks whether you are leaving when you walk back to the car and tells drivers nearby, and lets people rent out their garage by the hour or by subscription. How we built the native detection, the background location rules, the 30-minute free spots and garage bookings that cannot be oversold.