Paul Jialiang Wu agentic-portfolio δΈ­ζ–‡ EspaΓ±ol ν•œκ΅­μ–΄ ζ—₯本θͺžβœ‰οΈ Free list
← Back to portfolio

AI-NATIVE SERIES Β· Architecture

One Loop, Forty-One Commands: how a tool grows without becoming a junk drawer

A tool I maintain has forty-one subcommands and one control loop. The engine is 109 lines. Adding a capability costs three functions. Here is the pattern, the worked example, and the three rules that stop an addon system from rotting β€” none of which require the tool.

One Loop, Forty-One Commands β€” the engine is 109 lines, a new capability costs 3 callables, 41 capabilities shipped.
The whole argument on one card. The interesting number is the middle one.

1-minute takeaway

What this is: the architecture of a personal AI tool that has grown to 41 commands without turning into a drawer of unrelated gadgets β€” one shared control loop, and capabilities that plug into it.

Why it matters: the junk-drawer failure is not a coding problem, it is what happens to every growing system β€” a team, a curriculum, a company's processes β€” when each new need gets its own machinery instead of a costume for the machinery you have.

What you can do: take a decision you are facing this week, write it as four fields, and compute one line of arithmetic by hand. Twenty minutes. You will likely find your plan is resting on something weaker than you thought.

Context: one loop is the whole idea, and this is not about my tool

Everything below comes from one codebase, and almost none of it is about that codebase. The tool is private and you cannot install it, which is the honest constraint I wrote this under: if the value of an article depends on the reader obtaining the thing it describes, it is a brochure. So the test I set myself was that every principle here should survive the sentence "…and I will never see that repository."

The subject is a problem you already have. You maintain something that grows β€” a codebase, a team's process, a course you teach, a household's systems. Each new requirement arrives looking unique. And the path of least resistance, every single time, is to build it its own machinery.

The failure mode: a new machine for every need

The failure has a shape. Each new requirement arrives looking unique, so it gets its own machinery: its own loop, its own retry rule, its own idea of what "done" means, its own logging that is subtly different from the logging beside it. Six engines where one would do. (The kitchen version is a counter covered in single-purpose appliances, each with its own motor to break, versus one stand mixer with dumb attachments β€” but the analogy is an on-ramp, not the argument, so I will leave it there.)

Nobody decides to build a junk drawer. A junk drawer is what you get when nobody decides not to. And the cost is not the clutter β€” it is that improving any one thing improves only that thing. With a shared engine, every capability gets better at once.

The compression: four capabilities were one capability in four costumes

The turn in this story is not a clever idea. It is a boring discovery made while reading my own code.

There were four separate loops β€” one that improved a generated app, one that refactored a codebase, one that reverse-engineered an artifact, one that mined a vague complaint for a product. Four different domains, written months apart, feeling completely unrelated.

They were the same function. Not similar β€” the same, down to a guard clause that appeared verbatim in all four, character for character, rejecting a zero iteration count. I had written the identical defensive line four times without noticing, which is the most reliable signal that a thing wants to be extracted: not that the code looks alike, but that you keep independently reinventing the same small precaution.

Underneath every one of them was this:

Start somewhere. Propose a candidate. Score it against something outside yourself. Keep it only if it is better. Repeat, with a hard limit, recording every step. Stop when you hit the target or stop improving.

That is it. That is the motor. Improving an app, cleaning a codebase, taking apart a competitor's product, choosing a strategy, auditing a system for security β€” all the same shape, and the differences are entirely in three questions: what counts as a candidate, what counts as better, and what counts as allowed.

Diagram: one loop β€” seed, propose, score, accept, stop and log β€” shared by four capabilities (strategy, refactor, brace, refine), each supplying three callables.
The controller is written once. Each capability supplies three functions and inherits the bound, the trajectory and the stop condition for free.

The engine, small enough to read

The shared controller is 109 lines including its documentation. Its core is roughly:

best = seed
best_score = score(best)

while best_score < target and iterations_left:
    candidate = propose(best, i)
    candidate_score = score(candidate)
    if accept(candidate, candidate_score, best, best_score):
        best, best_score = candidate, candidate_score
    record(i, candidate_score, accepted)

Three things are load-bearing, and each one is a rule you can carry into any domain.

The bound is not optional. The loop cannot be constructed with a limit below one. Not "should not" β€” cannot; it refuses. Any process that can propose can run away, and the place to stop that is the constructor, not a code review.

The scorer is never the proposer. The thing that makes a candidate may not be the thing that grades it. In the strategy attachment this is enforced at construction: pass the same function for both and it raises, with the message "never self-certify". This is the rule people break constantly outside of software β€” the team that writes the plan also reports on whether the plan worked.

Every step is recorded, including the rejected ones. The trajectory is the output, not a debug artifact. Knowing the answer is worth much less than knowing what the answer beat.

Rung 1 β€” do this before reading on (2 minutes)

Pick any repeating process you own: hiring, a weekly review, editing drafts, choosing suppliers. Name its three functions out loud. Propose: where do candidates come from? Score: what, precisely, decides that one is better β€” and is it outside you? Accept: what would make you keep a candidate that scored worse?

Most people find the second one is missing. That is the finding, not a failure of the exercise.

The worked example: deciding what to do

The newest attachment is the one I will show in full, because strategy is the domain where fake rigour is most common and easiest to hide.

You hand it a brief with four parts: an objective, the success criteria that would mean you achieved it, the evidence you actually hold, and the options you are weighing. Each piece of evidence is tagged with how you know it: measured, documented, prior (someone else's data, not yours), or judgment (you reckon).

Then it runs the loop. Propose = add the option that covers the most so-far-uncovered criteria. Score = one line of arithmetic. Accept = strictly better, and legal.

Here is the whole scoring rule, and it is the part worth stealing:

score = (criteria covered / all criteria) Γ— weight(weakest evidence)

          measured 1.00 Β· documented 0.90 Β· prior 0.75 Β· judgment 0.50

Coverage is what you achieved. The tier weight is how much you are entitled to believe it. And they multiply.

That multiplication is the entire opinion of the tool, so let me defend it. If you average them, a plan that covers everything on pure guesswork comes out looking like a slightly weaker version of a plan built on measurement β€” eighty-something percent as good. That is false. It is not a weaker claim of the same kind; it is a different kind of claim. Multiplying says so: full coverage at judgment tier caps at 0.50, no matter how complete it looks.

Run the shipped example β€” a real decision about cutting new-engineer onboarding time β€” and it picks three options, covers 4 of 4 success criteria, and scores 0.75. Full marks on coverage, and it still loses a quarter of its score, because one of the three options rests on an industry benchmark rather than anything measured in-house.

The output says so out loud:

score 0.750 at prior tier Β· 4/4 criteria Β· stopped on plateau
   βœ“ devcontainer for the five main repos        [documented]
   βœ“ CI gate on stale setup docs                 [documented]
   βœ“ golden-path starter task                    [prior]
   β†’ the claim is only as strong as its weakest evidence: prior

A plan that covers everything and tells you it is resting on a magazine article is worth more than a plan that covers everything and says nothing. The discount is the product.

Two more behaviours, both of which are moral positions disguised as engineering:

A hard constraint halts; it does not cost points. One option in the example crosses a stated boundary β€” it would give new hires production access on day one. The loop does not subtract from its score and let a sufficiently attractive plan buy its way past. It stops, and says a human must sign this off by name. Anything that can be outweighed will eventually be outweighed by a number someone wanted badly enough.

The arithmetic is deliberately dull. No language model runs at decision time. Same brief, same answer, forever β€” and a reviewer can recompute the score with a pencil and catch the machine lying. A recommendation you cannot recompute is not evidence, it is an assertion with good posture.

Rung 2 β€” the twenty-minute version, no tool required

Take a real decision you are facing. On one page write: the objective Β· 3–5 criteria that would mean success Β· every option you are considering Β· and beside each option, which criteria it covers and how you know (measured / documented / someone-else's-data / you reckon).

Now compute: fraction of criteria covered Γ— the weight of your weakest evidence. That number is your plan. Most people's first honest run lands between 0.35 and 0.55, and the gap is almost never coverage β€” it is that the whole structure is resting on one unmeasured assumption nobody had named.

Four more capabilities, same loop

The pattern's value is that the next capability is boring to add. Four short ones:

Refactor a codebase. Propose a code change, score its structural quality, and accept only if the tests still pass β€” otherwise roll it back. The acceptance rule is where the safety lives. A quality score alone would happily improve the shape of a broken program.

Audit a deployment against a security standard. This one is the best demonstration that the pattern is not really about software. A published control rubric looks like a questionnaire. It is a scorer. Once you see that, the rubric becomes the score function, the loop autonomously gathers evidence for each item, and a compliance document turns into something that can fail a build. Any checklist, standard, or scoring guide you have ever been handed is a closed loop someone stopped building halfway.

Score a system's enterprise readiness. Seven pillars, and every gap prints the exact command that closes it. A finding with no next action is a complaint.

Reflection, as a measured practice. This is the one that keeps the whole thing honest. It holds a ledger of predictions with probabilities and due dates, scores them when they resolve, and expires conclusions so beliefs get re-tested rather than accumulating. A weekly review asks how you feel it went. A Brier-scored ledger asks whether you were right, and remembers.

Three rules that keep an addon system from rotting

Addons are how most systems die. Browser extensions, enterprise software, a team's process documents, the "miscellaneous" folder. Three rules have held so far.

Rule 1 β€” a new capability may not bring its own loop. If your capability needs its own loop, you have not finished understanding it. This is a strong claim and it is occasionally wrong, but it is wrong far less often than it feels in the moment, and the failure mode it prevents is worse than the friction it causes.

Rule 2 β€” cross boundaries through a seam, never an import. The strategy attachment writes its decision graph somewhere. It has no idea where. It holds a port β€” an abstract interface β€” and a separate adapter connects it to a real store. Swap the store, change nothing else, run the identical test suite against both bodies.

David Parnas wrote the reason for this in 1972, and it has not been improved on:

"Its interface or definition was chosen to reveal as little as possible about its inner workings."
β€” D. L. Parnas, On the Criteria To Be Used in Decomposing Systems into Modules, CACM 15(12), 1972 [R1]

His argument was not aesthetic. He was making a prediction about change: begin with the design decisions most likely to change, and hide each one inside a module so that when it changes, the change stops there. Fifty-four years later, the decisions most likely to change in my tool are exactly the ones behind seams, and I did not plan that β€” I discovered it by getting it wrong in the places I had not.

I got a live demonstration while building the strategy attachment. I connected it to a strict graph store that belongs to a different repository of mine, and its integrity rules rejected my write: decision nodes are human-authored only. I had modelled a slate of candidate options as a "decision". It is not one. A loop proposing candidates is doing analysis; deciding is something a person does. The rule was right and my model was wrong, so I changed the model. That is what a real seam buys you β€” the thing on the other side is allowed to refuse, and its refusal is information.

Rule 3 β€” the system must be able to say no to its owner. More on this next, because it is the rule everybody agrees with and nobody implements.

Rung 3 β€” the uncomfortable one (10 minutes)

Find one rule in your work that currently lives in a document, a norm, or your own good intentions β€” "we don't ship on Fridays", "every claim gets a source", "no vendor without two references".

Make something refuse. A test, a checklist item someone must physically tick, a form that will not submit. Then try to violate your own rule and confirm you are actually stopped. A rule that cannot fire is a preference wearing a uniform.

The part that makes the rest believable

Here is the section I would skip if I were selling you something.

Two commands appear in this tool's own manual with a warning label: NEITHER IS BUILT β€” these are wants, not capabilities. They were described in documentation before they existed, and instead of quietly deleting the paragraph, the paragraph stayed and grew a warning. It is one of the most useful entries in the manual, because its job is to stop a future version of me from confidently offering a feature that does not exist.

And the sharper one. The system was documented as having a self-improvement loop that banked a lesson after every session. It said so in the manual. What it actually had was a file, lessons.jsonl, frozen at 42 entries β€” untouched across roughly twenty-three shipped pieces of work, while the documentation cheerfully described a loop that was running.

A loop that was documented but never built is indistinguishable from one that quietly broke. That is the whole lesson, and it generalises brutally: every process your organisation believes it has, and has never watched fire, is in this state right now. The onboarding checklist. The post-mortem follow-ups. The quarterly access review.

I checked that file again while writing this paragraph, to be sure I was not quoting a fact that had since been fixed.

It is still 42.

Which is, I think, the most honest sentence in this article β€” and it stays in, because a piece about building trustworthy systems that quietly omitted its author's unfixed gap would be demonstrating the opposite of its thesis.

Patterns and anti-patterns

PatternAnti-pattern it replaces
One controller; capabilities supply three functionsEach capability brings its own loop, retry rule and logging
The bound lives in the constructor and refuses"We'll add a timeout later"
Scorer and proposer are provably different objectsThe team that wrote the plan reports on the plan
Evidence quality multiplies the scoreConfidence averaged in, so guesswork dilutes instead of capping
Hard constraints halt for a humanHard constraints priced as a penalty, so a big enough number buys past them
Cross boundaries through a port with two live implementationsDirect import, so the dependency can never refuse or be swapped
Rules that execute and fail the buildRules in a document nobody has watched fire
Deliberately dull arithmetic a reviewer can recomputeA model in the decision path, so the answer moves and cannot be audited

The first principle, in one sentence

Capability should cost three functions, not a new machine β€” and whatever you build must be able to refuse the person who built it.

What to do in the next twenty minutes

DoHow you know it workedBy when
Name propose / score / accept for one repeating process you ownYou can say all three in a sentence, and the scorer is not youToday, 2 min
Write one real decision as objective Β· criteria Β· options Β· evidence-with-tiersOne page; every option says how you knowThis week, 20 min
Compute coverage Γ— weakest-tier weight by handYou have a number between 0 and 1, and you can name what is capping itSame sitting
Convert one written rule into something that refusesYou tried to violate it and were actually stoppedThis week, 10 min
Pick one process you believe runs automatically, and check its output timestampYou know the last time it fired, from evidence and not memoryToday, 5 min

The last row is the one with the highest hit rate. I would bet on you finding at least one silent 42.

References

  1. Parnas, D. L. (1972). On the Criteria To Be Used in Decomposing Systems into Modules. Communications of the ACM 15(12), 1053–1058. PDF β€” quoted verbatim above; verified 2026-09-29.
  2. Conway, M. E. (1968). How Do Committees Invent? Datamation. melconway.com β€” "organizations which design systems (in the broad sense used here) are constrained to produce designs which are copies of the communication structures of these organizations", verified verbatim 2026-09-29. Why it belongs here: a junk drawer of capabilities is usually a picture of a team that never had one conversation about the shared motor.
  3. Brier, G. W. (1950). Verification of Forecasts Expressed in Terms of Probability. Monthly Weather Review 78(1), 1–3. The scoring rule behind the prediction ledger described above.

Written by Paul Jialiang Wu. Every figure in this piece was read off the codebase on 2026-09-29: 41 subcommands, 8 loops, a 109-line shared controller, 1,035 passing tests, and one lessons file still sitting at 42. The tool itself is private, which is why nothing here requires it. Statement classes: the numbers are measured, the three rules are design positions, the claim that they transfer to non-software domains is an inference I would like to be argued with about.