Skip to content

I use Google Analytics to understand what gets read, shared and clicked here. It only loads if you accept — nothing third-party runs before that. How Google uses this data

The blueprint · open

Architecture — the blueprint, in the open

This site is the argument. This page is the blueprint — how it's built, and how you'd build your own.

I started the year lost

A project that was not going well, a pile of catch-up obligations on AI tooling, and things degraded until the end of the year. Kiro had been within reach for a while by then, and I started the year willing to learn how to use it. And there is a detail I suspect a lot of senior engineers are living through and not saying out loud: I had the agentic development tool in hand — and still felt outside the hype.

Because the problem was not the tool; it was where I was going to use it. At that point in the year, all the AI work I was close to split into two halves: the modelling, which is strong, and the rest — systems integration, legacy that cannot be replaced, the ordinary complications of corporate IT. That second half is where I have spent eighteen years, and it is the one with no ready-made use case to learn on — the case has to turn up on its own, in real work.

The case that turned it around was not this site. At the beginning of the year, in January, I started building an authentication and authorization mechanism on the side — dense business rules, custom-built on Spring Boot and Spring Security, integrating legacy systems. I would never have delivered that without an agentic development tool — and it was not only the deadline: I was carrying tech-lead responsibilities on that project at the same time. That is what the tool bought. Not typing speed: both of those fitting into the same week. And nothing is more fun to me than seeing an application running beautifully — at a scale I could not reach on my own. That was where I saw something I had not seen in a long time: if the requirement is where I stay and the code is worked by AI-DLC, a software engineering project can be more audacious. Not as a forecast — as what I saw at that moment, with the thing running in front of me.

"Computer programming is an art, because it applies accumulated knowledge to the world, because it requires skill and ingenuity, and especially because it produces objects of beauty."

— Donald Knuth, 1974

White serif lettering standing off a pale museum wall, angled away from the camera, with Donald Knuth's name and the year 1974 below it to the right.
Fifty years before me, someone had already named the part I like most — and the wall is in the museum that exists to record it.

The holiday was in May, in San Francisco and the Valley, and the rest of this page comes out of it. There was not a place I passed through without some AI offering in it — on the train, on the street, in a shop window, on the lanyard of the person next to me. I came back with the idea of what to do, and since then I have run it on two fronts: an internal one, at work, with Kiro, and this one, in public, with Claude Code. Two harnesses running the same kind of work is what lets me separate what comes from the model from what comes from the setup around it.

One morning I took the Caltrain south — 8:57, next stop Palo Alto. The carriage was open laptops end to end, loops running, people trading ideas out loud on the way to work. It was not an event, not a community, nothing arranged. What I concluded from that, rather than saw: a lot of people doing the same kind of work, in the same place, at the same time — close enough to overhear without asking and to answer without scheduling. I was inside that for one week, in May. The rest of the year, I am not.

A montage of three frames from the same week: on the left, me and my partner on a paved walkway beside a row of red, yellow and turquoise bicycles, with trees and a clear sky behind; top right, the onboard display in a Caltrain carriage, reading "Southbound · 510 EXPRESS · 8:57a" and, below it, "NEXT STOP Palo Alto"; bottom right, a museum case holding a 2007 iPhone taken apart behind acrylic, its components labelled — camera, light sensor, mic, speaker, SIM, vibrator — under the legend "iPhone · INTRODUCED IN JUN 2007".
One week, in May: Google's visitor centre in Mountain View, the 8:57 Caltrain south, a case at the Computer History Museum. One train, one morning, no measurement. This is not data; it is what I saw.

Outside that week the carriage does not exist, and it is what the public front stands in for — there is a reason the front exists rather than a notebook. There are far too many configuration options — which harness, which hooks, which persona, which gate, which model — and nobody has enough sessions to test them all alone. Trading each other's experience of using AI is what will speed that learning up, and that is why what is here is the whole setup, not only the conclusion it reached.

What the requirement demanded, and the architecture it justified

The requirement for this public front is short: publish content, in two languages, with the whole build in the open. That is what decides the architecture, the bill, and the rest of this page.

And it was not built lean. It was built full and then cut: there was a backend platform — BFF on Lambda, DynamoDB, Cognito, SES —, a Lambda@Edge rendering OG images per request, a link-unfurl service, GitFlow with staging and production, and an offline-first PWA. A database with nothing to store. Auth with nobody to authenticate. A staging environment for a site whose revert is a merge. Each one was defensible when it was decided, and none survived the question "what is this for, here" — and every reversal is on the record with the decision that replaced it: 0025, 0026, 0027, 0028, 0029.

The cut is not this page's subject; it is the consequence. What is left is three things — a static site, a dev-loop plugin and an agent runtime — and they are not tiers of one system: each one exists without the other two. The site runs without the plugin. The plugin installs in any repository. The runtime is not mine. What sits in the middle is the one thing none of the three delivers on its own — and it is where the way I build this lives, which is the way I want to be hired to build: AI-native development with the SDLC rigor most AI work skips, a loop built on Context & Harness Engineering, with AI-DLC running inside it.

The three pillars, and what sits in the intersectionThree circles of the same size, overlapping, with one shared intersection at the centre. The first circle is the solution, the tadeumendonca-io repository, and inside it sit the React SPA built with Vite and TypeScript, the Terraform that provisions CloudFront and S3, the pipeline with its gates and its deploy, and the markdown content held in the repository itself. The second is the harness customization, the tadeumendonca-skills repository, and inside it sit the personas in the agents directory, the hooks registered in hooks.json, the skill library in the skills directory, the six commands a person types in the commands directory — autonomy, blueprint, new-issue, sprint-planning, sprint-review and sprint-retrospective — and the methodology ADRs. The third is the harness runtime, Claude Code, and inside it sit the orchestrator and the subagents, the six hook events it fires — PreToolUse, UserPromptSubmit, SessionStart, Stop, SubagentStart and SubagentStop — the permission policy, and the tools with MCP. At the centre, where all three overlap, it reads Context & Harness Engineering. That is the claim the drawing makes: none of the three circles is the discipline on its own, it is what exists where the three meet.The solutiontadeumendonca-ioReact SPA · Vite · TSTerraform: CloudFront, S3Pipeline: gates, deployMarkdown in the repoThe customizationtadeumendonca-skillsPersonas in agents/Hooks in hooks.jsonThe skill libraryCommands you typeMethodology ADRsThe runtimeClaude CodeOrchestrator, subagentsSix hook eventsThe permission policyTools and MCPContext & HarnessEngineering
The three pillars, and what sits in the intersection

What sits in the intersection is the actual work: deciding what the harness refuses, what it advises and what it only documents — and then proving the inventory of that is still true.

The launch showed the output. The case shows the machine.

Pillar 1 · the solution

A fully static SPA — React + Vite + TypeScript — served from S3 behind CloudFront, with a small CloudFront Function rewriting clean URLs. No server, no database, no auth. The content is markdown in the repository itself, and every published route is prerendered at build, in both languages — an article can be held back before publication, and a held one is compiled into the bundle without ever being prerendered.

(→ ADR-0002 fully static / no backend · ADR-0013 S3 + CloudFront)

End to end, backstage included — and the interesting thing about this picture is what is not in it:

The lanes and the tiers — what the reader meets, and what keeps it standingA grid read from left to right, four columns wide — public, devices, frontend and cloud infra — with three lanes stacked inside them. The top lane is the audience, what the reader meets on the site: the public arrives from a link, the device asks for a URL, and what comes back is prerendered HTML in both locales, with the React SPA taking over afterwards and no third party loaded before the reader allows it — GA4 only on consent, YouTube only on a click. That page comes whole from the cloud infra column: Route 53, ACM, CloudFront with its rewrite function, and a private S3 bucket that answers only that distribution. Between frontend and infra there is no backend column, and that absence is the claim this drawing makes: there is no application tier, because the requirement never asked for one, and nothing of mine runs per request. The two lower lanes are the backstage, what nobody sees and what keeps the operation running. The production lane: I open the Issue and ratify the irreversible; GitHub is the console, from any device, and a claude mention runs the agent inside CI with no machine of mine switched on; the repository and the build carry the personas and the hooks that deny the call, and produce both locales and the CV PDF; Terraform applies the infrastructure pipeline-only, with state in Terraform Cloud. The operation lane is the thinnest, and it is thin as a finding rather than by design: what I measure is GA4 after consent, so whoever declines is never counted; nothing watches the reader's device, no RUM, no access log and no uptime monitor; after every deploy a smoke run hits the live apex and checks that the published function is this repository's; and over the whole account there is a budget that emails, which is the only continuous watcher there is.CLOUD INFRAFRONTENDDEVICESPUBLICopens a linkasks for a URLcomes whole from hereand there is nobackendbetween the twoopens the workstarts the agent looppublishes to theoriginAUDIENCEreaders, recruiterswhoever arrived from alinkBACKSTAGE · productionme I open the Issueand ratify theirreversibleBACKSTAGE · operationwhat I measure:GA4 only after consentwhoever declines isnever countedbrowser, phoneand the LinkedIn and Xscrapersasking for the sameURLGitHub, from anydeviceIssue, comment, PRa claude mention runsthe agent in CInothing watches thedeviceno RUM, no access logno uptime monitorprerendered HTML inboth localesthe React SPA takesover afterno third partybefore the readerallows itthe repository and thebuildpersonas in agentsand hooks that denythe callboth locales and theCV PDFafter every deploya smoke run againstthe live apexand the live functionchecked against thisrepoRoute 53 · ACMCloudFront with therewrite functionprivate S3, reachableonly by OACTerraform,pipeline-onlyplan on the PR, applyon merge, over OIDCstate in TerraformCloudover the whole accounta budget that emailsthe only continuouswatcher
The lanes and the tiers — what the reader meets, and what keeps it standing

The absence is the design, not a gap. A picture like this, for a system like this, usually carries an application column, a database and internal integrations between the frontend and the infrastructure; here there is no column there at all, and what the reader asks for comes whole out of a bucket. The only third party at runtime is analytics, and it is consent-gated. And "no backend" raises one question before all others — how does a crawler see this — whose answer is that nothing has to be rendered for it to: what it asks for comes back as complete HTML, with the OG tags already in it, straight from a static file. No SSR, no edge rendering — the edge's rewrite function runs on every request for a page and touches the URL, nothing else.

The limit travels with the claim, because it is the part a reader can falsify: a URL that does not exist answers 200, not 404 — and what comes back is the landing page, complete with the landing page's own OG tags, under an address that was never real. CloudFront maps 403 and 404 onto /index.html, which is what lets a SPA work on deep routes and is a real trade rather than a detail. It has bitten here once: a path misroute sent the per-article OG images into that same fallback, and each one answered 200 text/html to every scraper that asked.

The only logic that runs between a reader and a file is that function: ten executable lines, with their own unit tests and a post-deploy check that the live function still matches this repo. And the bucket is not public in any sense: it answers s3:GetObject only from this distribution.

(→ ADR-0004 build-time render, no SSR · ADR-0005 every URL OG-complete · ADR-0033 consent-gated analytics · iac/frontend.tf the distribution and the policies)

USD 6.57 a month

This figure measures what the site added, not what it depends on, and it measures what the site runs on, not what I build it with. "Near-zero" is the easiest claim on this page to make and the easiest to leave unchecked — so here is the bill, with the serving lines read from the account's daily cost in late July 2026 and the registration read from the registrar's price list. Neither estimated:

  • The domain — USD 71.00/yr for the .io, an annual charge that lands in one month. USD 5.92/month amortized. I picked the .io for branding, not for cost: that is the honest reason, and the single line here you can decline.
  • Route 53 — USD 0.50/month, fixed. The hosted zone, whether or not anyone visits.
  • S3 — about USD 0.15/month, and it is deploy writes, not reads.
  • CloudFront — effectively USD 0.00 at this traffic.

Outside AWS the criterion is the same. GitHub Team and Claude Max are paid and stay outside the total — the GitHub Team subscription predates the site, though the CI load on it is entirely the site's own; GitHub Actions and SonarCloud are zero because the repositories are public — a property of the repos, not of the plan — and Terraform Cloud is zero because the infrastructure is small. And iCloud+ is the line that shows the criterion being applied rather than announced: it predates the site, but it carries the custom-domain email at the apex and iac/email.tf provisions its MX, DKIM and SPF records — so it is not adjacent to this infrastructure, it is inside it. (→ ADR-0016)

Outside the total sits every hour of mine as well: USD 6.57 a month is what it costs to keep this running, not what it cost to build. In people, it cost one — weekends, alongside consulting work. And the same reading turned up roughly USD 12.80 a month the site was not using: WAF web ACLs and idle public IPv4 addresses, left behind when the backend was retired. I found them by reading the bill, which is late — infrastructure you stop using does not stop billing — and what watches now is a budget in iac/budget.tf deliberately not scoped to this project's tags: otherwise it would only ever see spend this repo created, and this was exactly the kind it did not.

Pillar 2 · the customization

The interesting part isn't the stack — it's how it's built: agent-led verification, human-residual. The agent proves "done" with mechanical gates and real evidence (lint, types, tests ≥85%, a green build, SonarCloud, functional E2E, a fresh-context reviewer); the human keeps the irreversible and architectural calls. That loop lives in a separate plugin — tadeumendonca-skills — so it's a methodology you can adopt, not something bespoke to this site.

How work crosses the agent tiers — and where I come inA top-to-bottom flow in three tiers, with the owner at both ends and one large box in the middle that runs without him. At the top is me: I am the only origin of demand, and I open the Issue. Tier 1 is intake, and it is not one box: it is three lanes, and the issue's type decides which one it enters. A product issue closes through the two leads that disagree by design, product-lead and tech-lead. A content issue closes through product-lead alone, judging whether the piece is worth writing at all — not how it will be written. A loop issue, which is the machinery itself, closes through agents-lead alone — never paired, and with no exception — because the machinery is that profile's object and nobody else's. The three lanes all reach the same ready label, which is the artifact saying the description was closed — and on a loop issue that label is mine alone to apply. From ready downwards the AFK stretch begins, the part that runs without asking once I tell it to drain the queue: everything inside passes through the orchestrator, which is the main session and the hub every lane goes through, which commits and pushes, and which never merges and never decides the irreversible — a hook refuses it both of those from the main session. On the repository edit there is no lock at all: the hook that used to refuse it was deleted, so what keeps an edit flowing through the persona that owns it is now a rule and not a mechanism. What stands beside that rule is scrum-master, drawn off the path here: a profile holding no tools whatsoever — it cannot dispatch, edit, run a command or apply a label — which ranks the eligible pool and names in a record who should act next. Three parts, and the third is the one to keep: nothing prevents the edit, the record names who should have acted, and the record is written by the party it constrains and read by nothing. That is detection, self-attested, rather than prevention. It dispatches tier 2, the build, split by type as well: developer on product, content-writer on content, agents-lead on loop, building what it has just stress-tested. On content the build is a pair rather than one profile, which is why that one box carries two names: content-reviewer reads the draft against the same ruler it was written against, at most two rounds, and what it blocks is a draft rather than a merge. The orchestrator dispatches both, like everything else in here — neither hands work to the other directly. Out of that comes one merge request per story, reaching tier 3 — fresh context, no authorship bias — where quality-assurance checks the Definition of Done and, separately, whether this can break production; it is the only one that may merge. The loop lane reaches that same box rather than going round it, and it answers for more there rather than less: on a change to the machinery itself, quality-assurance checks the same Definition of Done and the same question about production, and additionally requires that agents-lead left its verdict marker before it may merge at all — a reviewer that has to have been present, not a review that is skipped. Safe-class work it merges itself, and the merge is the deploy. Boundary-class work — infrastructure, the loop's own rules, publishing in my voice — leaves the AFK stretch and comes back to me, and only after my go does it ship. Once a merge request exists, refusal is a single channel: the gate asking for changes and my no-go land in the same sent-back box, and that box returns through the orchestrator, never straight to whoever built it. Nine persona boxes, eight names, for two different reasons: product-lead and agents-lead each appear twice, because the same profile is dispatched at different moments; and one box carries two names rather than one, because the content lane is a pair. And there is a dashed channel between me and the orchestrator for when something is stuck — it exists throughout and it is not on the path. That is the claim this drawing makes: between the ready label and the merge there is no human on the path, and I appear only at the two ends — what crosses that stretch alone is the safe class only.AFK · from ready to merge, nothing on the path is humanTIER 1 · contentTIER 1 · productTIER 1 · loopproductproductcontentloopproductcontentloopdispatched by theorchestratorsafe classboundary classgochangesno-goHITL · MEthe only origin ofdemandI open the Issueagents-leadalone the machineryis its objectproduct-leadtech-leadthey disagree bydesignproduct-leadalone whether it isworth writing at allTIER 1 CLOSES HERE ·the ready labelthe description closed and on a loop issue,mine alone to applyORCHESTRATOR ·the main sessiondispatches everypersona, commits,pushesa hook refuses it themerge and the trunkpushon the repository editnothing refuses itscrum-master · holdsno tools at allranks the pool, nameswho acts nexta record it writesitself nothing readsitTIER 2 · BUILDdeveloper productTIER 2 · BUILDcontent-writer withcontent-reviewercontentat most two rounds,against the same rulerTIER 2 · BUILDagents-lead loopbuilds what itstress-testedMERGE REQUEST · oneper storyTIER 3 · GATE fresh context, noauthorship biasquality-assurance ·the only one that maymergeevery lane theDefinition of Done,and whether thisbreaks productionloop plus anagents-lead verdictmarkersent back one returnchannelmerge to main = thedeployHITL · MEboundary class:irreversible,architecturalgo / no-go
How work crosses the agent tiers — and where I come in

I appear at both ends, and they are different jobs: at the start, opening the Issue, and at the end, on boundary-class work only, deciding whether it ships. Between one end and the other there is no human on the path. And the drawing claims something stricter than "at the plan": I am the only origin of demand — nothing enters the queue on its own — and what closes intake is the ready label, the artifact saying the description was closed; from ready downwards, only the safe class crosses alone. No lane goes round the gate, including the one that builds the loop itself. A change to the machinery is written by agents-lead and still reaches the same box, and it answers for more there rather than less: the same Definition of Done, the same question about production, and on top of both a requirement no other lane carries — that agents-lead left its verdict marker before the gate may merge at all. A reviewer that has to have been present, not a review that is skipped. And the cost of it, since the rest of this page states its own: what decides a change is safe is the same kind of thing that wrote the change. Mis-classify one and it takes the empty path. What makes that acceptable here is blast radius, not confidence — it is a static site, and a revert is a merge.

(→ ADR-0003 trunk-based, one environment · ADR-0018 the CI gates)

What the harness is made of

What the harness is made ofThe claim comes first, because the claim is what the grid is for. Of everything the plugin exports, exactly one kind can REFUSE — a hook — and only on two of the six events it registers on. Personas ADVISE, and skills and commands only DOCUMENT. Four kinds against three classes of force is twelve cells; five hold something and seven are empty, and the seven empty ones are the argument. Now the inventory the claim is read off. The lanes are the 14 hook registrations in hooks.json, written by 13 scripts because preflight is registered twice; the 8 personas in the agents directory; the 15 skills in the skills directory; and the 6 commands in the commands directory. The deny column holds one cell, and it holds 3 registrations across two events of different shapes: permission-guard on the matcher Bash and mcp-guard on the matcher for MCP tools, both on PreToolUse, which refuse a tool call before it runs; and preflight on UserPromptSubmit, which refuses the prompt itself, before the turn starts. Persona, skill and command have no cell there at all. The middle column holds one cell too: the 8 personas — agents-lead, content-reviewer, content-writer, developer, product-lead, quality-assurance, scrum-master and tech-lead — which ADVISE, and that is a claim about their judgement rather than about their seat, because a lens nobody dispatches fails silently. The third column, the one whose components only DOCUMENT, holds three cells: the 15 skills, which is what the model reaches for on its own; the 6 commands, which is what a person types; and the other 11 hook registrations — 4 on SessionStart, 2 on SubagentStart and SubagentStop, and 5 on Stop. Read the two columns together and preflight appears in both, because it is registered twice with a different class on each event, and that is the drawing being derived rather than drawn: nobody authoring by hand would draw one script in two columns of the same grid.DOCUMENTS11 hooks · nonerefuses where it sits4 hooks · SessionStartpreflight ·session-wip ·session-plugin-version· cadence-notice2 hooks ·SubagentStart andSubagentStopdispatch-metrics-start·dispatch-metrics-stop5 hooks · Stopzombie-loop-detect ·orchestrator-tool-censuspremature-pr-link-detect ·owed-pr-link-detectclosure-artifact-guardStop and SubagentStopcould block none ofthe six does no persona15 skills · skills/what the model reachesfor6 commands · commands/what you typeautonomy · blueprint ·new-issuesprint-planning ·sprint-reviewsprint-retrospectiveADVISES no hook8 personas · agents/agents-leadcontent-reviewercontent-writerdeveloperproduct-leadquality-assurancescrum-mastertech-lead no skill no commandDENIES3 hooks · two events,two shapes2 hooks · PreToolUserefuse a tool callmatcher Bash ·permission-guardmatcher mcp__.* ·mcp-guard1 hook ·UserPromptSubmitrefuses the promptpreflight no persona no skill no commandkind · what -skills exportshooks · 14hooks.json13 scripts one isregistered twicepersonas · 8agents/skills · 15skills/commands · 6commands/
What the harness is made of

Of the plugin's own components, exactly one kind can stop you, and that is the honest version of the adoption pitch: three of the fourteen registrations in hooks.json return a denial before the act, and the act does not happen. They do it in two different shapes, which is the part worth having: permission-guard on Bash and mcp-guard on the MCP tools sit on PreToolUse and refuse a tool call; preflight sits on UserPromptSubmit and refuses the prompt, before the turn starts at all. the three PreToolUse hooks — permission-guard and wip-guard on Bash, and orchestrator-write-guard on the file-writing toolsstruck: of those four claims, one survives. Two of those guards were deleted in the plugin and mcp-guard had never appeared on this page at all. And nothing here caught it — which is the late leg described two paragraphs down, arriving as an instance rather than as a caveat: the drawing agreed with the manifest, so that check stayed green while both sides were stale together, and a deletion over there fires nothing on this side. And preflight is drawn in two columns of the grid above, because it is registered twice with a different class on each event — which is the one thing here nobody authoring by hand would have drawn.

The other eleven registrations only report, and not for the same reason — a distinction this page owes you rather than one it can round off. Five of them sit on events that refuse nothing, SessionStart and SubagentStart, so those five could not block if they wanted to; note that the reason is the event, not the absence of a tool call, because UserPromptSubmit has no tool call in front of it either and denies anyway. The other six could. Stop can block the turn from ending and SubagentStop can block a subagent from stopping, and every one of those scripts declines: every one of their exit paths is a success. zombie-loop-detect notices, one turn late and once per session for that head, that a branch is sitting on a gate verdict nobody acted on; dispatch-metrics-stop files the dispatch's numbers and gets out of the way; orchestrator-tool-census names what the orchestrator did with its own hands, write and post calls apart from reads, and decides nothing about it. Six hooks choosing not to be mechanisms says more about this harness than one did. And the personas advise — their judgement is checked by nothing, and this repo's own guide says in as many words that a lens nobody dispatches fails silently. That is the guarantee the loop gives — and it is worth exactly what the inventory in the drawing above is worth.

And that drawing's inventory is checkable — that is the second guarantee, and it is a different kind of thing. Rename a persona in the plugin and this repository's build goes red. The drawing above is authored by hand: a test compares it, node by node and count by count, against a committed manifest, in both editions; and a CI job compares that manifest against the plugin's live tree. That is exactly the difference between drawing a harness and proving the drawing is still it, and it is mechanical. And it has two legs, with different limits, stated here rather than later. From drawing to manifest, the comparison includes the enforcement class of all twelve cells, in both editions: give a persona denies in the manifest and this goes red, and that is the grid's central claim. From manifest to the plugin's live tree, the check arrives late, since nothing on this side can see a merge over there, and each component's class comes from a rule about its shape — which event a hook is registered on — rather than from reading what the script does: on re-reading the manifest, what is checked is that the class is a legal value, not that it is true of that component.

And that is why I call this one thing and not another. AI-DLC is not mine — it is AWS's name for a delivery lifecycle whose stages are run and verified by agents; I adopt it, I did not coin it, and it runs inside this rather than beside it. Context & Harness Engineering is the claim I am making, and the two words are two different things to build. The context is what an agent reads before it acts: the skills, the records, the briefs that tell it what was already decided, so it does not decide it again differently. The harness is what stands between it and the act: the hooks, the gates, the personas that read what it produced — and the grid above is the inventory of which of those can actually stop it. Neither half is the practice on its own — context with nothing holding it is advice, and a harness with nothing to read is a wall — and building, versioning and proving both is the work. Adopting a methodology costs nothing to say — which is precisely why saying it is worth nothing. This one is paid for, and the payment is in the paragraph above: a build that breaks when the inventory stops being true. It is the same agent-led verification ruler the rest of this page applies to code, turned on the methodology: whoever makes the claim is who produces the evidence.

(→ ADR-0043 the inventory pinned to the plugin)

Eight personas, what each one argues against — and what each one carries when it is dispatched. The last column is each brief's preload: the skills that enter the persona's session before it reads the first line of the task.

whowhat it ownswhat it argues againstwhich skills it carries when dispatched
product-leadthe reader, value, order, slice size — and positioning, voice, and the truth of anything published outside the content lanetech-lead; and on a product or loop diff it blocks a merge when it finds a published claim that is untrue — by convention rather than by hook. On content that veto is gone since 2026-09-03: there it holds intake and nothing else, and no persona holds a copy block on that lane at allagents-configuration · engineering-standards · definition-of-ready · shell
tech-leadarchitecture, measurement, sequencing — and it writes the product and system decision records; the ones about the loop itself are agents-lead'sproduct-lead, by design: product-and-market and system are genuinely different optimisationsagents-configuration · engineering-standards · definition-of-ready · documentation-standard · devops · shell
developerthe slice end to end — app, infrastructure, pipeline, and the tests written as it goesnothing. It builds, and it is what the gate is pointed atagents-configuration · engineering-standards · code-review · quality-gates · devops · shell
quality-assurancedelivery against the Definition of Done, and separately whether a change can break productiondeveloper, on both axes in one pass — and it is the only one the permission hook lets mergeagents-configuration · engineering-standards · definition-of-done · quality-gates · devops · shell
content-writerdrafts articles, site copy and social-post language in the owner's voice — shapes, cuts, structures and translates an experience he already has, never originates onecontent-reviewer, and that is the whole of it: it reads the draft against the very ruler it was written against, and since 2026-09-03 product-lead does not run the copy lens on this lane at all — its role in content is intake, and nothing elseagents-configuration · engineering-standards · shell · published-voice · content-publishing
content-reviewerraising a draft's bar before it reaches me — at most two rounds against published-voice, and it blocks nothing at all — it repairs the draft in place, on two grounds and only two: where it can quote a clause of that skill, or where the claim is false against the sourcecontent-writer, and this is the roster's first true pair: everything that meets neither ground comes back labelled advisory-and-droppable, with the prose left aloneagents-configuration · engineering-standards · shell · published-voice · content-publishing
agents-leadthe machinery itself: hooks, permissions, briefs, skills and commands, the plugin — and it writes the decision records about the loop, the other half of the split aboveme — and that is the interesting case: its counterpart is not another persona, it is the one seat in this loop that had nobody to argue withagents-configuration · engineering-standards · documentation-standard · definition-of-ready · devops · shell
scrum-masterthat the rites happen, in order, and that nothing is skipped — it ranks the eligible pool and names, in a record, which profile acts nextnobody, and it holds no tools at all: it cannot dispatch, edit, run a command or apply a label, so what it produces is a record the main session executes — and nothing reads itagents-configuration · engineering-standards

Two things in that last column are worth saying. agents-configuration and engineering-standards are in all eight — the universal preload: understanding the loop itself, and the engineering standards it is run against, belong to no specialty. shell — the file-and-command discipline — is in seven of the eight, and the one it is missing from is scrum-master, which holds neither Write nor Bash, so the rule would have nothing to govern there. And only 11 of the library's 15 skills are preloaded by anyone: the four nobody carries — backend, cloud-infrastructure, frontend and planning-poker — only reach a session if the model finds them on its own, through their description.

And this table is authored by hand — the new column included. The persona names in the drawing above are compared against the manifest and against the plugin's live tree, so retiring a persona reddens a build here. Down here nothing compares anything: check-harness-drift checks persona names and counts, and does not check which skills each one loads. Someone changes a brief's skills: block and this column starts lying the next day, with no signal at all. And a role changing hands reddens nothing either: what that check compares of a persona is its name, and how many personas there are — never what a row claims one does. Decision-record authorship split between two of these rows and no build anywhere noticed; those two cells were corrected by hand, like everything else in this table.

One line runs under all of that, and it is a line about consent rather than about tooling. Everything in the drawing above is committed — hooks, personas, skills, commands — and that is deliberate: it is what makes the work reproducible, so a fork inherits the floor itself rather than a description of it. What is not committed, and will not be, is the setting that makes the operator reachable. Every session I run has Remote Control on from the first second — remoteControlAtStartup, which opens a bridge so I can watch the live local session and approve its tool calls from my phone. It is not the cloud sandbox Claude Code also offers, and the two are not interchangeable: inside a cloud session Remote Control reports itself unavailable, because the local session it exists to reach is not there. That key lives in ~/.claude/settings.json, on my machine, in the one file this repository cannot ship.

That asymmetry looks like a gap in the harness, and the tool had already settled the argument — I had just never read it. So I read it: not the name of the key, which is not a specification, but the shipped binary. Repo-scoped settings cannot turn Remote Control on. Commit "remoteControlAtStartup": true to a project's .claude/settings.json and the CLI ignores it and says why — "repo-scoped settings cannot enable Remote Control; set it at user scope". The one thing a repository can do with that key is set it to false, and that direction is honoured immediately, ahead of whatever the person running the session prefers. Enabling is a person's decision; disabling is a project's; and only the second one travels through a clone.

Which is the right way round for a repository whose whole premise is being forked. Committing the true would have handed a session capability to everyone who cloned this and to CI, without one of them choosing it — and, per the paragraph above, it would not even have worked: a line that does nothing while reading like it does something is the exact failure this page keeps naming. So the setup step is in the README, both methods, with what each one costs. This page keeps the line and not the instructions.

Pillar 3 · the runtime

The orchestrator is the part of the harness you cannot install. It is in none of the inventory above — not in the components grid, not in the manifest, even though the tier flow draws it right in the middle of the AFK stretch — and it is the main session: the context that reads an Issue, decides which persona to dispatch, and weighs what comes back. The actor is not a plugin component, its policy partly is, and what you supply is the context that runs it. It is also the party the boundaries above are drawn against: the middle column can say no more than that a persona advises, and the reason it can say no more is that nothing forces a dispatch — which names the failure mode without naming who dispatches. That is the orchestrator, and a lens it forgets is a lens nobody ran.

And its context runs out. That is what a subagent buys: it reads, runs, gets it wrong and redoes it inside its own session, and what reaches the orchestrator is the conclusion. A task costs the orchestrator its verdict, not its execution, which is why the one real lever this harness has is verdict length, turned by writing the persona briefs. I measured it once, on this repo's own session, on 7–8 August 2026, by parsing the transcripts: what stayed inside the subagents was over an order of magnitude more than what came back. And the saving has a ceiling — even so, the returned verdicts were a large slice of everything the orchestrator took in from a tool. It is not an escape: that session compacted twice anyway. The number is not published, because the input is a private session transcript that no gate can reach.

And the ground under it moves. This is the part the rest of this page does not have: I control the site, I control the plugin, I do not control the runtime. Whoever produces it ships change constantly, and every new model changes which configuration still makes sense — not because the configuration became wrong, but because it was compensating for a weakness that is gone.

That is not my inference. When Opus 5 shipped, the Claude Code team deleted more than 80% of their own system prompt — their product's, not somebody's personal config — and the model got better without the scaffolding. And not as a one-off: every major model upgrade needs less scaffolding, so you delete rules and re-add them only where the model still fails. That is a cycle, not a spring clean.

The thesis that comes with it is the part I care about, and it is a hard one: frontier models are being hobbled by products built for yesterday's weaker models, and the advantage goes to whoever puts engineering effort into verification rather than instruction. That is the person who built the tool saying it — and the name I give that move, agent-led verification, is mine, not his. I am not quoting it for decoration: it is independent corroboration of a choice I had already made, from someone holding data I do not have.

And it is why this loop is made of hooks and gates rather than of a giant prompt explaining to the agent how to behave. Instruction ages with every new model, and it ages silently. A gate does not: it checks the result, and the result is the same thing before and after the upgrade. If the argument above is right, the part of my harness that survives is the part that verifies — and the part that instructs is the part I will be deleting.

Boris Cherny, who built Claude Code, on the Y Combinator channel:

The decision record IS the documentation

The classic argument for ADRs is the human of the future: record why the decision was taken, so that two years from now somebody does not undo it without knowing what was at stake. Here the argument is a different one, and it is what decides the format.

In a repository where the developing is done by agents, the record is inference context. An agent has no memory of what was discussed — it has the repository, and that is what it infers from. If the architecture that formed over time is not anchored somewhere in the code itself, every new change is decided without it, and the result is not one isolated wrong call: it is a new decision that contradicts a decision nobody remembers making. That is why a reversed decision stays here and says it was reversed. Without that mark, the record of a retired architecture reads as instruction — which is the cheapest way there is to get an agent to rebuild the very thing that was cut on purpose. With one exception, and it is the only one: there were two WAF web ACLs and only the regional one has an ADR — the CloudFront-edge one was built, was cut, and its record is this sentence rather than a file.

That purpose is what picks the format, not the other way round. MADR: context, the options that were on the table, the one decided, and the consequence. One short document per decision, one file per decision, all in the same repository the agent already reads — no wiki, no separate tool. What a format like that gives a human reader is traceability; what it gives an agent is what it needs in order not to contradict.

There are 49 decisions — and what is mechanical here is the index, not this number. The index is generated from docs/adr/, committed as an artifact, and checked in CI: adding or superseding a decision without regenerating it turns the pipeline red, so the artifact and the directory cannot drift apart. The 49 in this sentence is typed by hand: while the table was rendered here it came checked for free; cutting it removed that tie, and what holds the number up now is the link below, one click from counting them yourself. The rows are deliberately not printed here — this page points at canonical detail instead of restating it, and a 49-row copy would be that rule broken in the one section that exists to defend it.

(→ the decision library · ADR-0001 lean by design)

Replicate it for your own context

It's all public — two repos, no secrets.

tedeuxx/tadeumendonca-ioTypeScriptThis site and the Terraform that serves it — a static SPA on S3 + CloudFront, prerendered in both locales, with the decision library that records the load-bearing decisions and what each one cost. View on GitHub tedeuxx/tadeumendonca-skillsShellThe reusable dev-loop plugin: the principles layer, the agent personas, the permission guards. The half you can adopt with no cloud account at all. View on GitHub

The fork-to-live steps are in the READMEs, not on this page: this repo's has the cloud path end to end, from the domain to the first merge, and the plugin's has the loop half, which installs with no cloud account at all. And the bar a project has to clear to be listed in the portfolio here is public too, in docs/catalog-ready.md — the proof-of-engineering gate.

One thing I would copy without thinking twice. The deploy enters AWS over OIDC, so there is no stored secret: a leaked key is access until somebody revokes it, and a leaked token is access until it expires — and only if whoever took it can also satisfy the trust condition, which here is that repository's immutable subject, by numeric ID rather than by name, because a name can be transferred to someone else and the IDs cannot. The trade is that the root of that trust has to be created outside: Terraform here does not create the OIDC provider, nor the role that runs Terraform itself. It is a documented hole in a floor, and no plan will ever tell you it has drifted.

(→ ADR-0042 trust root outside Terraform · ADR-0015 immutable subject)

The part I would be nervous seeing someone copy without the rest is merging straight to production. Trunk-based with a single environment is fast and unforgiving in equal measure; without the gates in front of it, only the second half survives.

This is in the open because there are more configuration choices here than one person has sessions to run. If you have run any of those choices differently, you are the one holding the half this page is missing: tell me your counter-example, or share the page and say what you would change.