For most of the last two years, we held a contrarian position inside our studio: AI-assisted coding had no business near the systems we ship. We build for businesses where a subtle bug has a real price tag. The blast radius of a subtle bug is measured in real money. A confident hallucination in a settlement path is not a quirky anecdote; it is a phone call we do not want to make.
So we watched the vibe coding wave from the shore. We let other studios chase the demos. We kept writing code the way we always have: slowly, with intent, with tests we trust.
Then, in April 2026, Anthropic unveiled the Mythos family. The unrestricted variants stayed behind partner walls for months, reportedly because the same models that write code well can also identify exploitable vulnerabilities in critical infrastructure. In June, Fable 5 arrived as the first publicly available Mythos model, priced at $10 per million input tokens and $50 per million output tokens. Strong at code. Strong at research. Expensive on purpose.
We decided to stop watching. We ran a three-month integration across four active client engagements. This is the report.
How we used to work
Our default loop has always been small. A senior engineer reads the ticket, sketches the change on paper or in a scratch buffer, writes the test, then writes the code. Pair programming when the stakes are high. Code review by another senior before anything touches main. No juniors, no contractors flown in for "velocity," no offshore handoffs. The work is slow because the work is careful.
We had tried earlier generations of coding assistants. They were fine for autocomplete on the trivial line: closing brackets, suggesting an obvious method name. They were dangerous on anything structural. The pattern was always the same: a plausible block of code that read well, passed the obvious test, and quietly handled the edge case wrong. We banned them from anything financial. We banned them from anything cryptographic. That left them useful for boilerplate, which we did not need help with.
What Fable 5 changed
The first thing Fable 5 changed was the failure mode. The earlier generations failed by producing wrong code with high confidence. Fable 5 still fails, but it fails differently: it asks more questions, surfaces more of its reasoning, and stops more often to say it does not have enough context. That alone does not make code correct. It does make code reviewable.
The second thing it changed was the economics of throwaway exploration. At its price point, Fable 5 is not cheap. But the unit you are buying is not tokens; it is candidate solutions. We can ask it to propose three implementations of a problem, each in a separate branch, and read all three in the time it used to take one of us to write one. The cost per candidate is a rounding error against an engineer-hour. The value is in seeing alternatives we would not have considered.
The third thing it changed was the boundary of "code we should write by hand." The boundary used to be drawn around correctness: anywhere correctness mattered, humans wrote it. The new boundary, after three months, is drawn around novelty. Where the pattern is established, the model is usually right. Where the pattern is ours alone, the model is usually wrong.
Where AI earns its place
We kept a log. Every task we delegated, every task we did not, the outcome of each. After roughly 320 logged tasks (illustrative estimate from our internal tracker), a clear pattern emerged.
| Task type | AI fit | Why |
|---|---|---|
| Boilerplate and scaffolding | High | Clear structure, low consequence of error |
| Test writing with defined invariants | High | Constraints are explicit, output is verifiable |
| Refactoring known patterns | Medium | Works well with examples, struggles at boundaries |
| Security-sensitive logic | Low | Subtle errors are invisible until exploited |
| Novel business logic | Low | No training data for your specific domain rules |
| Unfamiliar codebases | Low | Context gaps cause confident hallucinations |
The high-fit category covers more ground than we expected. Scaffolding a typed API handler with validation, error responses, and an OpenAPI annotation is a few minutes of work that the model does in seconds, with output we read in under a minute. We get a verifiable artifact and a starting point. The pattern that works for us is to give the model a tight, opinionated frame and ask it to fill in the shape.
prompts/api-handler.mdWrite a Fastify route handler in TypeScript.
Constraints:
- Path: POST /v1/transfers
- Input schema: { fromAccountId: UUID, toAccountId: UUID, amountMinor: int, idempotencyKey: UUID }
- Validate with zod. Reject on parse failure with 400 and the zod error tree.
- Wrap the handler in a request-scoped logger (pino) with traceId from req.id.
- Return 202 with { transferId, status: 'queued' }. Do not perform the transfer here.
- Throw on any unexpected error; let the global handler convert it.
- Export a named function `registerTransferRoute(app: FastifyInstance)`.
Do not invent fields. Do not add retries. Do not add caching.
Match the existing style in src/routes/payments.ts (attached). That prompt produces code we can ship after a normal review. The constraints are explicit, the surface area is small, and the file it has to match is right there. The model is doing the thing it is good at: filling in a well-defined shape.
Where it does not
The low-fit category is where we have the scar tissue. Security-sensitive logic, novel business rules, and any code that reaches across a context boundary the model cannot see: these are the places where Fable 5 still produces output that reads correctly and behaves incorrectly.
Here is one we caught in review, lightly edited and labeled as an illustrative example:
src/billing/applyCredit.ts (illustrative)// Apply a credit balance to an outstanding invoice. // Generated by Fable 5, given an English description of the rule. export async function applyCredit( accountId: string, invoiceId: string, amountMinor: number, ): Promise<void> { const account = await db.account.findUnique({ where: { id: accountId } }); const invoice = await db.invoice.findUnique({ where: { id: invoiceId } }); if (!account || !invoice) throw new Error('not found'); const credit = Math.min(account.creditBalanceMinor, amountMinor); // BUG: read-modify-write on two rows, no transaction, no row lock. // Two concurrent calls can both pass the check and double-spend the credit. await db.account.update({ where: { id: accountId }, data: { creditBalanceMinor: account.creditBalanceMinor - credit }, }); await db.invoice.update({ where: { id: invoiceId }, data: { paidMinor: invoice.paidMinor + credit }, }); }
The function reads cleanly. The types are right. A junior reviewer would approve it. The bug is that there is no transaction and no row lock, so two concurrent invocations against the same account can both pass the balance check before either update lands. The credit gets applied twice. Real money moves that should not have.
The model did not write a comment saying "this is unsafe under concurrency." It wrote confident code. We caught it because we have a checklist for any function that mutates monetary state, and "is there a transaction and an appropriate lock?" is on it. We did not catch it because we read the code carefully and noticed.
This is the lesson we keep relearning: security is not a feature, it is a property of how you work. AI does not change that. It changes the volume of code you have to apply the property to.
The discipline layer
The thing nobody quite tells you in the demos is that letting a model write more of your code does not reduce the engineering work. It moves it. The hours we used to spend writing scaffolding now go into three places: writing better prompts, writing better tests, and reviewing more code per day.
That last one is the constraint. A senior engineer can carefully review a few hundred lines of unfamiliar code per day before quality drops. If the model writes four times as much, you have not made the team four times faster. You have moved the bottleneck from typing to reading, and reading does not parallelize the way typing does.
So we added a discipline layer. Three rules, written on the wall:
If a human would not be allowed to merge this PR without a test, neither is the model. If the change touches money, identity, or signatures, a human writes the first draft. If the model proposes a structural change, the engineer who reviews it must be able to explain it without reading the diff.
The third rule is the one that bites. It forces the reviewer to actually understand the change, not pattern-match it as plausible. We have killed plenty of plausible PRs this way. We have not regretted any of them.
Our current workflow
The shape of the workday has changed more than the shape of the codebase. A typical change now goes through four steps:
First, an engineer writes the ticket and the acceptance criteria the way they always have. We have not delegated thinking. The model does not get to decide what the feature is.
Second, the engineer drafts a prompt: the constraints, the file references, the explicit non-goals. This is where the work has shifted. A good prompt at our prices is worth a lot more than a good IDE shortcut. We keep a small library of patterns: API handler, migration, integration test, decode-and-validate, idempotent worker.
Third, the model produces a candidate. Often two or three, in parallel branches. The engineer reads them, picks one, edits it, runs the tests, and opens a PR with a brief note on what the model produced and what they changed. The note is mandatory. We want to be able to look back at a year of work and see where the model contributed and where the engineer overrode it.
Fourth, normal review. Another senior reads the PR. The fact that an AI wrote part of it is irrelevant to the standard; the standard is the standard. If it is unclear, it does not merge.
We have not adopted Claude Mythos 5, the unrestricted variant. Project Glasswing is limited to a few hundred organisations and we are not among them. We are not sure we would want to be. The published Fable 5 is already doing more than we expected. The capability ceiling is not our bottleneck.
The takeaway
We were wrong to dismiss vibe coding as a category. We were right to be careful about which parts of our work it touches. Fable 5 did not change what we believe about correctness, security, or handoff quality. It changed where we spend our hours.
If you are a founder reading this and wondering whether your team should be using AI in production, our short answer is: yes, with rules. The rules matter more than the model. A team that adopts AI without a discipline layer ships faster for three months and pays for it for three years. A team that adopts AI with one ships at roughly the same pace and gets some hours back to think.
We are still slow. We are still careful. We still read every line that goes into production. The difference is that more of what we read was drafted by something else, and we have learned to spot, quickly, where it went wrong. That is the skill the next few years will reward: not prompting, but reading.
If you want to talk through how this might land in your codebase, we are reachable. We do not sell AI consulting. We build software, and we are happy to share what we have learned doing it.