The Work Package
Decompose intention into bounded assignments machines can complete and applications can absorb.
Chapters 02 through 05 established the conditions for machine coding: dependable foundations, configured intelligence, discovered intent, and an understood world. This chapter addresses what happens next — the daily practice itself. A goal exists, the machine is ready, the system is known. What, exactly, do I give the machine to do?
The answer I have arrived at, through enough failed attempts to respect the question, is the work package: a bounded engineering assignment that a machine can complete and an application can absorb. This chapter is about the skill of decomposing an intention into such pieces, directing their execution, and making the results accumulate into one coherent, working application.
That skill is, I believe, the new programming. Not writing instructions for a computer — organising machines that write them, and ensuring the thousands of things they produce become one thing that works.
The new programming problem
Generating code is no longer the bottleneck — in my machine-coding practice with sufficiently capable coding AI, at least. Any such model can fill a screen with plausible implementation in seconds, and for some kinds of development that is genuinely the hard part done. But where the work is to change a living system correctly, the bottleneck is knowing what work should happen next, communicating it sufficiently well, verifying what came back, and making sure the result contributes to the same application as everything that came before.
I have watched this failure from the inside. A session produces an impressive volume of code — new endpoints, new tables, new components — and the application is no further forward. Each piece works in isolation; together they disagree about names, duplicate each other’s responsibilities, bypass the established patterns, and leave integration to some unspecified later. The machine did everything it was asked. What it was asked was not the work the application needed.
This is the distinction on which the chapter turns. Local success is an implementing machine completing a package and producing evidence that it satisfies the specified contract. Application success is that completed work integrating with existing components, advancing the intended capability, preserving system constraints, and contributing to the user’s actual goal. These are not interchangeable. A package may pass its tests while the application remains broken. I must manage both levels, continuously, because nobody else in the loop will.
Start with goals, not tasks
I never begin by asking the machine for artefacts — twelve endpoints, three tables, a component. I begin with what the application must accomplish, and I work downward:
Product intention → Goal → Capability → Component → Work package → Integrated behaviour.
A goal describes something the product must accomplish, in user terms: a developer can change files in an approved project without repeatedly losing access, while the security restrictions stay intact. A capability is a function the system needs to provide that goal — stable authorisation, live revision resolution. A component is reusable software structure that delivers part of a capability. A work package is the bounded assignment through which a component is built or changed. And integrated behaviour is the only thing the user ever experiences.
This is a thinking tool, not a taxonomy to enforce. Small efforts may collapse levels; large ones may need all of them. Its purpose is traceability: I should be able to follow any piece of machine-written code upward to the user outcome it serves, and follow any goal downward to the packages that implement it. Work that cannot be traced in either direction is work I should question before commissioning.
Before any of that decomposition, one question comes first: is this goal worth pursuing at all? A goal earns packages when it serves the product intention, when its value justifies the integration and review it will consume, and when no existing capability already provides it. Machines make it cheap to start things; that cheapness is precisely why the decision to start must stay expensive. I have learned to ask, for every candidate goal, what user outcome it changes and what I will stop doing to pay for it. A goal that cannot answer is not a goal yet — it is an idea awaiting exploration, and Chapter 04 is where it belongs.
Build on what you already know
One of the costliest avoidable mistakes in machine coding is asking the machine to create what already exists. Before any package is designed, I establish what the repository already offers: architecture, prior decisions, accepted components, reusable services, interfaces, tests, and implementations the machine can read and follow.
ALIVE has taught me this twice in documented form. The WF-01 reuse investigation found that the existing workflow runner could already invoke capabilities under grants, feed stage outputs into later inputs, and persist runs, stages, and artefacts — so the design called for narrow adapters rather than a new orchestration system. WF-03 did the same against a harder problem: existing workflows, persistence, source authority, and evaluation were mapped concern by concern, and only the genuinely missing behaviour — a character-span planner over exact corpus text, a whole-chapter context mechanism — was specified as new work. In both cases the investigation preceded the assignment, and the assignment shrank because of it. WF-03 adds a further lesson in honesty worth copying: the experimental stack, with its two failing revocation regressions, was explicitly paused and retained on a separate branch rather than merged or assumed. Unfinished, failing work was kept visible and kept out of the way — recorded, not hidden, and never allowed to contaminate packages that depended on settled ground.
I stress the direction of that reasoning. Reuse must be demonstrated, not assumed: two components with similar names may carry different authority or lifecycle requirements, and pointing a machine at the wrong predecessor is worse than pointing it at nothing, because the result arrives looking idiomatic while violating the constraints that matter. Every accepted component becomes a reference that makes future packages easier to define and easier to review — but only if the reference is real, inspected, and named exactly.
A work package is not merely a prompt
A prompt is a message I send to a model. A work package is a durable engineering assignment that survives the model that receives it. Another intelligence — human or machine, tomorrow or next month — should be able to pick it up and understand what is being asked without reconstructing the entire conversation that produced it.
My standard package contains ten elements. Each earns its place by answering a question the implementer would otherwise answer by guessing:
- Goal: why does this change exist, and which capability does it serve?
- Existing reference: what code, capability, contract, or precedent must be reused or followed?
- Required behaviour: what must change, and what outcome is expected?
- Scope: what may the worker modify — and what is out of bounds?
- Invariants: what behaviour, constraint, or security property must remain true throughout?
- Dependencies: what must already exist or be completed first?
- Acceptance criteria: what would establish that the task works?
- Required evidence: what tests, outputs, inspection records, and observations must be retained?
- Escalation conditions: when must the worker stop, ask, or return the package to design rather than improvise?
- Integration: how does the result become part of the application — where it is wired in, what verifies the wiring, and who accepts it?
The charters from earlier chapters feed the package without being copied into it. The Foundation Charter supplies the defaults; the AI Configuration Charter supplies the model assignment; the Intent Record supplies the why; the System Charter supplies the boundaries. The package itself carries only what this task needs, with pointers to the rest. A package that drags the whole charter along is not thorough; it is unfocused, and unfocused context is where misunderstandings breed.
Here is a compact example, labelled illustrative — the shape of a real
assignment, not a record of one. Suppose the live-source binding from
Chapter 05 needs its revocation path hardened: today revocation blocks
the central workspace path, and the task is to extend that guarantee to
legacy callers without changing authorisation semantics. Writing that as
one package immediately exposes the problem: I cannot name the target,
because I have not verified which callers bypass the live-aware path.
The report states the gap plainly — direct legacy callers passing old
approval references were never individually audited — and the central
path I can verify (_source_for_runtime in alive/workspace_api.py,
resolving through source_live.resolve_current unless the
EXACT_CAPTURE opt-out applies) does not tell me about the rest. So the
honest assignment is a discovery package first:
Goal: know exactly which source-consuming paths resolve the binding and
which still use old exact-revision behaviour. Existing reference: the
central _source_for_runtime path and the report’s own limitation list.
Required behaviour: enumerate every approval_ref consumer, classify
each as binding-aware or legacy, and report the classification with file
and function names. Scope: read-only inspection; no behaviour changes.
Invariants: nothing is refactored on suspicion. Acceptance: a complete
list, each entry evidenced by the code that proves its classification.
Escalation: stop if a path cannot be classified without running it.
Integration: the list becomes the dependency map for the implementation
packages that follow — which is precisely the point.
Only then does the implementation package I sketched earlier become writable: a named caller, a verified current behaviour, tests that can fail for the right reason. This is the chapter’s distinction in miniature. “Harden revocation everywhere” is a goal. “Classify every approval_ref consumer” is a package ready for execution. Jumping straight to implementation would have asked the machine to discover the architecture — the exact failure Chapter 03 warns against — and the result would have looked complete while leaving unaudited paths untouched.
Notice what the package does not contain: no architecture to invent, no permissions to reinterpret, no open design decisions. Everything the implementer must decide is bounded; everything unbounded has somewhere to go — back to design.
How large should a package be?
Sizing is judgement, and it is among the hardest judgements in this book. A package too large overwhelms the implementer: requirements blur, unrelated systems get modified, assumptions hide inside volume, and the result can look complete while failing integration in ways nobody can locate. A package too small wastes the developer’s scarcest resource — attention — on issuing instructions, coordinating dependencies, and reviewing trivialities.
My principle: small enough to understand and verify; large enough to deliver a coherent change. Sometimes that is one function. Sometimes it is a component across several files. Sometimes a cross-cutting security change is too interdependent to divide safely, and the honest response is a larger package with stronger review rather than a false decomposition.
Size moves with circumstances. A capable model with generous, well-chosen context can absorb more; a coupled architecture demands less per package because every change touches shared assumptions. Where verification is cheap and thorough — fast tests, clear oracles — packages can grow, because mistakes are caught quickly. Where review is the bottleneck, they should shrink, because each package must earn scarce human attention. Knowledge cuts both ways: a well-mapped subsystem with strong precedents supports larger assignments, while unfamiliar territory calls for small probes whose failures teach cheaply. Parallelism follows the same logic: independent packages with stable interfaces can proceed together, but packages that share changing interfaces or data models must be sequenced, or their parallel products will disagree. I do not prescribe numbers of files, functions, or tokens. I prescribe the question: can I verify this as one thing, and does it mean something as one thing?
Hand work to the appropriate intelligence
This chapter assumes Chapter 03’s allocation and applies it. The designing intelligence — the one that produced the package above — does the architectural thinking: understanding the system, discovering references, settling contracts, anticipating integration risks. The implementing intelligence executes within those decisions. Independent review then examines the result against the package and the actual system, in a separate context.
The failure mode to watch is the package that asks the implementer to redesign. The signs are recognisable: the worker questions settled contracts, invents new abstractions unprompted, or returns asking for decisions the package should have contained. If the worker must rediscover the architecture to proceed, the package was not finished; it was abandoned halfway through design. The remedy is never to demand more brilliance from the same worker. It is to improve the context, redraw the boundary, supply specialist tools, or assign a more capable model — the escalation ladder from Chapter 03, applied at the point of failure rather than after three futile retries.
Keep the whole application moving
This is the chapter’s most important practical section, because it is where machine coding most often fails in practice. A sequence of locally successful packages can still leave an application inconsistent, incomplete, or unusable. Dependencies between packages must be honoured; established interfaces preserved; duplicate components refused at birth; parallel changes kept compatible; accepted work integrated promptly; and the application kept usable throughout — a system that only works after everything lands is a system nobody can evaluate until it is too late to steer.
Discoveries must travel to the right destination. A finding about the architecture returns to design; a finding about the purpose returns to intent. What must not happen is silent absorption: the implementer noticing a better structure and rebuilding toward it without authorisation, so that the application drifts one unreviewed improvement at a time.
The most practical moment in this whole discipline is the one right after a package reports completion. Take the restart improvement from the final section as it might actually unfold. The implementer reports done: tests pass, the review finds no bent invariants, the game demonstrates the transition. I do not assign the next attractive feature — persistent high-score tables, say — because attraction is not a scheduling principle. I work the decision instead. First, the delivered behaviour against the acceptance criteria: the transition itself meets its narrow contract, so that package stands accepted — but play-testing shows scores from the abandoned run leaking into the restarted game. That leak does not retroactively fail the accepted transition package; it exposes a requirement the original contract omitted, namely that score state also resets. The omission lives at capability level: reliable restart is still unfinished. Second, the correction this implies is a new package scoped to score-state initialisation, with its own tests — not a reopening of the accepted work and not a new feature. Third, the goal and its dependencies: reliable restart remains the open capability, nothing blocks the correction, and the leaderboard can wait. So the next package is the score-state correction, chosen because it completes something unfinished rather than because it shines. That is the whole method for choosing the next package: compare, verify, reassess the goal, clear the blocker or finish the capability, and only then reach for anything new. Acceptance is precise about what it covers, which is exactly why the remaining gap is visible instead of hidden inside a vague approval.
The unit of progress is the integrated capability, not the completed package. I work toward moments when I can demonstrate something the application can now do that it could not do before — a vertical slice of real behaviour, however thin. An enormous backlog of completed but unintegrated work is not evidence of progress; it is inventory, and inventory rots. ALIVE’s PI-03C delivery is the documented form of this discipline: substantial deterministic work delivered explicitly as a draft not qualified as the milestone, with acceptance blocked on named gates and a direct instruction never to merge on author tests or green CI alone. Implemented is not accepted, and the paperwork says so. Completion of a package is not completion of a capability, and completion of a capability is not necessarily completion of the goal. A package is not accepted because its implementer reports it finished. It is accepted when its evidence, its review, and its integration all check out.
Evaluate and correct continuously
Every package execution is an attempt submitted to the master loop of this book: communicate, build, evaluate, improve. The first implementation is a hypothesis about what the application should gain, and hypotheses get tested. Tests examine the behaviour. Review examines the requirement, the boundaries, and the system effects. I examine the result directly wherever the behaviour is something a person can judge.
What each failure becomes depends on where it lives. An implementation defect becomes a bounded correction package. A scope defect returns to the package design. An architectural defect returns to design proper. A context defect returns to the System Charter. An intent defect returns to exploration. The correction always goes to the level that caused it — which is why the levels exist. Blind repetition of the same request is not persistence; it is the refusal to diagnose, and it reliably converts a small defect into a large token bill.
Preserve the application between sessions
A machine-coding application will be built by many models across many conversations, branches, sessions, and days. It must not depend on any one of them remembering anything. I keep three lightweight durable records, in plain Markdown, aligned with the repository they describe:
Application map: what exists, how components fit together, which interfaces and patterns are authoritative, which architectural decisions stand. This is the newcomer’s orientation and the reviewer’s baseline.
Package record: for each package, what was requested, which sources were referenced, what the scope was, what actually changed, what tests were run, what the review found, and what acceptance evidence closed it.
Next-work plan: what still needs doing, what is blocked and on what, which dependencies determine the next useful package, and where the next integration milestone lies.
These records mirror the actual repository and its retained evidence; they are never a second truth allowed to drift. Drift is the specific disease to watch for: a map describing components that no longer exist, a package record claiming tests that no longer run, a plan pointing at milestones the architecture has abandoned. I detect it the same way I detect anything else — by checking, periodically, whether the records still describe the world, and by treating every accepted change as an obligation to update the records it touches. A map nobody maintains becomes folklore; a plan nobody reads becomes ritual. Small, current, and consulted beats comprehensive, stale, and ignored. When the next worker — model or human — starts from these pages rather than reconstructing the world, the system is working: continuity across different models, sessions, and days, purchased with the cheapest currency available, which is writing things down.
The real measure of speed
There is a temptation, sharpened by how fast machines produce code, to measure activity: lines written, calls made, tickets closed, packages completed. All of it can rise while the application stands still. I have seen the shape of it — a week of impressive throughput and nothing new the application can actually do — and the lesson survives every new model: the objective is not maximum machine activity but sustained progress toward a functioning application.
I weigh progress the way an owner would: accepted, integrated behaviours demonstrably working; time from goal selection to verified functionality; correction cycles and what caused them; the size of the unintegrated backlog; regressions introduced and caught; review findings and their severity; and, wherever possible, the intended user outcome shown working. Different projects will emphasise different items — a prototype values time-to-demonstration, a regulated system values review severity and traceability — and I claim no universal metric. What is not negotiable is the level of measurement: whatever is counted must be counted at the level of the application, not the package. And as established in Chapter 03, fewer review findings alone prove nothing; reviewer effort and detection effectiveness are part of any honest reading.
A package that produces a working improvement
To make the relationship concrete, here is the chapter’s method applied end to end — an illustrative walkthrough of the recurring arcade-game demonstration, not a report of work executed. Assume a small playable space-shooter already exists, created by a coding AI. It runs, but restarting after the player loses is poor: the game freezes on the final frame and the only recovery is reloading the application.
Goal: a player can restart a completed game reliably, in place, without reloading. Existing knowledge: the game already has an input handler, a game-state object, a scoring mechanism, and a rendering loop; restart must reuse all four, not duplicate them. Design: the minimum behaviour is a reset-to-initial-state transition triggered from the game-over screen, preserving the high-score table and honouring the existing input mappings. Package: implement the reset transition and its wiring; modify only the state-transition module and its tests; preserve the rule that scoring never mutates the high-score table except through the approved write path; add deterministic tests for reset correctness and high-score preservation, with explicit stop conditions if the state object cannot be reconstructed without broader refactoring. Implementation: the coding machine produces the transition and tests within those bounds — what it would produce, not a transcript of an actual run. Evaluation: the deterministic tests run, and a human play-test confirms that losing, restarting, and playing again behaves correctly across several attempts, including edge cases such as restarting mid-animation — which accepts the transition package against its narrow contract. Improvement: extended play then reveals that scores from the abandoned run leak into the restarted game. That leak does not fail the accepted transition work; it exposes an omitted requirement — score state was never in the original contract — so it becomes a correction package at capability level, scoped to score-state initialisation with its own tests, not a comment in the margins. Integration: the transition package is accepted when its tests pass, the review confirms no invariant was bent, and the game demonstrates the behaviour; the restart capability as a whole is accepted only once the correction lands too. The package record and application map are updated at each step, so the books always show which part is done and which part remains.
One improvement, fully worked, leaves the game better and the records truer. Repeat that a hundred times, across goals that matter, and you have an application — and, not incidentally, the method by which it was built.
Directing machines, building applications
A machine can complete an assignment. Only the developer can ensure the assignments collectively become the intended product. That is the skill this chapter exists to teach: decomposing intention into bounded, verifiable, integrable work; reusing what exists; sizing with judgement; allocating intelligence by responsibility; integrating continuously; evaluating honestly; correcting at the right level; preserving what was learned; and measuring progress where the user lives — in the working application.
The charters said what to build, with what, and under which constraints. Packages say who does what next, and how we will know it worked. What remains is the machinery of trust itself: proving, independently and repeatedly, that machine-made software deserves its place. That is the subject of the chapters ahead.