{"slug": "real-engineers-dig-with-their-bare-hands", "title": "Real Engineers Dig with Their Bare Hands", "summary": "In a July 14, 2026 essay, software engineer Meerita argues that using AI agents for repetitive coding tasks is not 'vibe coding' and does not outsource understanding, emphasizing that engineers retain responsibility for correctness and architecture. He provides a Git repository with rules for AI-assisted development and compares AI agents to past tools like syntax highlighting and CI/CD pipelines that automated manual rituals without eliminating the need for engineering knowledge.", "body_md": "July 14, 2026\n\n# Real Engineers Dig With Their Bare Hands\n\nYes, Father, I have sinned. I let a machine write the boring parts. No, I am not vibe coding. There is a difference, and the difference is two weeks of rules, a clear architecture, automated checks, and knowing exactly when to take the shovel back.\n\nTwo neighbors stop in front of a construction site and look through the fence. Inside, five workers are using two enormous machines to finish digging a massive hole. One neighbor shakes his head.\n\n“Fifty people could have dug that with shovels. Everyone would have had a job.”The other looks at him and says,“Why stop at fifty? A thousand people could have dug it with their bare hands.”\n\nMy [previous essay about working with AI](https://www.minid.net/2026/7/10/ai-works-for-me) generated a longer discussion than I expected on HN, and some people complained that I did not give any specific details about how I work. So, in this essay, I want to explain what I have actually automated in my engineering workflow. This includes [access to a Git repository with all the rules I typically use](https://github.com/meerita/monorepo-nextjs-golang-rust-python-ai-rules) in a large project.\n\nBefore getting into the practical part, though, I need to address the predictable objections:\n\nYou are vibe coding.\n\nYou are AI-pilled.\n\nYou will eventually forget how software works.\n\nThese objections argue against a point *I am not making.*\n\nI am *not* saying that learning how things work under the hood is a waste of time. *Quite the opposite.* That knowledge is precisely what allows me to automate safely, inspect the result, and recognize when an agent has done something stupid. **Delegating grunt work is not the same as delegating judgment.** Running formatters, checking architectural boundaries, finding empty files, detecting unused dependencies, and preparing a migration plan are mostly mechanical tasks. Determining whether the generated code is correct, whether the abstraction makes sense, whether the architecture is appropriate, and whether the system should exist in the first place still requires an engineer.\n\nThe machine does not assume responsibility. *I do.*\n\nWhen I was younger, I uploaded files manually through FTP and SSH. I edited code in text editors with no syntax highlighting, no autocomplete, no inline warnings, and no useful feedback until compilation failed. Sometimes the feedback arrived even later, when the system broke in production. Great times. Very character-building. To reduce human error (or at least give it fewer opportunities to express itself), I remember using Teleport Pro and WinHTTrack to crawl our applications and find broken links. Then text editors acquired syntax highlighting, which felt almost unfair. IDEs started warning us before compilation. Autocomplete became normal. Suddenly, the computer was helping instead of silently watching us make mistakes.\n\nI replaced repeated uploads with `rsync`\n\n, wrote shell scripts, and eventually adopted version control, automated tests, CI/CD pipelines, infrastructure as code, dependency bots, static analysis, and increasingly sophisticated deployment systems. Each new tool eliminated another task that developers had previously considered a sacred manual ritual. None of those tools made knowledge about servers, networking, permissions, failures, or rollbacks unnecessary. They simply removed repetitive execution, caught mistakes earlier, and reduced the number of Friday evenings spent discovering that someone had uploaded the wrong folder to production.\n\nAI agents feel like the next step in the same progression.\n\n**I am not outsourcing understanding.** I am automating execution and catching errors closer to where they are introduced and writing boilerplate code. In any case, engineers still need to decide whether the code is correct, the abstraction makes sense, the architecture fits, and the system should exist at all. Heck, even Linus Torvalds [reaffirms that Linux is not anti-AI](https://www.phoronix.com/news/Linux-Is-Not-Anti-AI). We have used graphical Git clients, IDE refactoring tools, and autocomplete for years without declaring that engineering is dead because someone clicked a button. But as my grandfather said to me multiple times, *“convenience always wins over nostalgia”*, especially when it also prevents mistakes.\n\nWorking with an agent is not fundamentally different from using another high-level interface over a complicated system. It is a new kind of GUI, although sometimes it is closer to a NOGUI because the interaction happens through language rather than menus. **The interface is more powerful, but the principle is familiar.** You describe the intended result. The tool performs a collection of lower-level operations, write boilerplate code for you. You inspect what it did. You approve, reject, or correct the result. The important difference is that agents can operate across a much larger surface area. They can read a repository, follow instructions, modify several components, run tests, inspect failures, and iterate. *That does not make them infallible.* It makes good instructions and verification much more important.\n\nWe are also past the stage where agents only generate tiny CRUD applications for demos. Anthropic recently described an experiment in which [16 parallel agents produced a Rust-based C compiler from scratch](https://www.anthropic.com/news/claude-2-code-compiler). Over almost 2,000 Claude Code sessions, the agents generated roughly 100,000 lines of code and reached the point where the compiler could build Linux 6.9 for x86, ARM, and RISC-V. That’s impressive. Bun has also undergone [a large migration from Zig to Rust](https://bun.com/blog/bun-in-rust), with its current repository instructions describing the project as primarily written in Rust with just one engineer. Microsoft [is applying agents to codebase-wide refactoring](https://devblogs.microsoft.com/cppblog/perform-wide-sweeping-refactors-using-c-code-editing-tools-for-github-copilot/), framework migrations, tests, modernization, and work across large repositories. Its own developer material explicitly presents agent mode as capable of changing multiple files and migrating legacy code to modern frameworks. Microsoft engineers are also working in increasingly common hybrid C++ and Rust codebases.\n\nThese examples do not prove that agents can autonomously replace an engineering organization. They prove something less dramatic and more useful: agents can already perform substantial work on real codebases when experienced people provide direction, constraints, and verification. Programming was moving toward higher-level composition long before “vibe coding” became a phrase. Engineers have spent decades installing, configuring, and combining software written by other people without reading every line of its source. The relevant question is whether you understand the abstractions you depend on, the decisions you are making, and the failure modes you are accepting. The same standard should apply to agents.\n\nAgents do not automatically produce vibe-coded software. People produce vibe-coded software when they accept systems they do not understand. You can create a mess by copying code from Stack Overflow, following a tutorial, installing the wrong framework, hiring an incompetent consultancy, or giving an AI agent unrestricted access to a repository. The agent is not the defining feature. The absence of engineering judgment is.\n\nReal vibe coding happens when someone cannot explain:\n\n- Why the architecture has its current shape.\n- Why a dependency was introduced.\n- Where business rules live.\n- How transactions are handled.\n- Which components are allowed to communicate.\n- What happens when an external service fails.\n- How data moves through the system.\n- How to test, deploy, observe, or recover it.\n- How to modify the software without asking the machine to rediscover everything.\n\n**That is a dangerous position, regardless of how the code was produced.** Using agents responsibly means retaining ownership of the decisions while delegating parts of the execution. *You still write code.* Often you write quite a lot of it, because agents are imperfect and some tasks are easier to start or finish by hand. Sometimes I implement the core idea myself and use agents to propagate it through the system. Sometimes the agent builds the first version and I replace the parts I dislike. Sometimes it only investigates the repository and gives me an executable plan. The relationship is not “the agent codes and I watch.” It is closer to directing several extremely fast junior engineers who have read half the internet, never get tired, occasionally misunderstand obvious instructions, and remain capable of confidently constructing something absurd.\n\nThe most important part of my setup *is not a clever prompt.* It is the collection of rules that defines how agents are allowed to work inside a project. I do not rely exclusively on a giant `AGENTS.md`\n\nfile. Instead, I keep a small index and a structured `.agents/`\n\ndirectory containing focused rules.\n\nA simplified version looks like this:\n\n```\nAGENTS.md\n.agents/\n  rules/\n    00-agent-behavior.md\n    01-project-boundaries.md\n    02-git-and-branching.md\n    03-surfacing-gaps-and-incomplete-work.md\n    04-file-headers-and-comments.md\n    05-security.md\n    10-naming-files-and-folders.md\n    11-constants-and-enums.md\n    12-abstractions.md\n    14-code-naming.md\n    15-control-flow-and-nesting.md\n    16-conditional-logic.md\n    ...\n```\n\n`AGENTS.md`\n\nacts as the index. It tells the agent which rules exist, what they cover, and when they should be loaded. It matters because a single enormous instruction file is not necessarily better. Agents have finite context, and wasting that context on irrelevant rules leaves less room for the repository, the task, and the actual implementation. An agent working on a domain object does not always need the complete PostgreSQL migration policy. An agent updating Docker configuration does not need every frontend naming rule. **The system should load the relevant constraints for the work being performed.**\n\n**Rules must be short enough to remain usable and specific** enough to influence behavior. Writing a book for every rule defeats the purpose. The agent will spend its context reading your constitution and have no space left to govern the country.\n\n[You can see an example](https://github.com/meerita/monorepo-nextjs-golang-rust-python-ai-rules) of a monorepo with several rules and skills I normally use.\n\nBefore defining language conventions or architecture, I define how I want agents to work with me (the `01-agent-behavior.md`\n\nfile defines this). This is the universal behavior layer.\n\nIt covers things such as:\n\n- Read the relevant documentation and project rules before changing code. (Yeah, that obvious)\n- Do not silently invent requirements.\n- Surface missing information and incomplete work.\n- Explain uncertainty instead of hiding it.\n- Do not change unrelated files.\n- Do not install dependencies without approval.\n- Do not weaken tests to make a build pass.\n- Do not suppress errors that should be fixed.\n- Show an implementation plan before large changes.\n- Communicate with me in Spanish, but write code and technical identifiers in English.\n- Keep explanations direct and reasonably short.\n- Stop at destructive or irreversible operations.\n- Ask for approval before deleting or replacing significant components.\n\nThese instructions may sound obvious to you, but they are not obvious to an agent. Agents are optimized to complete tasks. Without boundaries, they may choose the shortest path to a green test suite, even when that path involves changing the test, bypassing the architecture, adding an unnecessary package, swallowing an error, or quietly narrowing the original requirement. **A useful rule does not merely describe the desired outcome. It also defines unacceptable shortcuts.**\n\n**You should not blindly copy another person’s rules and assume your project is now safe.** **Rules encode judgment.** A respected Go engineer may publish an excellent set of conventions, but those conventions reflect that engineer’s experience, preferences, architecture, and operational environment. More on this one, **every LLM will execute rules differently,** based on context window power, trainning, etc. Your set of rules may not perform equally if you are using Opus 4.8 than Gemini 2.5. Copying them can produce good-looking code while leaving you unable to explain why the system works that way. That is only a slightly more sophisticated version of vibe coding.\n\nYou can use other people’s rules as examples. You can adopt rules you understand and agree with. What you should not do is outsource the criteria by which your own system will be judged. Your `.agents/`\n\ndirectory should contain your knowledge, your team’s decisions, and your project’s constraints. If you do not understand the platform, the architecture, the infrastructure, and the trade-offs behind those rules, the agent cannot rescue you. It can only make your confusion much more productive.\n\nAfter the behavioral rules, I define language-agnostic system rules. These cover subjects that should remain consistent regardless of whether the implementation uses Go, Rust, Java, Swift, Kotlin, TypeScript, or something else:\n\n- File and folder naming.\n- Code naming.\n- Constants and enumerations.\n- Abstraction boundaries.\n- Control flow and nesting.\n- Conditional logic.\n- Identifier generation.\n- Comments and file headers.\n- Git and branching.\n- Security boundaries.\n- Dependency approval.\n- Transaction behavior.\n- Migration safety.\n- How gaps and incomplete work must be reported.\n- How executable plans should be written.\n- What information may be sent to an external language model.\n\nThis creates a stable base before adding rules for individual applications and layers.\n\nFor a monorepo, [I separate universal rules from application-specific ones](https://github.com/meerita/monorepo-nextjs-golang-rust-python-ai-rules). A project containing a Next.js frontend, iOS and Android applications, a Go service, and a Rust service cannot be governed effectively by one undifferentiated instruction file. The repository should make it clear which rules apply everywhere and which belong to a particular application, language, or architectural layer.\n\n```\nmonorepo/\n├── AGENTS.md                              # Root index — entry point for all agents\n├── CLAUDE.md                              # Claude Code pointer to AGENTS.md\n├── .agents/\n│   └── rules/                             # Universal rules (apply to every layer)\n│       ├── 00-agent-behavior.md\n│       ├── 01-project-boundaries.md\n│       ├── 02-git-and-branching.md\n│       ├── 03-surfacing-gaps-and-incomplete-work.md\n│       ├── 04-file-headers-and-comments.md\n│       ├── 05-security.md\n│       ├── 10-naming-files-and-folders.md\n│       ├── 11-constants-and-enums.md\n│       ├── 12-abstractions.md\n│       ├── 14-code-naming.md\n│       ├── 15-control-flow-and-nesting.md\n│       ├── 16-conditional-logic.md\n│       ├── 18-identifiers-and-uuidv7.md\n│       ├── 19-llm-data-boundary-and-code-egress.md\n│       ├── 20-persistence-and-postgresql.md\n│       ├── 21-query-services.md\n│       ├── 22-transactions.md\n│       ├── 23-migrations.md\n│       ├── 24-security-and-compliance.md\n│       ├── 25-executable-plans.md\n│       └── 26-dependency-audit.md\n├── .claude/\n│   └── skills/                            # Executable Claude Code skills\n│       ├── definition-of-done/\n│       ├── plan-authoring/\n│       ├── pr-check-release/\n│       ├── pr-merge-dev/\n│       └── release-check/\n├── apps/\n│   ├── web/                               # Next.js (Bun workspace)\n│   │   └── .agents/rules/                 # Web-specific rules\n│   ├── mobile-ios/                        # Swift / SwiftUI\n│   │   └── .agents/rules/\n│   └── mobile-android/                    # Kotlin / Compose\n│       └── .agents/rules/\n├── services/\n│   ├── api/                               # Go modular monolith + MCP server\n│   │   └── .agents/rules/\n│   ├── identity/                          # Rust auth service\n│   │   └── .agents/rules/\n│   └── ai/                               # Python AI layer (MCP client)\n│       └── .agents/rules/\n├── docker/                                # Local backing infrastructure\n│   └── .agents/rules/\n├── docs/                                  # Architecture, product, process docs\n└── tools/                                 # Local developer tooling\n```\n\nThis structure also makes rules easier to review. A change to the persistence policy does not require editing a massive document containing frontend conventions, security requirements, and Git instructions.\n\nOnce the universal rules exist, I define the exact stack agents are allowed to use. This is more important than it sounds. Agents want to complete the task, and in the absence of constraints they will happily:\n\n- Install a library you never approved, preferably a version old enough to have its own archaeology department.\n- Use a language feature that has been obsolete for years.\n- Target the wrong runtime.\n- Add a second package that solves a problem the first package already solved.\n- Copy an implementation written for a different framework version.\n- Mix patterns from incompatible generations of the same platform.\n- Replace a perfectly good standard-library feature with another dependency because that solution appeared more often in the training data.\n- Repeat an insane amount of code that can be abstracted.\n\nI have reviewed systems where different modules were effectively targeting different Java versions even though Java 21 was the approved standard. I have also seen Go code written in an older style while the project was already using a newer release with simpler and better-supported alternatives. The opposite problem is even worse: without an explicit stack policy, an agent may assume the wrong language, runtime, framework, or dependency version, generate a large amount of code, and only discover at compile time that the APIs it selected are unavailable or incompatible with the actual project.\n\nThen, while the agent is still struggling to finish the task, the cheerful message arrives:\n\nI see you are using an older version than expected. I will now update my implementation.\n\n*Excellent.* Another mountain of tokens spent undoing work that should never have started.\n\nThe opposite happens too. I once had an agent generate a Zod schema using the Zod 3 style while the project was already on Zod 4. The code still worked, but it ignored the newer, preferred API. Nothing was technically broken. It was simply outdated on arrival.\n\nThe stack rules should define, at a minimum:\n\n- Approved language and runtime versions.\n- Approved frameworks.\n- Existing libraries that should be preferred.\n- Dependencies that are forbidden or require explicit approval.\n- Testing frameworks.\n- Formatting and linting tools.\n- Build and validation commands.\n- Deployment targets and runtime environments.\n- Compatibility requirements.\n- Whether experimental or unstable APIs are allowed.\n\nDo not make the agent infer these details from whichever files it happens to read first.\n\nThe next rule set defines the system architecture. This is not where I want the agent to express itself. **I want decisions.**\n\nIs the system a monolith, a modular monolith, a set of microservices, a serverless application, a library, a command-line tool, or something else?\n\nWhere do business rules live?\n\nWhich direction may dependencies point?\n\nHow do applications communicate?\n\nWhich layer owns persistence?\n\nWhich parts of the system are allowed to know about the framework?\n\n**These questions must be answered before implementation begins.** Otherwise, the agent may gradually produce something that is not a monolith, not a service architecture, and not anything else you could explain without drawing arrows for forty minutes.\n\nDuring due diligence, I have met teams that believed they had built microservices when they had actually built a distributed monolith. They gained the deployment complexity of microservices while preserving the coupling of a monolith. *A magnificent combination.*\n\nArchitecture is not an aesthetic preference. It affects infrastructure costs, deployment complexity, observability, scalability, failure modes, staffing, and the speed at which the product can change. Many teams choose architectures because large technology companies use them. They copy the visible shape without inheriting the scale, constraints, operational maturity, or budget that made the original decision reasonable.\n\n**An agent will happily accelerate that mistake.**\n\nFor many backend projects, [I use Robert C. Martin’s Clean Architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html). You do not have to. Choose an architecture that fits the system you are building. A library, a microfrontend, a mobile application, a compiler, and a REST API do not necessarily need the same shape. What matters is making the decision explicit.\n\nFor Clean Architecture projects, I define rules for:\n\n- Dependency direction.\n- Domain isolation.\n- Use cases and application services.\n- Interfaces and adapters.\n- Infrastructure boundaries.\n- Data mapping.\n- Framework isolation.\n- Error handling.\n- Transaction ownership.\n- Testing responsibilities.\n- Allowed imports between layers.\n\nThese rules prevent small violations from accumulating. The agent should not import a framework into the domain layer. It should not place business decisions in a PostgreSQL trigger. It should not spread the same validation logic across the controller, database, and domain model. It should not make the application layer depend on an infrastructure implementation because that happened to be convenient. Humans introduce these problems too. The difference is that an agent can introduce them across fifty files before lunch. Consistency is one of the greatest benefits of agent-assisted work, but *only* when you define what consistency means.\n\nThe rules are not only for agents. I am human, which means I am also capable of rushing, overlooking files, forgetting conventions, and convincing myself that a questionable exception is perfectly reasonable because I would like to finish for the day. I do not trust that little bastard either.\n\nWhen I think a task is finished, I run the `/definition-of-done`\n\nskill. It reviews the work against the project rules and executes the relevant automated checks.\n\nThink of it as everything you should verify before running git push and making your teammates deal with whatever you forgot.\n\nDepending on the repository, it may:\n\n- Run unit, integration, and architectural tests.\n- Apply formatters.\n- Run linters and static analysis.\n- Check dependency boundaries.\n- Search for empty or abandoned files.\n- Detect unused dependencies.\n- Inspect unresolved markers and temporary code.\n- Check migration consistency.\n- Verify that generated artifacts are current.\n- Confirm that the working tree is clean.\n- Check whether all expected files are tracked.\n- Compare the result against the original plan.\n- Report incomplete requirements.\n\nMost of these checks are performed by the agent using tooling I wrote, which is included in the example repository. The agent also verifies that the implementation covers the approved plan rather than merely compiling.\n\nFor example, teams sometimes create files during implementation and accidentally leave them empty or abandoned. My checks detect those files, determine whether anything references them, and report why they may exist. Once the finding is reviewed, the agent can remove them.\n\nGo catches unused local variables and imports at compile time, but it does not detect every abandoned declaration, exported symbol, dead path, or forgotten file. Other ecosystems may provide even less protection unless stricter compiler and linting rules are explicitly enabled. As a result, empty files, unused exports, abandoned modules, and obsolete code paths can remain in a repository indefinitely. Without regular maintenance, repositories become cemeteries of previous intentions.\n\nThe Definition of Done prevents “the code compiles” from becoming the definition of completion.\n\nDatabase rules deserve their own section because agents can cause spectacular damage in the persistence layer.\n\nYes, [PostgreSQL can do almost everything](https://postgresisenough.dev). That does not mean every workload belongs in PostgreSQL. You still need to choose the right storage system for the problem and define how each database is allowed to participate in the architecture.\n\nIn Clean Architecture projects, and in many other architectural styles, I often see business rules gradually pushed into PostgreSQL because it is convenient. UUIDs are generated in one place, calculations happen in another, validation is duplicated in the application, and eventually nobody can explain which layer owns the truth.\n\nAgents are particularly vulnerable to this temptation because database features often provide fast ways to satisfy a requirement. If a task says, “Ensure this value is always updated,” a trigger may look like a successful solution. But if the architecture says business behavior belongs in the domain or application layer, that trigger may be technically effective and architecturally wrong.\n\nPersistence rules should define:\n\n- Which databases are approved.\n- Which layer owns database access.\n- How repositories are structured.\n- Where identifiers are generated.\n- Where business calculations may occur.\n- Whether triggers and stored procedures are allowed.\n- How transactions begin and end.\n- How migrations are written and reviewed.\n- How destructive migrations are handled.\n- How queries are organized.\n- How pagination and locking work.\n- How retries and idempotency are implemented.\n- How database-specific types are kept out of the domain.\n- Which operations require explicit human approval.\n\nThe goal is not to ban every advanced database feature. It is to ensure those features are used deliberately, not simply because the agent found them convenient.\n\nOnce the rules and skills are in place, the first thing I do is write detailed plans and functional specifications. I spend quite a lot of time defining what we are going to build together with my team. For this, I keep a separate `docs/product/`\n\nfolder in the repository, where we document the functional specifications and implementation plans for each feature. I used to write these documents in Confluence and, later, in Slite. Over the years, I got tired of keeping this information somewhere else, so now everything lives in the repository. I do not use product specifications as giant prompts. I use them to think through the product, make decisions, and guide its execution.\n\nThe agent and I execute the plan together. With my guidance, it helps turn my decisions into a detailed, executable plan. The process is somewhat similar to [Matt Pocock’s /grill-me skill](https://www.aihero.dev/skills-grill-me), but with a narrower objective: producing an agent-readable plan that can be implemented without constantly rediscovering context. The agent divides the full plan into meaningful phases. This lets me make better use of its context window instead of having to compress the conversation every twenty minutes and hoping that none of the important decisions disappear in the process.\n\n```\ndocs/\n  ├── README.md\n  ├── api/\n  │   └── README.md\n  ├── architecture/\n  │   ├── 01-stack-definition.md\n  │   ├── 02-local-development-environment.md\n      ...\n  │   └── README.md\n  ├── plans/\n  │   ├── 02-ci-security-scanning.md\n  │   ├── 03-ai-ocr-governance.md\n  │   ├── 04-ocr-llm-resilience-and-fallback.md\n      ...\n  │   └── README.md\n  ├── product/\n  │   ├── README.md\n  │   ├── lender-portal/\n  │   │   ├── 01-overview-and-scope.md\n  │   │   ├── 02-personas-and-roles.md\n          ...\n  │   │   └── README.md\n  │   └── sow-msa-redline-response-matrix.md\n  └── software-architecture/\n      └── README.md\n```\n\nSo, what `/plan-authoring`\n\nactually does? In short, this skill turns my messy high-level plans into an executable, phased plan that an agent can run without me babysitting it. But it refuses to write a single line of the plan until it has done its homework and interrogated me first.\n\nIt runs in four stages, and it will not let me skip ahead no matter how much I beg:\n\n**Gather context.** It reads the repo, AGENTS.md, the rules, the architecture docs, and whatever high-level plans the work relates to. It is explicitly forbidden from inventing files, commands, or decisions that don’t exist, which, if you have used agents for a while, you know is a real feature and not a given.**Debate with me.** This is the part I actually care about. It surfaces ambiguities, contradictions, and trade-offs and forces me to make decisions instead of hand-waving. Planning is a conversation, not a transcription.[Think of it as /grill-me energy](https://www.aihero.dev/skills-grill-me), but pointed at producing a plan.**Confirmation gate.** It will not write the definitive plan until I explicitly confirm the context is enough, the decisions are made, and the scope is clear. It is a gate, not a formality, and yes it asks.**Write the plan.** Only now does it copy a template and fill it in with everything we settled.\n\nThe output comes in two flavors. A Focused Plan is a single file for a bounded change. A Master Plan is a whole directory for the big scary stuff: a `00-bootstrap.md`\n\nentry point, a `01-master-plan.md`\n\nwith the objective, scope, decisions already made, and a global checklist, plus one self-sufficient file per phase.\n\nThe clever bit, and the reason it solves my context-window problem, is that every phase is designed to run in a fresh chat with zero conversation memory. Each phase file carries its own objective, preconditions, ordered steps, a persistent checklist as the single source of truth for progress, and a ready-to-paste executable prompt. Phases are ordered inner-to-outer following Clean Architecture, so nothing gets wired up before the thing it depends on exists.\n\nThe whole philosophy is one line from the skill itself: creativity belongs to the planning phase, not the execution phase. All the thinking, arguing, and deciding happens up front with me. By the time an agent picks up a phase, there is nothing left to improvise. It implements, it does not re-investigate. Open a fresh chat, paste the bootstrap, and let it work one phase at a time without compressing context every twenty minutes.\n\nOnce I execute `/plan-authoring`\n\n, the high-level plans become the executable plan:\n\n```\ndocs/plans/\n├── README.md                              # the only committed file; the rest is gitignored\n├── 07-team-billing-and-seats.md           # my messy high-level plan (the input)\n│\n└── team-billing-and-seats/                # the Master Plan the skill authored (the output)\n    ├── 00-bootstrap.md                    # paste this into a fresh chat to start or resume\n    ├── 01-master-plan.md                  # objective, scope, out of scope, decisions made,\n    │                                      # phase index + global checklist\n    └── phases/\n        ├── 00-baseline-audit.md           # what exists today, what we are allowed to touch\n        ├── 01-billing-domain.md           # value objects, enums, domain errors, invariants\n        ├── 02-subscription-aggregate.md   # Subscription + Seat entities, policies\n        ├── 03-ports-and-use-cases.md      # ports, application DTOs, use cases\n        ├── 04-stripe-adapter.md           # payment provider adapter behind the port\n        ├── 05-persistence.md              # repositories, migrations, no N+1 by design\n        ├── 06-seat-assignment-api.md      # transport layer, authz, tenant isolation\n        ├── 07-webhooks-and-dunning.md     # invoice.paid / payment_failed handling\n        ├── 08-admin-ui.md                 # seats, plan changes, billing history screen\n        └── 09-release-hardening.md        # e2e, security review, quality gates green\n```\n\nA few things worth pointing out, because the tree hides the interesting part.\n\nThat `07-team-billing-and-seats.md`\n\nsitting at the top is my brain dump, and it looks exactly as ugly as that sounds. It’s blockers I ran into, quotes pasted straight out of Slack threads, half-formed requirements that made sense at 11pm, and a pile of dos and don’ts in no particular order. It is not a plan. It’s the raw material for one. The skill reads all of it, then does the thing I actually pay it for: it argues with me. It pushes back on the contradictions, makes me commit to the decisions I was avoiding, and only once we’ve settled everything does it produce the neat folder sitting right next to my mess. The brain dump stays. The plan is what gets built from it.\n\nEvery file inside `phases/`\n\nis self-sufficient, and this is not a nice-to-have, it’s the whole trick. A fresh agent can open any one of them, read its checklist, and execute it without knowing the other eleven phases exist. No conversation history, no “as we discussed earlier,” no context that quietly evaporated three compactions ago. Each phase carries everything it needs to be run cold. That’s what lets me run one phase per chat and never watch the context window fill up with things the agent already forgot.\n\n**The phase numbers are not decoration either.** They go inner-to-outer following Clean Architecture, which means nothing gets wired up before the thing it depends on actually exists. If you don’t do it this way, multiple errors will occur and your phases will never be done. The agents will “patch their way out” of the dependency hell. Domain first, because everything stands on it. The Stripe adapter comes later, once there’s a port for it to plug into. The UI comes last, because building the screen before the billing logic is how you end up with a very pretty form that submits into the void. The ordering is the plan doing my thinking for me so I don’t have to relearn it every time.\n\nAnd the whole folder is gitignored except `README.md`\n\n. On purpose. These plans are local working artifacts, not source code, and I don’t want them cluttering history or turning into merge conflicts nobody asked for. Continuity between agents doesn’t come from git. It comes from the checklists living inside these files. An agent finishes a phase, ticks the boxes, and the next agent reads those same boxes to know exactly where things stand. The state travels in the files, not in the commits. Which, if you were paying attention, is exactly the point.\n\n**Once the plan is written, the fun begins.** I open a fresh chat, paste the bootstrap prompt, and let the agent start executing. Before it writes a single line of domain logic, however, it handles the plumbing I would otherwise forget, postpone, or quietly hope Future Diego will deal with. Future Diego has already filed several complaints about this arrangement.\n\nThink of it like flying an Airbus A300. I prepare the flight plan, complete the preflight checks, and take off. Once the aircraft is established on its route, the autopilot and flight management system handle much of the routine execution. But I am still the captain. I monitor the instruments, verify that the aircraft is following the intended route, respond to changing conditions, and take manual control whenever necessary. The automation may fly the plane, but it does not get to decide that landing in a nearby field is close enough.\n\nThe agent begins by reading the first part of the plan and performing the Git ceremony. It verifies that I am on a fresh development branch and not about to commit directly to `main`\n\nlike a man who has given up on both process and reputation. Then it creates a proper pull request with a sensible name, an actual description, the correct labels, `[WIP]`\n\nin the title so nobody mistakes optimism for completion, and me assigned as the owner.\n\nIt pushes the branch to GitHub. If an issue already exists for the work, it links the pull request to it. If there is no issue, it creates one using the context from the plan, because a naked pull request pointing at nothing is not project management. It is archaeology for the next engineer. Once everything is connected, the agent moves the issue into the **In Progress** column. Only then does it begin the actual implementation phase.\n\nThis is where “human in the loop” stops being a slogan and becomes a working method.\n\nWhen the phase is complete, I review it thoroughly. I inspect the code, test the flows, and change things manually where necessary. By this point, much of the implementation is intentionally repetitive. That is not a failure of creativity. It is the desired outcome. Boilerplate is predictable, and predictable code is easier to review, maintain, and extend.\n\nWhat I am really checking is whether the agent respected the rules we established at the beginning. I do not want domains and use cases written in ten different styles, each one a small artistic reinterpretation of the previous one. I want consistency. I verify the flows, the terminology, the boundaries between layers, the shape of the use cases, and the patterns used across the codebase. I look for anything that quietly drifted away from the conventions.\n\nThe agent proposes. I dispose. Sometimes I also discover that the questionable decision came directly from the plan I wrote. This is useful because it confirms that the human is, in fact, still very much in the loop.\n\nOnce I am satisfied with the phase, I instruct the agent to commit and push. It creates the commits, pushes them to the remote branch, and updates the pull request description so it reflects the work that was actually completed rather than the work we confidently imagined would be completed several hours earlier. Then it waits for CI.\n\nIt does not say the build “should be fine.” It does not report that the tests “probably pass.” It checks the pipeline, confirms that every required job is green, and only then reports that the phase is complete and we can move on. No inspirational speeches from the compiler. It checks, then reports. Then I repeat the process.\n\nOne phase per chat. Fresh context every time. Each phase reviewed, committed, pushed, and verified before the next one begins. This continues until the entire saga is complete and the implementation finally resembles the plan closely enough that we can all agree it was intentional.\n\nWhen the final phase is done, before I allow myself to feel proud, I run the `definition-of-done`\n\nskill.\n\nThis is the executable version of our Definition of Done. Its entire purpose is to tell me the truth about whether the feature is actually complete or merely looks complete from a comfortable distance. It runs every gate in order, from the cheapest checks to the most expensive ones, and it does not stop at the first failure. The final report must be complete, not emotionally considerate.\n\nFirst, it verifies that I am working on a real feature branch and not on `main`\n\nor `dev`\n\n. Then it confirms that the feature was properly planned and specified rather than conjured from a vague instruction such as “implement this” and several minutes of misplaced confidence.\n\nNext, it runs the toolchain gates from the repository root:\n\n`fmt`\n\n`fmt-check`\n\n`lint`\n\n`architecture-check`\n\n`check`\n\n- the full test suite\n\nThe test suite includes unit, integration, and end-to-end tests. If the repository does not yet provide a root-level target, the skill falls back to running the appropriate commands per service. A missing convenience target is allowed. Missing verification is not.\n\nIt also checks that the commits are properly documented and that the working tree is clean. There should be no forgotten changes, temporary files, credentials, `.env`\n\nfiles, or other small surprises attempting to begin an independent career in version control.\n\nThen it runs the security and legal gate. This includes executing the `security-review`\n\nskill against the diff, verifying server-side authorization, checking for new PII or secret exposure, applying ASVS requirements to the affected surface, reviewing GDPR and data-residency implications where relevant, and confirming fail-closed behavior whenever a security guarantee cannot be met.\n\nThe most important part of this process is what the skill refuses to do.\n\nIt may automatically fix formatting. It fixes nothing else.\n\nIt will not weaken a test to make the suite pass. It will not ignore a broken architecture rule. It will not soften a security boundary because the report would look nicer with more green checkmarks. It will not describe a partial success as completion.\n\n“Most gates green” is not done.\n\nThe result is binary:\n\n**DONE**, with every required gate passing.** NOT DONE**, followed by the exact list of failures and the person or role responsible for addressing each one.\n\nThe skill reviews and reports. It does not open the pull request, approve it, or merge it. Those decisions remain mine.\n\nThat is the point of keeping a human in the loop. The agent can execute the plan, automate the repetitive work, run the checks, and report the evidence. But responsibility never leaves the cockpit, even when the captain occasionally forgets where he left the checklist.\n\n## Nobody told me the future would be this good\n\nI love this way of working. Small tasks are painful not because any single one is difficult, but because there are always dozens of them attached to every meaningful piece of work. Create the branch. Check the issue. Open the pull request. Update the description. Run the tests. Check CI. Review the diff. Verify the labels. Make sure nobody accidentally committed a secret. None of these tasks is especially impressive, but together they consume attention like a slow leak in a tire.\n\nThe more of that process we automate, and the more warnings we put in place, the fewer mistakes we have to repair later. Humans have limited cognitive capacity. Mine, after nearly three decades in software, is already carrying several legacy systems and at least one undocumented production incident. I would rather spend it on architecture, product decisions, security, and the actual problem we are trying to solve.\n\nThe agent should do more than type faster. It should perform the repetitive work, enforce the process, challenge assumptions, and surface inconvenient facts. A useful agent should not simply agree with me. It should tell me when the branch is wrong, when the tests are failing, when the implementation drifted from the plan, and when my brilliant shortcut is just tomorrow’s incident report wearing a nice hat.\n\nThat is the real value. The agent is not there to protect my ego. It is there to protect the project, including from me.\n\nI wish I had this 28 years ago. It would have saved me countless hours of manual work, repeated mistakes, forgotten checks, and heroic debugging sessions caused by problems that should never have existed in the first place. Today, projects can be built faster, with better consistency, stronger verification, and less operational noise than at any previous point in my career.\n\nThere is no shame in that.\n\nWe did not stop using compilers because writing machine code by hand looked more authentic. We did not reject version control because copying folders called `final`\n\n, `final-v2`\n\n, and `final-really-final`\n\nbuilt character. Better tools let experienced engineers apply their judgment across a larger surface area. The important skill is no longer how much repetitive work you can tolerate. It is how well you can define, direct, review, and improve the system that performs it.\n\nDefining your own process is vital. It gives the agent clear instructions about what you expect, how the work should be structured, which rules are non-negotiable, and how completion must be proven. But more importantly, it gives you back the most valuable thing you have: focused time.\n\nThat time should not be spent remembering whether you updated a pull request label. It should be spent on your vision, your knowledge, your judgment, and your values.\n\nThe debate around AI-assisted development is often framed as a contest between “real engineers” and people asking a chatbot to build the next big project. That framing is convenient because it avoids the more uncomfortable question:\n\nWhat happens when experienced engineers use agents well?\n\nAn engineer who understands architecture, infrastructure, security, databases, operations, and product requirements can operate across a much larger area than before. The agent does not replace that knowledge. It amplifies it. It allows one engineer to direct more execution, cover more ground, and spend more time on the decisions that actually require judgment. That does not mean doing things by hand has become useless.\n\nWriting code manually, debugging without assistance, configuring systems yourself, and understanding what happens below the abstraction layer are still essential parts of becoming a strong engineer. Manual work builds intuition. It teaches you where systems break, why abstractions leak, and what the tools are actually doing on your behalf. You cannot review an agent properly if you have no idea what good work looks like without one. **The mistake is not doing things manually. The mistake is insisting on doing everything manually forever.** There is a difference between practicing a skill to understand it and turning repetitive execution into a professional principle. One makes you better. The other can make you slower than everyone around you while giving you the comforting impression that the slowness itself is proof of craftsmanship.\n\nThis will change how engineering teams are built. Companies will not continue paying people to perform repetitive work manually simply because manual work feels more authentic. They will pay for judgment, ownership, technical direction, deep understanding, and the ability to produce reliable systems using the best tools available.\n\nTyping every line of code or every command by hand may improve your understanding, and sometimes that is exactly what you should do. But doing it all the time will not protect your career. At some point, it will simply reduce the amount of work you can deliver compared with engineers who have learned how to automate responsibly. Blindly accepting whatever an agent produces is not the answer either. That is not engineering. It is delegation without supervision, which is how you eventually end up explaining to a security team why the database password is in the frontend bundle.\n\nThe valuable engineer will be the person who can do both: understand the work deeply enough to perform it manually when necessary, and automate it well enough to avoid wasting that knowledge on repetitive execution. They will know when to use the machine, when to inspect it, when to distrust it, and when to take the controls back. The future belongs neither to the engineer who refuses automation nor to the person who cannot work without it. It belongs to the engineer who understands the system, directs the tools, verifies the result, and remains responsible for what ships.", "url": "https://wpnews.pro/news/real-engineers-dig-with-their-bare-hands", "canonical_source": "https://www.minid.net/2026/7/14/how-to-automatise-with-ai", "published_at": "2026-08-09 11:19:23+00:00", "updated_at": "2026-08-09 11:35:18.325610+00:00", "lang": "en", "topics": ["artificial-intelligence", "developer-tools", "ai-tools"], "entities": ["Meerita", "Git", "Hacker News", "Linus Torvalds", "Linux"], "alternates": {"html": "https://wpnews.pro/news/real-engineers-dig-with-their-bare-hands", "markdown": "https://wpnews.pro/news/real-engineers-dig-with-their-bare-hands.md", "text": "https://wpnews.pro/news/real-engineers-dig-with-their-bare-hands.txt", "jsonld": "https://wpnews.pro/news/real-engineers-dig-with-their-bare-hands.jsonld"}}