DEV Community

Kemal Deniz Teket
Kemal Deniz Teket

Posted on

4-layered approach: A Practitioner's Account, Part III

§0 — Hook

Part I of this series described two loops. An outer loop at project level — ideation, problem definition, architecture, roadmap — and an inner loop at work level: spec the unit against its io-schemas, respect the package dependency map, write the tests first, implement, verify, integrate. Part II added the intake for that inner loop: review sessions producing findings, findings triaged into buckets, buckets becoming planned work items. Part I also named three gaps: documents overwritten instead of versioned, session handoffs improvised, and a process that was disciplined but not yet systematic.

Loops

This article introduces the design that closed those gaps: a 4-layered execution architecture — better structure, segregation of concerns, explicit rules and constraints. Within a few days, LLMs and I completed more than twenty work items in paragraf's codebase with it — a new UI package, bug fixes, test coverage, API cleanup. Planned, implemented, test-verified, archived. My contribution to a typical item was two decisions — because the other hundred were made once, in the design. I spent about a week building a system whose purpose is to set limits on what an LLM may do: to make "understanding my intention" almost unnecessary during execution, because intention was already encoded before execution began.

The system is four layers of plain markdown — no framework, no runtime, no vendor lock-in — with one central rule: judgment is allowed in exactly one layer, through exactly one mechanism. Everywhere else, ambiguity is unexpressible: it either resolves against data on disk, or the system stops and asks me.

This piece stands alone. It continues a series (Part I, Part II), but you need neither to follow along. This part of the methodology — flows, procedures, sequences, state, plans, session logs, and archives, exactly as they ran — is published here: methodology repository. Every claim below can be checked against those files.

§1 — 4 Layers: Primitive, Sequence, Procedure, Flow

Two terms first, because the whole architecture rests on the difference between them. A condition is branching on data already written to a file or state — IF status == done. A judgment is branching on interpretation, ambiguity, or preference — and in this system, every judgment is resolved by a human decision, through one mechanism: ASK, which blocks execution until the human answers. Conditions are legal in the upper two layers (Procedure and Flow); judgment is legal in exactly one layer (Flow).

The four layers:

  • A Primitive is a single verb with a fixed signature — READ, WRITE, VERIFY, ASK, nine in total — no branching, no ability to call anything else.
  • A Sequence is a named, silent, fixed series of primitive calls (moving a file, appending to a log). No conditions, no judgment, no state writes, no human contact: it succeeds and returns data, or fails and lets the caller decide.
  • A Procedure is linear session bookkeeping (opening a session, closing it, archiving completed items). It may branch on conditions — data on disk — never on judgment.
  • A Flow is a branching, iterating workflow — the only layer a human invokes, and the only layer where judgment is exercised, via ASK.

Each layer may only call the layers below it. Nothing calls upward.

Layer Condition (data) Judgment (via ASK) May call
Primitive no no nothing
Sequence no no primitives
Procedure yes no primitives, sequences
Flow yes yes — only here all layers

If you know the tool/skill/agent vocabulary that frontier LLM platforms converge on, the mapping is not one-to-one. Industry terms are bands with fuzzy edges; these layers are rungs with one hard edge:

Frontier LLM Suggested system
Tool Primitive, Sequence, Procedure
Skill Sequence, Procedure, Flow

The overlap is the point. Industry vocabulary doesn't tell you where mechanics end and judgment begins — a platform "skill" file can quietly contain a judgment ("choose whether the user wants X or Y") in the middle of nominally mechanical instructions, and nothing in the format prevents it. That is why the Skill band reaches into the Flow column. Here, the judgment boundary is a layer edge: a Sequence or Procedure has no vocabulary for judgment at all. The question "should this layer interpret?" isn't answered by discipline. It's unexpressible.

One related distinction, since the table above has no Agent row: a flow is not an agent. Two different agents can execute the same flow — the mechanical steps should be identical, because the lower layers leave no room for them to differ; only what happens at ASK points — the judgment surfaced, the decision returned — legitimately varies. The flow is the score; the agent is the performer.

§2 — A Flow Sample

Before the walkthrough, the map. Flows (green) read from and write to a small set of stores (grey): findings enter through the issues table; grouping turns them into work-pool entries; running a work item reads the pool and the current state, produces a plan (red — the one artifact that moves to the archive when its work closes), and writes results back to the pool and state. The human appears twice on this map, both times through the same mechanism: the flow presents its output in full, asks, and blocks until answered. Everything else on the diagram is reads and writes. The rest of this section walks one real work item across it.

Flows

The bug: a color-profile parser that produced wrong colors for modern color profiles — silently. The function read one parameter (gamma) for all five types of parametric curve, discarding the extra parameters four of those types require. Every input accepted, wrong values cascading downstream, nothing ever complained. The kind of bug that ships.

In my issue tracker this was one finding; triaged together with a second — a misleading comment sitting next to a real test gap in the same rendering path — it became a single work item of type issue-bucket. From there, the layers each did the job they exist for.

Flow — where the decisions happened. The plan-create flow loaded the architecture map and the affected packages' context files, drafted a plan — eight tasks, seven required tests, explicit constraints (the public curve type must not change; the four complex curve types get sampled into a lookup table rather than solved analytically) — then stopped. It presented the full plan, not a summary, and issued an ASK: approve, request changes, or cancel. Nothing had been written to disk yet. That pause is the load-bearing wall of the system. Decision one: I approved. Decision two, also mine at an ASK: lookup table over analytical solving.

Flow, continued — mechanics under conditions. The plan-execute flow worked the tasks strictly one at a time. Task 1 wrote the failing tests with WRITE. Before implementation could begin, a red-phase check ran VERIFY on the new tests and confirmed they fail against the current code — a condition, not a judgment: test output on disk. Only then did the fix proceed — READ the parser, UPDATE the corrected sections, WRITE the missing test. Each task's required tests ran through VERIFY; each result was appended to the session log. At every task boundary the flow checked its ask-human triggers — work spanning layers, new dependencies, public type changes, unplanned edge cases — and none fired, so it never had to stop.

Procedures — the bookkeeping nobody should improvise. session-open procedure set the state fields and initialized the log. session-close procedure wrote the snapshot (a fixed set of fields, each written exactly once), flipped the plan, the work-pool entry, and both findings to done, and closed the log. The archive procedure swept everything marked done — plan file, work-pool row, session log, findings — into append-only archives, each finding stamped with the work item that resolved it. All of it conditions on disk state; none of it interpretation.

Sequences — where drift goes to die. The session log was written only through the write-log sequence: read the log, append the entries, write it back whole — one named call instead of three steps that could each be done slightly differently. When findings changed status, the update-issue-status sequence applied the fixed transition table. And archiving ran through the move sequence: read source, write destination, VERIFY the destination, only then DELETE. The one irreversible primitive in the system is reachable through that sequence alone — there is no other door to it.

Lifecycle of one work item

Work Status Action
open work item selected
plan context-loading, tasks, tests, constraints
approve ASK - request changes -> re-plan
red-phase new tests must fail
execute one task at a time
verify required tests green, VERIFY
close status update
archive via move sequence

Every layer visible, each doing only what its rung allows. The two decisions were mine, at ASK points, inside flows. Everything else was primitives doing single verbs, sequences doing fixed series, procedures branching on disk state. Not didn't involve judgment — couldn't. The layers those steps ran in have no mechanism for it.

§3 — Guarantees: Structural vs Conventional

Not all of this system's rules hold the same way, and a piece like this usually glosses that. The criterion: a rule is structurally guaranteed if violating it requires constructing a call path that exists in no file — the violation is deliberate and visible. A rule is conventionally guaranteed if violating it looks like normal operation minus a step — the model breaks it by simply not following text, and the failure is silent.

DELETE reachable only through the verify-then-delete move sequence is structural: no path in the vocabulary reaches a deletion without passing a verification first. "ASK lives only in Flows" is conventional: it's a sentence in a markdown file, and nothing mechanically stops a procedure from containing an ASK except the executing model choosing to honor the text. So are "one task at a time, no batching" and the layer-calling restrictions themselves.

And I have direct evidence that conventional rules drift, because my own files carry the scars. Several procedure files contain callouts like "do not omit any" — emphasis that exists only because I observed the model skipping steps and patched it with louder text. That is the system admitting, in writing, that convention decays, and that my current mitigation is the weakest guarantee available: words, repeated more forcefully.

The system does have a repair mechanism for this, and it is the counterpart to those scars: a sequence is created only when the same fixed series of steps recurs across procedures or flows and drift has been observed on it — the verify-then-delete move sequence exists because deletion is hard to reverse; the write-log sequence because its three steps invited improvisation. That rule converts a recurring conventional failure into a structural guarantee. Emphasis patches are the symptom; promotion into a sequence is the cure. The honest state of the system is that some observed drift has been promoted, and some is still sitting in patched text.

To be fully honest, the distinction itself has a floor: in a logic-in-markdown system, even "structural" is convention at the substrate — everything is text a model chooses to follow. The difference that survives is drift-resistance: structural violations require deliberate construction; conventional violations are silent omissions.

The honest generalization goes one step further: this architecture does not reduce judgment failures, it relocates them. Every interpretation problem is pushed into flows, which means my worst failures are now concentrated at ASK exchanges — the design tells me where I will fail, not that I won't.

This matters because the field is quietly souring on process-as-markdown. Practitioners report agents ultimately not following elaborate instruction files, and nobody honestly reads the mountains of generated markdown they approve. Both criticisms are fair, and this system's answers are partial: the approval gate presents the full plan and blocks on it — the one document you cannot skim is the one that authorizes execution — and the structural/conventional split at least tells you which rules die first when compliance slips. Markdown buys near-zero implementation cost, total portability, and a trivially editable process; it pays by holding most rules only as strongly as the model's adherence on a given day (and by real operating costs — the append-only session log, for instance, retransmits its entire accumulated content on every append). I chose that trade deliberately, for one person, iterating weekly. I would not choose it, unmodified, for a team.

§4 — Handoff Documents and Version Boundaries

One mechanism in the system scales beyond it. At session scale, a snapshot is a fixed set of fields written at close and consumed at the next open — completed, incomplete, next — so a fresh context window resumes without replaying anything. The same pattern applies one zoom level up. When a codebase turns to spaghetti, or the project's shape changes drastically, the move is not to refactor in place with an ever-longer conversation. The move is handoff documents — a deliberate, human-reviewed summary of decisions made, state reached, constraints learned — and then a fresh start: version N+1, new session, sometimes a new codebase, with the handoff documents as its only inheritance.

A typical progression: Version 1 contains initial human-AI delegations on tasks, basic architecture & descriptions, a running prototype, manual scenario tests. Version 2 contains project structure: types, config, service, UI, etc. Cross-cutting concerns such as authentication, observability, security can be introduced during Version 3.
Initial versions are allowed to be spaghetti; their job is to prove the mechanics. Version N+1 may inherit the decisions, design, code snippets. And each boundary is a re-delegation point: with what version N taught me, what do I hand off differently now? Snapshot and handoff are the same idea at two scales — durable state that survives the death of its context.

§5 — Related Concepts

This section locates the system in the current landscape; it is not a story about the system's origins. I have followed these concepts for months; the specific pieces linked below are recent reads — snapshots of where the terminology stands right now — and the relations are family resemblances, not one-to-one mappings.

The first is spec-driven development (Böckeler's comparison of SDD tools on martinfowler.com). In the taxonomy now circulating — spec-first, spec-anchored, spec-as-source — this is a spec-first workflow: a spec (the plan) is created per work item, gates execution, and is archived on completion. Practitioners in that space report struggling with exactly the two problems this article has been circling: agents not reliably following their own process files, and one rigid workflow forced onto every size of task. The structural/conventional split above is an attempt at the first; this system's three work-item types are an answer to the second.

The second is durable execution (Temporal's workflow model). Engines like Temporal structure long-running workflows the same way this markdown does: deterministic orchestration, a signal-and-wait primitive for human input, persisted history that lets execution resume exactly where it stopped. ASK is a signal-and-wait; the snapshot is a poor markdown cousin of event-history replay; the handoff document is the same pattern promoted to project scale.

The third is harness engineering (Böckeler's mental model, Anthropic's harness for long-running agents, OpenAI's account of an agent-first codebase). In that vocabulary, this system is an outer harness built from feedforward guides (the plan, the layer files) and computational feedback sensors (VERIFY, the required tests) — with the human as its only inferential sensor: there is deliberately no LLM-as-judge middle tier here; every act of interpretation routes to a person.

The family resemblances across those three accounts are hard to miss. Anthropic bridges context windows with a progress file and a get-your-bearings ritual (this system's snapshot), works one feature at a time (one task at a time), and enforces some of its rules with "strongly-worded instructions" — the conventional guarantee class from §3, unnamed there. OpenAI's team versions execution plans as first-class repository artifacts, active and completed side by side (plans and archives here); runs recurring cleanup tasks against accumulated drift — what Böckeler calls the steering loop, and what §3's sequence-promotion rule does by hand; and instructs its agent to "escalate to a human only when judgment is required," which is this system's ask-human triggers in six words. Not everything runs in this system's favor: Anthropic reports the model tampers with JSON files less than with markdown ones; my state file is YAML, but my plans and logs sit on the wrong side of that finding — untested here, noted honestly.

I built this system three months ago and read these particular pieces in recent days, so the claim is neither discovery nor priority. It is narrower and, I think, more useful: a markdown system designed alone, around one practitioner's needs, sits recognizably inside the patterns that three separate communities are converging on — arriving from the LLM-practice side rather than from tooling or distributed systems. That fit is the strongest evidence I have that the design is load-bearing rather than idiosyncratic.

§6 — Issues and Next Steps

The boundary this system draws — scope and intent gated by a human, mechanics running free until a named trigger fires — is, I think, the one transferable idea here. Not the four layers; choosing where that boundary sits on purpose, instead of letting it fall wherever a tool vendor's defaults put it.

Three issues, observed rather than predicted. First, self-grading: the same agent writes the plan's required tests and the implementation, then gets graded against its own tests. The red-phase check proves the tests can fail, and I read the test list at plan approval — but nothing checks whether the tests are sufficient. This is the behaviour-harness blind spot the field is openly struggling with, and this system has it too. Second, markdown as logical gates: enforcement rigor decays and state management slips, exactly as §3's scars document. The choice was deliberate — I had only built code-based approaches before and wanted to test logic-in-markdown in action — and the test produced its answer. Third, the control inventory is thin: sensors exist at exactly one point in the lifecycle (VERIFY against required tests), nothing runs continuously against the codebase, and there are no inferential controls at all.

The next steps address each. A hybrid substrate: structural guarantees migrate to code — hooks, scripts, validation — while guidance and judgment stay in text; neither markdown alone nor code alone solves the problem, and the split should follow the guarantee classes from §3. And three new flows that fill the named gaps: a code-review flow (the system's first inferential sensor), a security-evaluation flow (its first control running outside the work-item lifecycle), and an e2e/user-acceptance flow (a behaviour harness that tests as a user would, against feature definitions the agent may flip to passing but never edit).

The full methodology behind this article — every flow, procedure, sequence, plan, log, and archive referenced above, including the scars — is available in the methodology repository. The next piece reports what survived contact with a project that is nothing like this one.

Top comments (0)