Skip to content

Latest commit

 

History

History
363 lines (290 loc) · 28 KB

File metadata and controls

363 lines (290 loc) · 28 KB

Deterministic Agentic AI Development with Claude Code

  • Project: Minimum Viable Health Dataspace v2 (EHDS reference implementation)
  • Audience: anyone asking "how do you actually use Agentic AI for programming without it going off the rails?"
  • Last updated: 2026-06-01
  • Maintainer: Matthias (@ma3u)

Companion document: Software Development Life Cycle (SDLC) — the deterministic gates this AI author has to pass through, same as any human contributor.

🟢 Not a software engineer? Read the plain-language version first: How We Use AI to Help Build This.

Acronyms used in this document (click to expand)
Acronym Expansion
LLM Large Language Model — the kind of AI behind Claude Code; non-deterministic by nature
CI/CD Continuous Integration / Continuous Delivery — the automated build-test-publish gate (see SDLC §6)
PR Pull Request — a proposed change, reviewed before it is merged
ADR Architecture Decision Record — a short written note capturing a decision and its reason
RBAC Role-Based Access Control — granting permissions by user role
MCP Model Context Protocol — a standard way for AI tools to connect to live data sources

1. The thesis: wrap a non-deterministic author in a deterministic harness

Large Language Models (LLMs) are non-deterministic. Ask the same question twice and you may get two different answers. Software, by contrast, demands determinism — the build is reproducible, the tests are reproducible, the deployment is reproducible.

The whole craft of "agentic AI for programming" is bridging that gap:

Treat the agent as a fast, tireless, broadly-knowledgeable junior developer. Then make every piece of its output pass the same deterministic gates a senior would enforce — automatically, every time.

The agent supplies breadth and speed. The harness supplies determinism and trust. Neither is sufficient alone. This document describes the harness I use with Claude Code on this project, and the rules of engagement that keep AI-generated code reviewable and safe in a regulated-health-data domain. The general principles behind this approach are laid out well in Anthropic's Building Effective Agents.

The guiding principle, borrowed from how I run human teams: Evidence > assumptions · Code > documentation · The gate, not the author, decides what ships.

Why this matters

This is a reference implementation for the European Health Data Space (EHDS), a regulated domain. Using AI there is only acceptable if you can still trust and audit every change. The layered harness below is what makes that true: the AI goes faster and broader, but it can never quietly ship something that bypasses the project's safety, privacy, and review checks. A human — ideally a domain expert — stays the final decision-maker (§8).


2. The determinism stack

Determinism is layered. Each layer narrows what the agent can do and sharpens what it should do, so that by the time code reaches the deterministic gates it is already shaped by the project's rules. Read the diagram top-to-bottom: each layer adds a constraint, and the bottom layer (L6) is the same gate a human passes.

flowchart TD
    L0["🧭 L0 · Spec<br/>CLAUDE.md + .claude/rules/*<br/>(read every session)"]
    L1["🔑 L1 · Constrained tools<br/>settings.json allow-list<br/>(safe ops auto-run; rest needs approval)"]
    L2["📚 L2 · Durable memory<br/>ADRs + planning index<br/>(why decisions were made)"]
    L3["⚙️ L3 · Repeatable prompts<br/>slash commands"]
    L4["👥 L4 · Specialist sub-agents<br/>architect · compliance · tester · security<br/>(read-only, scoped)"]
    L5["🧩 L5 · Skills<br/>domain packs (health-dataspace)"]
    L6["✅ L6 · Deterministic gates<br/>pre-commit + CI/CD<br/>(the SAME gates a human passes)"]
    L0 --> L1 --> L2 --> L3 --> L4 --> L5 --> L6
Loading
Layer What it is Why it matters
L0 The written spec the agent reads every session Without it the agent guesses your conventions; with it, it follows house style.
L1 An allow-list of tool calls (§4) Limits the blast radius — the AI can't push, delete, or deploy on its own.
L2 ADRs + planning index (§3) Gives the agent the why, so it stays consistent with past decisions.
L3 Slash commands (§5) Turns ad-hoc prompts into repeatable, reviewed workflows.
L4 Read-only specialist reviewers (§6) Expert second opinions that can advise but never silently edit.
L5 Skills — task-triggered domain playbooks Encodes "the way we do X here" for recurring task types.
L6 The deterministic gates (pre-commit + CI/CD) The final arbiter — AI output ships only if it passes, exactly like a human's.

The bottom layer (L6) is shared with humans and is documented in the SDLC. The layers above it are the agentic scaffolding and are the subject of this document.


3. Anatomy of the .claude/ folder

Everything that constrains and configures the agent is checked into the repo, so it is versioned, reviewable, and identical for every session and every contributor.

Path Role
CLAUDE.md (repo root) The operating manual the agent reads every session: build commands, the 5-layer architecture, key directories, coding conventions, and the Top Gotchas (the traps that waste an hour if you don't know them). Kept short on purpose.
.claude/settings.json Permission allow-list — which tool calls run without asking (see §4).
.claude/rules/code-style.md TypeScript/Next.js + Cypher + Bash + Prettier conventions, scoped to source paths.
.claude/rules/testing.md Test frameworks, locations, commands, what not to mock.
.claude/rules/api-conventions.md Protocols (DSP/DCP/FHIR/OMOP/EHDS/GDPR), data models, route patterns, role/access matrix, mock-fixture mapping.
.claude/commands/ Slash commands — repeatable, parameterised prompts (§5).
.claude/agents/ Specialist sub-agents — scoped, read-only experts (§6).
.claude/skills/SKILL.md A domain skill pack auto-triggered by task type.

Why it matters: because this lives in git, improving the agent is a normal PR — change a rule, review the diff, merge. The agent's behaviour is configuration, not folklore: anyone can see exactly what governs it, and changes are themselves reviewed.


4. Constrained tools & permissions (blast-radius control)

.claude/settings.json is an allow-list. Read-only and obviously-safe operations run without interrupting the flow; everything else requires explicit human approval:

{
  "permissions": {
    // Abridged excerpt — the live .claude/settings.json has ~51 allow entries.
    // A representative subset of what auto-runs:
    "allow": [
      "Bash(git diff:*)",
      "Bash(git status)",
      "Bash(npm test:*)",
      "Bash(npm run build:*)",
      "Bash(npx tsc:*)",
      "Bash(grep:*)",
      "Bash(find:*)",
      "Bash(docker compose ps:*)",
      "Bash(kubectl get:*)",
      "Bash(gh pr view:*)"
    ],
    "deny": [
      "Bash(kubectl delete:*)",
      "Bash(kubectl drain:*)",
      "Bash(docker system prune:*)"
    ]
  }
}

The agent can freely inspect, build, type-check, and test — the actions you want it doing constantly. Anything that mutates outside the working tree (pushing, deleting, deploying, installing) surfaces for a human decision.

Why it matters: this is the principle of least privilege applied to an AI author — give it exactly the access it needs to be useful, and no more, so a mistaken or misunderstood instruction can't cause irreversible damage.


5. Repeatable prompts: slash commands

A free-form prompt is non-deterministic by nature. A slash command is a checked-in, version-controlled prompt that produces a consistent workflow every time it's invoked — the determinism trick applied to the instruction itself.

Command What it does
/review Reviews the working git diff against this project's conventions: TS strict mode + @/* imports, Cypher MERGE-only + PascalCase labels, fictional org names only, mock fixtures kept in sync with API routes, tests for new behaviour.
/fix-issue <N> Investigates a GitHub Issue end-to-end: gh issue view N → locate relevant files → implement → verify.
/deploy-check Pre-deployment validation using the project's real build/test commands.

Why it matters: these encode "the way we do X here" once, so the quality of the review or workflow no longer depends on how well I happened to phrase the prompt that day. A command is a prompt you can review, version, and improve like any other code.


6. Specialist sub-agents (scoped, read-only experts)

For deep reasoning in one domain, the project ships specialist sub-agents under .claude/agents/. Each is deliberately constrained:

Agent When to use it Model Tools
architect Reason about the 5-layer Neo4j graph, DSP/FHIR/OMOP/DCAT-AP interactions, service topology, cross-cutting trade-offs. Sonnet Read, Grep, Glob, Bash (read-only)
compliance-reviewer Verify EHDS conformance, DSP/DCP protocol correctness, GDPR patient-rights, audit-trail integrity. Sonnet read-only
tester Audit coverage, triage test failures, plan new Playwright journeys, assess Vitest health. Sonnet read-only
security Review auth flows, RBAC, Keycloak config, credential/secret handling, vulnerabilities. Sonnet read-only

Two deliberate constraints make these safe:

  1. Read-only toolset. They reason and advise; they don't write. (The architect agent's brief literally says "Do not write code unless explicitly asked; your job is to reason and advise.") A wrong opinion is cheap; a wrong edit is not.
  2. Sonnet, not the top model. Right-sized for focused, scoped review — fast and economical, with the orchestrating session retaining the harder reasoning.

Why it matters: this mirrors a real team. You bring in a security or compliance reviewer to look and advise, not to silently rewrite your branch — and in a health-data project, an independent compliance/security read is exactly the kind of second opinion you want before merge.


7. Rules of engagement (the determinism techniques)

These are the habits — encoded in CLAUDE.md and the rules files — that keep agent output predictable and trustworthy. Each one closes a specific failure mode of AI-assisted coding:

  • Read before write. Always inspect a file before editing it. Why: blind edits are how an AI corrupts code it didn't fully understand.
  • Idempotent by default. Cypher uses MERGE, never bare CREATE; schema constraints use IF NOT EXISTS. Why: re-running a change is then a no-op, so a retried or repeated agent action is safe rather than duplicating data.
  • Plan / ADR first for big changes. Architectural work starts with an ADR (see SDLC §3). Why: the decision is reviewed before a single line is written, so the agent can't quietly take the project in the wrong direction.
  • Token-efficient context (ADR-026). Routinely-loaded docs are kept under ~15K tokens. Why: a sharp, relevant context produces sharper reasoning — load the ADR index then the one relevant ADR, not the whole corpus.
  • Evidence over assertion. A change isn't "done" because the agent says so — it's done when the gates are green (lint, type-check, tests, scans). Why: the SDLC gates apply to AI commits identically to human commits.
  • Traceable provenance. AI-assisted commits carry a Co-Authored-By: Claude trailer. Why: git log always shows what the agent touched — essential for audit in a health-data context.
  • Domain guardrails. Hard rules the agent must never break — e.g. only fictional organisation names in demo data and docs (AlphaKlinik Berlin, PharmaCo Research AG, …; never real entities). Why: these protect against reputational and privacy harms; they live in the rules files and are checked by /review.

8. The human-in-the-loop: the conceptual-review flywheel

The most important part of agentic development is not the AI — it's the feedback loop that turns human expertise into better specifications.

flowchart TD
    H["🧑‍⚖️ Human expert<br/>(architecture · governance · domain)"]
    S["📋 Spec<br/>CLAUDE.md · ADRs · rules"]
    A["🤖 Claude Code<br/>proposes a change"]
    G["✅ Deterministic gates<br/>(SDLC)"]
    R["🚀 Running system + docs"]
    H -->|"sharper spec: Issue / ADR / corrected doc"| S
    S -->|"read every session"| A
    A -->|"Pull Request"| G
    G -->|"merged result"| R
    R -->|"review &amp; critique"| H
Loading

An AI agent is only as good as the spec it reads. When a human corrects a sequence diagram, tightens an ADR, or files a precise Issue, that correction becomes durable input the agent honours in every subsequent session. So the highest-leverage contribution to this project is often conceptual, not code: better requirements, clearer governance rules, corrected architecture descriptions. Each one raises the floor of everything the AI produces next.

Why it matters: this is the answer to "how to best use Agentic AI for programming." Don't aim for a hands-off autopilot — aim for a tight loop where human judgement continuously sharpens the spec, and deterministic tooling continuously verifies the output. The domain expert is the steering wheel; the AI is the engine.


9. Strengths, risks, and mitigations (an honest assessment)

Where agentic AI excels here Where it needs the harness Mitigation in this project
Breadth — wiring CI, security scanners, SBOM, multi-layer schemas quickly Confidently wrong output (plausible but incorrect) Deterministic gates (tests, type-check, scans); /review; read-only specialist sub-agents
Consistency — applies project conventions uniformly Drift from intent over a long task ADR-first for big changes; small PRs; human review of the diff
Speed — repetitive refactors, fixtures, boilerplate Hallucinated APIs / fabricated facts "Base everything strictly on the repo, don't invent" (the init recipe, §10); CI catches non-existent calls
Tireless — never skips a checklist step Over-engineering / scope creep KISS / YAGNI in the rules; maintainer trims scope at PR
Great at scaffolding tedious safety work Blast radius if given broad tools Permission allow-list; least-privilege tools (§4)

The pattern: AI handles the breadth; deterministic tooling and human judgement handle the correctness.


10. The init recipe — bootstrapping Claude Code on any repo

The .claude/ setup above wasn't hand-written from scratch — it was generated by pointing Claude Code at the existing repo with a single, carefully-bounded instruction, then reviewed like any other change. The reusable recipe is published as a gist:

ClaudeCodeInit — the bootstrap prompt

In summary, it asks the agent to read all planning and architecture docs in the repo and generate a complete .claude/ folder:

  1. CLAUDE.md — concise: build commands, architecture, key dirs, conventions, top project-specific gotchas.
  2. settings.json — allow safe ops (build/test/git-read/grep/find), require approval for destructive actions.
  3. code-style.md — conventions extracted from the actual codebase.
  4. testing.md — real test frameworks, commands, standards.
  5. api-conventions.md — protocols, data models, API patterns.
  6. review.md — a code-review command using git diff injection.
  7. fix-issue.md — an Issue-investigation workflow with gh CLI.
  8. deploy-check.md — pre-deploy validation using the real build command.
  9. SKILL.md — domain skill packs, auto-triggered by task type.
  10. agents/ — specialist read-only agents (architect, compliance, tester, security) on Sonnet.

The one constraint that makes it trustworthy:

"Base all content strictly on what you find in this repository. Do not invent architecture or conventions not present in the code or docs."

Why it matters: that single rule is what turns a generic AI into a project-specific one — and it's the same anti-hallucination discipline that runs through everything above.


11. Outlook — maturing the agentic setup

  1. Claude in CI (Continuous Integration) — automated PR review via the Claude GitHub app/Action, so every PR gets an AI first-pass review on the server, not just locally.
  2. Branch protection (see SDLC §11) so even AI commits cannot bypass green CI.
  3. Commit-message enforcement (commitlint) so AI-authored commits keep the Conventional Commits shape that drives release notes.
  4. Live context via MCP — Model Context Protocol servers exposing Neo4j / FHIR so the agent can reason against current data, not just the schema.
  5. An eval / regression harness for agent output — golden tasks the setup is re-run against when CLAUDE.md or the rules change, so configuration changes are themselves tested.

References