A developer's domain-driven manifest stops AI coding agents from guessing in legacy code

The author, whose post carries no byline (the Hacker News submission lists only the username "AlarQ", not a stated author), argues that AI coding agents work well on greenfield and small projects but drop sharply in quality once they hit "brownfield" code: legacy systems with heavy dependency trees, strong coupling and years of deferred tech debt. He illustrates the failure with a concrete example: ask an agent for a "job offer status" field in a fresh repository and it adds one cleanly; ask for the same field in a system that has been shipping for four years, and the model invents a fourth spelling of a concept the codebase already names three different ways, because the codebase itself never settled which spelling is authoritative. It writes an adapter where a direct call was fine, or calls straight through where an adapter was the whole point. His conclusion: the model is not what needs upgrading. The code is not ready, and readiness is something that can be built incrementally.

His fix starts by splitting tech-debt work along a cost line he says has never priced evenly. The usual industry practice, he writes, earmarks 10 to 20 percent of the technology budget for paying down tech debt, a plan that tends to stay theoretical ("In theory... In the next quarter..."). Of that budgeted fifth, deciding what should change and typing the change out have never cost the same: deciding has stayed about as expensive as ever, while typing has collapsed in cost now that an LLM can perform the mechanical half of a cleanup (an extracted module, a refactor across two packages, added test coverage) at prices that no longer resemble 2020. Borrowing terms from John Ousterhout's "A Philosophy of Software Design", while admitting he bends them, he calls the deciding half "strategic" work he still does himself (reading the system, working out what has to change and why, whether a change actually serves the feature) and the implementation half "tactical" work, now handed to LLM "skills" (markdown files of instructions the model loads when a task matches) and "sub-agents" (separate model sessions with their own fresh context and narrow job, reporting back a result instead of a full transcript). His own strategic analysis becomes GitHub issues; his agent system implements them into pull requests he reviews, watching test coverage and which other parts of the system consume whatever he is touching.

The strategic half runs on Domain-Driven Design, the approach he credits to Eric Evans for shrinking the communication gap between business and technical language. Every repository he owns carries a ".workflow.json" manifest at its root: a single declaration of which languages the repo holds, which directories an agent should read first, which checks must pass before work can ship, and, in one block, the repo's Domain-Driven Design bounded contexts, each context's subdomain type, where its glossary lives, and its edges to neighbouring contexts. That block is the only registration a repo needs; there is no second registry to fall out of sync. Beside the manifest sits a "CONTEXT.md" per bounded context, a living glossary of each term's precise meaning and the synonyms deliberately rejected. Nothing above these per-repo files is hand-authored: a generator walks every repository on disk, unions their domain blocks, and emits a single, disposable "CONTEXT-MAP.md" showing every context in the portfolio and every edge between them.

He walks through his own example, job-offer-box, a job-application tracker split across two repositories: a Rust backend kept under a project he calls hyperion, and a web frontend. The backend owns the product language, persisting terms like Job Offer, Profile, Profile Variant, Resume and Cover Letter, under a rule that whichever context holds the durable state owns the shared term. The frontend owns only its own screen vocabulary (View Model, Filter State, Facet Stats) and marks everything else "published", arriving as TypeScript generated straight from the backend's OpenAPI document. In the frontend's manifest, one edge declares four things: "to" (the context on the other end), "direction" (the web repo calls the backend, so outbound; the backend's own manifest declares the same edge inbound), "owner" (whose model wins on disagreement; here the backend's, so "supplier"), and "pattern" (the relationship itself, picked from a closed vocabulary; here "unclassified", because the frontend accepts the backend's shape as-is when writing and translates it into its own shape when reading, a nuance a single label could not capture).

The mechanism on top of this is what makes the manifests self-checking: every edge between two contexts is declared twice, once from each side, and a generator cross-checks the pair. Because a supplier states its own stance ("published-language") and a consumer states its own ("conformist" or "anticorruption-layer"), the check is a pairing table rather than a demand for identical labels. He runs this consistency check as a skill at three moments: after touching a manifest, when onboarding a new repository, and before changing anything another context depends on. Each mismatch it finds is filed automatically as a "DDD issue" on the repository that owns the wrong side, carrying a fingerprint (the kind of finding plus the two addresses) so a later run after a partial fix updates the same issue instead of opening a duplicate, and a mismatch that stops appearing closes its own issue. From there the issue follows his usual loop: an issue, an agent, a pull request, his review.

He is explicit that this only solves the boundary problem. The strategic layer, the shape of the context map, is already in place and settles where a context ends and how it talks to its neighbours, but the inside of any single context, he writes, is still ordinary code that will let you build a nonsense object and save it. Migrating each context in turn to a real domain model built from Domain-Driven Design primitives (value objects, aggregates, domain services) is his next, unfinished step. He gives no quantified figure for how much time or money the tactical, agent-run half actually saves, describing the gain only qualitatively ("the time is saved"), and says he plans to publish the whole system, skills included, soon.

Key facts

  • The author splits tech-debt work into a "strategic" half he still does himself (deciding what should change) and a "tactical" half now handed to LLM skills and sub-agents (typing the change into files), borrowing and knowingly bending John Ousterhout's terms from "A Philosophy of Software Design".
  • Every repository he owns carries a ".workflow.json" manifest declaring its Domain-Driven Design bounded contexts, their subdomain types, and their edges to neighbouring contexts; a "CONTEXT.md" per context holds the precise meaning of every term and the synonyms it deliberately rejects.
  • Each edge between two contexts is declared twice, once from each side, covering direction, ownership and integration pattern; a generator cross-checks the pair and automatically files any mismatch as a fingerprinted "DDD issue" so repeat runs update rather than duplicate it.
  • In his example project, job-offer-box (a Rust backend kept under a project called hyperion, plus a web frontend), the backend owns product terms like Job Offer and Profile because it holds the durable state, while the frontend owns only screen vocabulary and imports everything else as TypeScript generated from the backend's OpenAPI document.
  • He says this context-mapping layer is already working, but the inside of each bounded context is still ordinary code that will let you save a nonsense object; migrating each context to real Domain-Driven Design primitives is his next, unfinished step, and he plans to publish the whole system and its skills soon.

Why it matters

AI coding agents increasingly do the typing half of software work, but almost none of the code that actually needs changing at most companies is greenfield: it is old, coupled and full of debt. That mismatch produces a specific, well-known failure: agents guessing at names and boundaries a codebase never settled for itself. This post describes a concrete, personal attempt to close that gap without waiting for a smarter model. Instead of hoping an agent infers the system's structure correctly, the author writes the bounded contexts, their glossaries and their edges down in a form both people and models can read, then checks that writing for internal consistency automatically rather than trusting it to stay accurate by hand.

Who it affects

Software engineers and small teams who already run multiple repositories and are pushing AI coding agents into legacy systems, particularly anyone already using or open to Domain-Driven Design as a shared vocabulary between business and code. It is not aimed at greenfield projects, where the author says agents already perform well, and it assumes a workflow already built around per-repository manifests, skills and sub-agents rather than a single chat-based coding assistant.

How to use it

This is not a released product; it is the author's own practice, described in a blog post. He states that he will publish "the whole system, with the skills ready to use" shortly, which implies the generator, the skill definitions and the manifest schema are not yet public at the time of writing. A reader cannot install anything from this post today; the reusable part is the pattern itself: a per-repository ".workflow.json" declaring bounded contexts and their edges, a "CONTEXT.md" glossary per context, edges declared twice so a script can cross-check them, and mismatches filed automatically as fingerprinted issues.

How solid is it

The account is a single first-person blog post (70 points and 14 comments on Hacker News at the time of writing), not a peer-reviewed study or a vendor case study, and it describes one person's own system applied to his own repositories, illustrated by one example project, job-offer-box, that he also owns. No quantified savings figure, whether a percentage, a dollar amount or hours, appears anywhere in the post; the benefit is described only qualitatively, as "the time is saved". The deeper claim, that migrating each bounded context to real Domain-Driven Design primitives will fix the code inside the boundaries, is presented as his next step rather than something already done and measured.

Risks and caveats

Everything here is self-reported and untested by anyone but its author: there is no outside adoption, benchmark or before-and-after comparison to check the claimed benefit against. The approach is tied to a specific personal toolchain (a JSON manifest schema, markdown skills, TypeScript generated from an OpenAPI document), so how well it transfers to other stacks, larger teams or codebases the author does not fully control is untested by anything in the post. The author is also explicit that the technique addresses only the boundary between contexts; the code inside each bounded context, by his own account, is still ordinary code that will let you build and save a nonsense object, so the harder migration work remains ahead of him, not behind him. No name is given for the author anywhere in the article itself, only the Hacker News submission's username, "AlarQ", which is not stated as a byline.

“The model is not what needs upgrading.”

— the blog post's author