!
This article is a reprint from Claude Code Hajimemashita.
When They Say "It's Done," Nothing Is Done
When letting AI do development, I used to write the schedule in Markdown. I would list tasks as checkboxes and have the AI check them off when finished. I think it's a common approach.
But this doesn't work properly.
When I'm told "it's done" and go to check, half the checkboxes aren't filled. The features they said they'd implement aren't there. When another issue comes up during the work, a new Markdown file appears. After a while, files that are neither a schedule nor notes are scattered around, and I lose track of where things stand. Something is progressing, but when I ask for status, I can't get a clear picture.
What AI Can Write Doesn't Constrain AI
The reason is clear.
The Markdown schedule is written by the AI itself and read by the AI itself. Anything that can be rewritten cannot serve as a constraint for the one who rewrites it. The real substance of the tasks resides in the AI's memory, and the Markdown is just a copy. As the conversation grows longer and the memory gets compressed, the real substance disappears first, leaving only the copy behind. Looking at the remaining copy, the AI says, "This much is done." It has no awareness that it's lying. At that point, the information that checkboxes are "unchecked" simply doesn't exist within the AI.
The proliferation of Markdown files stems from the same issue. When another task emerges during work, incorporating it into the existing schedule requires reassessing dependencies. Creating a new file is instantaneous. So the cheaper option is chosen.
What I Wanted Was Parallel Execution
What I really wanted was to run multiple AIs simultaneously.
With Claude Code or Codex, as long as you run them sequentially with a single agent, the waiting time accumulates with each task. Running them in parallel would finish faster. But since multiple agents are touching the same code simultaneously, if you get the task partitioning wrong, the second and third agents will fight over the same file, and one change will overwrite another.
The method to avoid conflicts is well-known: partition tasks so that they touch different areas. The problem was that I was relying on human intuition to determine that partitioning. I would read the task descriptions and decide, "These two should touch different parts, so they can run in parallel." When I got it wrong, things broke after launching.
Measure the Impact Area, Separate If They Overlap, Then Distribute
So I built a tool called Lattice. Here's what it does:
- Compare the task descriptions with the code structure to estimate which parts of the code each task will touch.
- Output tasks with non-overlapping estimated areas as combinations that can run simultaneously.
- If they overlap, determine if refactoring can separate them. If so, refactor first. Verify that behavior remains unchanged, then re-measure the areas.
- Based on the re-measured results, rebuild the schedule itself.
The third step is central. Task management tools typically arrange tasks in order based on the assumption that the code structure cannot be moved. If they overlap, you just do them sequentially. Lattice moves the code instead. If multiple tasks compete for the same area, it changes the code first so that competition is no longer necessary.
Code changes are performed inside disposable working copies (git worktrees). The original branch is untouched. If verification passes, the changes are accepted; if not, they are discarded. When the code changes, any previous schedules and task descriptions given to the AI are invalidated, and a new version is created. If an AI is still running on old assumptions, it would cause breakage.

Part of the dependency task diagram generated by Lattice. Cards are tasks, thin lines are dependencies, thick lines are the longest dependency chains.
This diagram was not drawn by hand. It is automatically assembled from dependencies the moment tasks are registered in consultation with the AI.
Moved Tasks to a Place the AI Cannot Rewrite
To measure impact areas, tasks need to be in a machine-readable format. Markdown text cannot be measured. So Lattice stores tasks in a dedicated repository.
By placing tasks in this repository, conditions can be attached to writes.
Completion requires evidence. To mark a task as done, you must attach a description file pointing to the results and a Git object. When writing, the system checks whether the actual results exist; if not, the write is rejected.
Who wrote it is required. Any operation that changes state requires three identifiers – host, session, and agent – to be present in environment variables. If even one is missing, it is rejected with ACTOR_UNRESOLVED, and the repository does not change by a single byte.
Partial rewrites are not allowed. To change the task structure, you must create the complete new version and submit it as a single transaction. There is no syntax to conveniently delete a single inconvenient entry. If a task that previously existed disappears without evidence, the write is rejected.
Phases do not close without approval. Even when all tasks under a phase are complete, the phase remains in a gate_ready state. To proceed further, you must leave a record and evidence of confirmation.
None of these rely on telling the AI to "be careful." I moved the tasks to a place where writes do not succeed unless these conditions are met.
Let's try writing a completion without the identifiers:
lattice todo done --plan phase-control-live-gantt --task 020 --evidence .lattice/evidence.json
The response is this, and the task is not marked complete:
{
"schema": "lattice.cli_error.v2",
"code": "ACTOR_UNRESOLVED",
"message": "actor_environment_invalid",
"detail": {
"reason": "actor_environment_invalid",
"required_environment": ["LATTICE_TODO_ACTOR_HOST", "LATTICE_TODO_ACTOR_SESSION", "LATTICE_TODO_ACTOR_AGENT"],
"missing_environment": ["LATTICE_TODO_ACTOR_HOST", "LATTICE_TODO_ACTOR_SESSION", "LATTICE_TODO_ACTOR_AGENT"],
"invalid_environment": [],
"next_action": "set_required_actor_environment_and_retry"
}
}
It actually returns in a single line. It tells you what is missing and what to do next, in a machine-readable format. If you take the hash of the repository file before and after, it remains the same value.
I don't recall individual cases where evidence was insufficient and got rejected in operation. Since I have a rule in dotagents (a system that manages my tools collectively) that any inconvenience in tools should be fixed on the spot, I kept fixing Lattice whenever I found a bottleneck. The first commit was on July 15th; 12 days later, 731 commits, version 0.29.0, and 89 design decision records. Meanwhile, the thing I really wanted to build is still on hold, though.
I Don't Know If It's Faster
I haven't measured whether it's faster in parallel. There are cases where it might be faster to just have the AI write tasks roughly in Markdown rather than structuring them and measuring impact areas. I don't have numbers on how much time was saved.
What clearly changed is that the tasks I said would be done actually get done. Tasks are not skipped. The number of times I'm told something is done when it isn't has clearly decreased.
Filed a Patent
I filed a patent for this mechanism. Filed on July 27, 2026, with application number Tokugan 2026-178950, invention title "Information Processing Device, Software Development Control Method, and Program," with 12 claims.
The core is: estimate impact areas from task descriptions and code structure; if they don't overlap, run them in parallel as is; if overlapping can be eliminated by refactoring, do that first and then run them; then execute multiple development agents simultaneously based on that plan. The actual Claim 1 reads as follows:

Claim 1 of the filed patent claims.
The patent application also covers what happens next: if a conflict occurs during parallel execution, stop the affected tasks and re-plan the stopped area. By observing the actual changed locations, if they go outside the estimated area, treat it as a runtime conflict. This part is also implemented and I'm refining it while testing.
Current Status
The task storage is the authoritative source; I don't keep tasks in Markdown. To know the current status, I ask the tool.
lattice status --json
lattice todo status --json
Progress is viewed in the task diagram. I can start a live view that updates even while viewing.
lattice todo gantt serve --port 0

Full view. 74 tasks and their dependencies fit into one image.

Right half of the screen. Shows breakdown of task status, number of tasks that can be started simultaneously right now, and audit progress per phase.
The right half shows the breakdown of task status and audit progress per phase. locked indicates waiting for audit order. Task start is determined solely by dependencies, so even tasks belonging to later phases can start if their prerequisites are met. Multiple phases can progress simultaneously.
Whether taking task management away from the AI is the right approach, I won't know until I use it more. For now, it's working in my environment.
Top comments (0)