AGENTIC ENGINEERING · TOOLS AND WORKFLOW

Agentic engineering

I lead our agency in adopting agentic engineering workflows to increase our velocity - enough that our release cadence has gone from fortnightly to twice weekly. We review the newest tools and update our workflows monthly. It's a lot of fun to tweak our AI tooling and get features shipped as fast as we can think of them.

We put a lot of effort into the scaffolding and guardrails for our AI. Below I'll go into detail about how I currently deliver new features and new project prototypes rapidly.

THE PIPELINE · SAME SHAPE ON EVERY REPO

How a feature ships

Every new feature travels the same route. Small features or tweaks can skip the spec step and jump straight into planning with the agent.

  1. 01SpecScope, examples, and acceptance checks in a markdown file the agent reads first.
  2. 02PlanUsing Lavish, the agent creates a detailed plan for how it will add the feature, and presents it as an annotatable page file in browser
  3. 03BuildOnce the plan is accepted, one orchestration agent runs with subagents, in its own worktree. It implements the full feature, tests included.
  4. 04GatesTypecheck, linting, integration tests or e2e tests at multiple viewports. Each step provides feedback to the agent so it can self-correct
  5. 05no-mistakesIn depth automated review step. The agent flags any long term maintainability issues, re-runs tests and proposes fixes or improvements.
  6. 06Human reviewWe look through the files that were changed, smoke test locally if needed, and modify the spec file if anything needs changing, then raise a PR with another tool call
FIG 01 · FEATURE PIPELINESPEC → SHIP

BACKEND · FASTAPI · POSTGRES

Backend: guardrails to stay on track

Backend agents get the strictest scaffolding, because backend mistakes are the quiet ones. The repo's CLAUDE.md is a real onboarding document: architecture map, module conventions, the exact CI commands, and a list of project-specific pitfalls with worked wrong-and-right code examples, so the agent doesn't rediscover them the hard way. We use a makefile with all the common commands the agent needs, which greatly increases the reproducability of agents.

Linting an agent can't argue with

One command, make lint-all, runs four layers: a formatter, a linter, a type checker, and a custom linter we keep for rules no off-the-shelf tool checks. The custom rules are small and evaluate in milliseconds, for example every route handler must be async, no print statements in endpoints, and every model column's type annotation must agree with its nullability. A post-edit hook also auto-formats every file the agent touches the moment it writes it, so unformatted code never even reaches a commit. This keeps code looking consistent across the codebase.

Modularity the agent can navigate

Every entity in the project is a module with the same fixed file layout: model.py, schemas.py,endpoints.py, factory.py,utils.py, and its tests. Each module also carries afeature_definition.md - a living spec of the business rules the agent must read before touching the module and update after. Predictable structure is what makes agents fast: they always know where things go.

Integration tests, given-when-then

Tests run against a real Postgres database, not mocks - factories build the object graph, external services are stubbed centrally, and every test reads as given, when, then. The style is mandated in the repo's style guide, so the agent writes tests we can skim in seconds:

TEST_ENDPOINTS.PY · TIME ENTRY MODULEPYTEST · REAL POSTGRES
async def test_get_time_entries_for_task_success(
    async_client: CustomTestClient,
):
    # Given we have an admin user with a business
    user_business = await admin_user_with_business()

    # Given we have a task with 3 time entries
    task, _ = await _create_task_with_time_entries(
        user_business.business, 3
    )

    # When we request time entries for this task
    response = await async_client.api(
        f"/time-entry/task/{task.id}",
        expected=200,
        token=user_business.token,
    )

    # Then we should get back all 3 time entries
    assert len(response) == 3

FRONTEND · REACT · TAILWIND V4 · PLAYWRIGHT

Frontend: the agent looks at what it built

Frontend needs different guardrails, because the failure mode is different: a page can pass every test and still look wrong. The stack is chosen for agents as much as for users: Tailwind utility classes keep every style decision in the markup where the agent can see it, design tokens are the only allowed colours, and Zod validates every API boundary against a generated contract. Of course we also use typescript and enforce linting, on the frontend, but that doesn't catch as many errors as proper e2e testing.

E2E tests the agent runs on itself

Every screen has Playwright coverage at two viewports - desktop and iPhone - and both must pass before any task is done. The suite runs against deterministic mock fixtures rather than a live backend, so a red test always means the frontend broke. Each parallel agent worktree grabs its own free port and boots its own dev server, so several agents can run e2e at once without stepping on each other.

Screenshots are a gate

This rule makes agents excellent at design too: tests passing is not sufficient - the screenshots must look right. After any UI change the agent captures full-page screenshots of every touched screen at both viewports, opens them, and fixes overflow, cramped tap targets, and broken alignment before it may call the work done. This one practice catches more real bugs than any lint rule I've written.

One contract, two repos

The two repos share a single source of truth for the API. Whenever the backend changes, it exports its full API docs to a file the frontend repo keeps a copy of - so the frontend agent always builds against the exact endpoints and shapes the backend actually serves, with Zod checking them at runtime:

  1. 01BACKEND REPO · FASTAPIThe endpoint landsWhenever the API changes, the agent runs one make target that regenerates the docs straight from the live FastAPI code.
  2. 02GENERATED CONTRACTbackend-docs.toonThe full OpenAPI spec in TOON, a token-efficient format - compact enough for an agent to read the whole API in one sitting. Never hand-edited.
  3. 03FRONTEND REPO · ZODSchemas validate every boundaryThe frontend agent writes Zod schemas, query hooks, and mock fixtures against the fresh contract. Any drift fails loudly at runtime, not quietly in the UI.
FIG 02 · API CONTRACT PIPELINEBACKEND → ZOD

The generated contract file is the load-bearing idea: backend and frontend never guess at each other. The frontend is always built against what the backend actually serves, regenerated the moment the endpoint lands.

THE TOOLKIT · 14 ENTRIES · CHANGES MONTHLY

The toolkit

Everything above runs on this set of tools.

SKILLS · WRITTEN AND MAINTAINED MYSELF

SKILLbitbucket-prPushes the branch and writes the PR description from the session's own context - the agent explains its own work.
SKILLend-of-dayReads the day's commits across every repo and provides dot points of everything achieved that day so nothing is forgotten.

TOOLS

TOOLClaude CodeDaily driver. Our choice of LLM provider due to its frontier coding skills
TOOLherdrAgent multiplexer in the terminal - every agent at a glance, blocked, working or done. Detach and they keep running; it notifies when one needs help.
TOOLllmtrimLocal proxy that trims wasted tokens from prompts, history, and tool output before they reach the API - same answers, noticeably smaller bill.
TOOLlavish-axiPlans become HTML artifacts I can annotate and send back before any code gets written.
TOOLno-mistakesA validation pipeline: automated review, tests, lint, docs, PR, CI. Nothing reaches develop without clearing it.
TOOLcaveman-commitCommit messages with the noise cut out. Subject under 50 characters, body only when the why isn't obvious.

PRACTICES

PRACTICESpec writingHalf the work is the spec the agent builds from - tight scope, examples, acceptance checks.
PRACTICECLAUDE.md per repoEvery repo teaches the agent its own conventions, pitfalls, and hard rules. The doc is the onboarding.
PRACTICESubagentsSonnet explores, Haiku runs the lint, Opus writes the code. The main thread keeps its context for the real work.
PRACTICEHooksA post-edit hook auto-formats every file the agent touches. Guardrails that run themselves.
PRACTICEGates with feedbackTypecheck, tests, and lint all feed their errors straight back to the agent, so it self-corrects instead of waiting on a human.
PRACTICECustom lint rulesHand-rolled rules encode our conventions and say exactly what to fix - problems get caught before a human ever sees the diff.