AI Engineering

Using AI well is an engineering discipline, not a habit. I built my team's AI delivery system — the pipeline, the gates, the context, the review roles — and it ships real features.

10 pipeline stages 23 skills · 12 agents 16 features shipped through it 30+ per-service context files 4 role-based AI reviewers feature drafts: days → hours

System architecture

Two views of how the system works — the orchestration pipeline that routes every request, and the memory architecture that makes it remember.

Orchestration Pipeline

A request flows through six stages — from user input to learned response. The orchestrator decides which models, tools, and memory stores to use at each step.

Hermes Orchestration V1 Architecture — 6-stage pipeline: Input, Intent, Context, Execution, LLM Execution, Output, with Memory Plane, Capability Fabric, and Learning Loop

Memory Architecture

Every layer earns its token cost. Facts flow from ephemeral session context to permanent knowledge — and nothing important lives in only one place.

Hermes Agent Memory Architecture v2.1 — showing the layered system from SOUL.md (identity/law) through MEMORY.md (runtime injection), Mnemosyne (vector store + knowledge graph), to Obsidian (human-curated semantic store)

SOUL.md — identity & law

Loaded every turn. Contains persona, iron rules, skill triggers, routing logic. The constitution — it never changes mid-task and overrides everything below it on conflict.

MEMORY.md — runtime injection

Always-loaded facts with a 7-day admission test: still true and useful next week, or it doesn't get in. Behavioral corrections, environment facts, user preferences — compact, high-signal, token-cost forever.

Mnemosyne — vector store + graph

3,700+ entries. Hybrid search (50% vector + 30% FTS5 + 20% importance). Knowledge graph with temporal triples for structured relationships. The long tail — on-demand recall, not always-loaded. Self-maintains via nightly digest and weekly consolidation.

Obsidian — human-curated layer

The canonical semantic store. Interlinked markdown knowledge base for deep domain knowledge. Human-authored, human-organized — the agent reads it but doesn't write to it uninvited.

Session transcripts — searchable history

FTS5-backed conversation history. Past sessions are searchable but stay out of the active context. Used for cross-session recall — "what did we do about X" — without polluting the current turn.

The failure file

Every AI success story you'll read is missing this section. Here's what went wrong in ours — the discipline came from the failures.

The fix that broke production

The agent found a real bug — one that had sat harmless in production for years — and repaired it. The repair changed behavior other code had quietly grown to depend on, and things blew up. Lesson: an agent evaluates code; it doesn't know your system's history. A harmless bug is load-bearing until proven otherwise.

The big answer to a small ask

The requirement was genuinely small — an existing rule needed one more condition, a change the codebase was already shaped for. The agent, not grasping that intent, rebuilt the surrounding flow instead: hundreds of new lines that technically worked and doubled the review burden. Lesson: the smallest correct change comes from knowing what the codebase already wants to do — that judgment is still ours.

Correct, and slow

Asked for accuracy, the agent updated the database row by row — correct, and an IO storm at our volume. Batching was the obvious answer, but only obvious to someone who has paid for IO before. Lesson: performance instincts don't ship with the model; they come from the scars.

The pattern behind all three: the damage happens when someone can't yet tell a good answer from a plausible one — a junior burning tokens on the wrong question, merging changes they can't explain. So the rule is not "use AI less." It is: discernment first, delegation second. You must be able to judge the problem and the logic before you outsource the typing.

The delivery system

$ workflow run <feature>

prd ✓ proposal ✓ contracts ✓ sdk ✓

tasks → dev → verify

⏸ gate: waiting for human approval…

# AI never commits

AI-native software development lifecycle

An artifact-gated, 10-stage delivery pipeline built as agent skills: requirements document (PRD) → design → contracts → SDK → tasks → parallel agent development → machine-judged acceptance. Every artifact carries a human approval signature, and irreversible actions — publish, push, migrations — require explicit human confirmation.

  • Artifact Pipeline
  • Role-based Review
  • Human Gates

[chat] @bugdoctor error spike, workflow svc

→ tracing across repos… (MCP: logs + code)

→ hypothesis: stale credential cache

→ evidence: trace id 8f3a · 3 log lines

# hours of triage → minutes

Bug Doctor

Team-built AI incident diagnoser living in our team chat: symptoms in, trace-backed hypotheses out — reading production logs over MCP and code across every repo, frontend and backend. The real work was making the system diagnosable first: standardized errors, trace IDs through every hop, names that tell you what broke. The bot is the payoff; the discipline is the design.

  • Chat Bot
  • MCP
  • Standardized Tracing

$ schema build events/*.json

codegen → node ✓ java ✓ rust ✓

publish → sdk v1.0.34

# producers and consumers can't drift

Event Schema Registry

JSON-Schema-first event contracts with multi-language SDK codegen (Node, Java, Rust) — producers and consumers can't drift because the schema is the source of truth.

  • JSON Schema
  • Codegen
  • Multi-language SDK

[chat] @reach send a $10 bonus to users registered on Jan 12

→ target preview ready · audit logged

⏸ waiting for "confirm"…

→ executed · results reported to chat ✓

# preview first · a human confirms · audit always

Operations agent (human-in-the-loop)

A LangChain agent living in our team chat: operations asks in natural language, the agent resolves the target audience, shows a preview, and executes only after an explicit "confirm" — every step audit-logged. The same gate philosophy as everything else I build.

  • LangChain
  • Zod Tools
  • Preview-first

$ agent task "add a field to the contract"

→ repo resolved (1 of 17) · context loaded

→ memory: prior decisions recalled

# the prompt is engineered context, not clever words

Context engineering

Clever prompts don't scale; engineered context does — a routing manifest across 17 repositories, 30+ per-service context files, and persistent memory across sessions. The agent starts every task already knowing the codebase.

  • Routing Manifest
  • Context Files
  • Persistent Memory

Ten stages, one gate at a time

A one-line feature request walks through ten stages, each invoked as /workflow-<stage>. There is no state.json — every stage derives its state from the presence and content hash of the artifact the previous stage wrote, and refuses to run until that artifact exists and is approved.

  1. 1 · Init — open the feature workspace; downstream stages populate it, nothing else.
  2. 2 · PRD — draft the requirements document, marking every unknown as [to confirm] instead of guessing.
  3. 3 · Proposal — frontend/backend design, the API contracts, and the data contract.
  4. 4 · Approve — a human sign-off gate on the design. Nothing proceeds without it.
  5. 5 · Proto — generate the .proto contracts and publish the shared gRPC types.
  6. 6 · SDK — update the SDK to consume the freshly-published contracts.
  7. 7 · Figma — map the frontend design to components (optional, when there's UI).
  8. 8 · Tasks — a dependency-ordered work breakdown the agents can pick up.
  9. 9 · Dev — parallel implementation by subagents, one task at a time.
  10. 10 · Verify — machine-judged acceptance against the contracts.

Artifact-gated, human-approved, contract-first. Contracts are generated and shared before a line of code is written — so producers and consumers can't drift.

A skill is a checklist with teeth

Each stage — and each reusable building block — is a skill: a Markdown file the agent reads before it acts. This is a real excerpt from graceful-shutdown, the policy every backend service must satisfy before it's called production-ready. It came out of a real incident.

Real excerpt from the ai-native-sdlc repo — desensitized (neutral service names, no company internals).

skills/graceful-shutdown/SKILL.md
# Graceful Shutdown — Monorepo Default Policy

# A service is "graceful-restart capable" iff all six hold:

  1. Signal binding. Listen for SIGTERM → enter draining state, do not exit.
  2. Two-stage drain. Flip health probe to NOT_SERVING first, wait one
     readiness period so the load balancer stops sending traffic, then drain.
  3. In-flight wait. Stop accepting new connections; let in-flight
     requests finish, bounded by a timeout < terminationGracePeriodSeconds.
  4. Background workers drained. Consumers, tickers, span processors
     all observe the shutdown signal and exit cleanly.
  5. Connection cleanup. DB / Redis / upstream pools closed after the
     server stops; telemetry flushed last.
  6. K8s manifest aligned. terminationGracePeriodSeconds ≥ drain + buffer.

# If verification can't be done, say so in the PR —
# do not claim "graceful shutdown done" on code review alone.

The skill also ships stack-specific templates (Rust, NestJS, Node, Java), the K8s manifest, a local SIGTERM test, and a list of anti-patterns to reject in review. Twenty-three skills like this live in the repo — the ten pipeline stages plus reusable blocks.

Each reviewer is a specialist, not a generalist

The pipeline dispatches role-specialized subagents, each with a tight remit and its own tool budget. Here is the real remit of code-reviewer — one of twelve.

Real excerpt from the ai-native-sdlc repo — the agent's own definition file.

agents/code-reviewer.md
# Role: senior code reviewer. Correctness, security, performance,
# maintainability — with constructive, specific feedback.

When invoked:
  1. Identify the scope of changes and the language/framework.
  2. Read the changed code in full, plus enough context to judge correctness.
  3. Review in order: correctness → security → performance
     → maintainability → tests → docs.
  4. Produce prioritized, actionable feedback with file/line references.

Severity:
  CRITICAL security or data-loss risk — BLOCK merge.
  HIGH     real bug or broken contract — fix before merge.
  MEDIUM   maintainability / minor correctness — fix when practical.
  LOW      style, naming — optional.

# Be specific, be brief, be kind.

The full roster is twelve: planner, product-owner, microservice-architect, code-architect, backend-developer, frontend-developer, data-layer-reviewer, code-reviewer, qa-expert, security-auditor, technical-writer and harness-optimizer. Each one draws a boundary; none of them can approve its own work.

The discipline the agents run under

All of it operates under one standing rule set — a desensitized set of Karpathy-derived guidelines that bias toward caution over speed.

  • Human-in-the-loop, always. Approval gates sit at design and before any publish; the AI never commits or publishes on its own.
  • Content-hash state. State lives in the artifacts, not a database. Re-running a stage hashes the upstream artifact and detects changes, so edits ripple forward deterministically.
  • No unreviewed merge. Every stage produces a reviewable artifact; the next stage refuses to run until the previous one exists and is signed off. Plausible is not correct — nothing merges on hope.

The full build

The whole pipeline — 10 stages, 23 skills, 12 agents — lives on GitHub, desensitized and MIT-licensed. What you've seen here is a few samples; the rest is in the open.

explore the build on GitHub →

Principles of working with agents

  • AI proposes, humans approve. Every irreversible action — commit, publish, deploy, migration — sits behind an explicit human gate. No agent ever commits.
  • AI compresses the zero-to-eighty stretch. A two-day build becomes a two-hour first draft. The last twenty percent is still ours, and the real skill is discernment: catching what it got wrong.
  • AI amplifies your code culture. Rot in, rot out — an agent raised on a disciplined codebase ships discipline; raised on mess, it ships mess faster.
  • Context beats prompts. The agent should start every task already knowing the codebase — routing manifests, per-service context files, persistent memory — not a cleverly worded request.
  • Incidents compile into policy. A production lesson becomes a rule wired into the agent harness — a readiness gate the agent can't skip, so the same mistake can't ship twice.

The rules my agents live by

Both of my agents — the one at work and the one at home — run under the same standing rules. Every one of them was written the hard way.

  1. Rule 0: no guessing. Verify before speaking; if you can't verify, say so.
  2. My words mean exactly what they say. Don't interpret, don't complete my thoughts — ask.
  3. Execute only what was asked. "While I'm here, let me also…" is where incidents start.
  4. Show proof after every write. "Done" is a claim; a file path is evidence.
  5. Discussion is not permission. Talking about running something is not approval to run it.
  6. "It ran" is not "it works." Verify after every execution.

Slow is fine. Wrong is not.

Raising an agent

The Lab page shows what my home agent does. This is how it got that way — the same method I use on the agents at work, run twice, converging on the same constitution.

Constitution before tasks

On day two of the agent's life I installed SOUL.md — its identity file: problem-solving protocol, naming rules, behavioral law — before it did any real work. Rules don't retrofit well.

Small jobs first

New agent, small scope. I watch where it stalls or overreaches, then widen. It's the same calibrated-challenge ladder I use on junior engineers.

Every failure becomes law, immediately

It executed without confirmation three times in one session — that same day, "discussion is not permission" became permanent law. Six standing rules; every one has an incident behind it.

Writes must show receipts

After every correction the agent must show the stored entry — ID and content. "Got it" is not evidence that learning happened.

Memory has an economy

Every always-loaded fact costs tokens forever, so MEMORY.md — the always-loaded layer — has a 7-day admission test: still true and useful in a week, or it doesn't get in. Facts route by weight — behavioral law loads every turn, Mnemosyne holds the long tail for on-demand recall, transcripts stay searchable but out of the way.

Tune the harness, not just the prompt

The expensive model was over-serving simple execution, so it got demoted to deep-reasoning duty only. An update wiped the config once — pre-update backups went on that day. A nightly memory digest, a weekly consolidation pass, a monthly self-audit: the agent maintains itself, on a schedule.

Two agents, two independent memory stores, one converging constitution. That's when you know it's a method — not a habit.

Every tool answers a constraint

None of this tooling exists because it's cool. Large language models have a handful of hard constraints — and every piece of my stack is a direct answer to one of them.

Context is finite

A model can only hold so much, so relevance beats volume: a routing manifest across 17 repositories decides where a task belongs, and 30+ per-service context files mean the agent starts already knowing the codebase — instead of re-reading it every session.

Memory doesn't persist

The biggest handicap of any agent: session ends, knowledge gone. My answer is layered — an identity file for law, an always-loaded fact file with a 7-day admission test, a vector store (Mnemosyne, 3,700+ entries) for the long tail, and Obsidian as the human-curated layer on top. Facts route by weight; nothing important lives in only one head.

Tokens aren't free

Every dev command an agent runs burns context. A filtering proxy (RTK) strips the noise before the model sees it — 75M+ tokens measured saved. Scheduled scripts that need no judgment run with no LLM at all. At home, a tiered router sends routine work to budget models and saves the heavyweight for deep reasoning. Same principle at every scale: pay for thinking, not for typing.

Plausible is not correct

Models produce answers that look right. That's why nothing merges without a human gate, every memory write shows a receipt, and the failure file above exists. Trust is a budget — spend it on verification, not on hope.

Good process doesn't repeat itself

Anything done twice becomes a versioned skill. Some we adopted from the community and adapted — credited, not claimed. Some we built from scratch: the delivery pipeline, the review roles, the repo router. The test is always the same: would a new teammate — human or agent — do this right on day one?

The stack will change. The constraints won't. Build for the constraints.