I started with one screenshot of a Data Rooms page that looked wrong.
That screenshot became an architectural migration spanning eleven pull requests. All eleven final heads had passed 22 CI checks. Thirty-four LiveView route patterns had moved onto the new application shell, ten legacy presentation modules were gone, and a permanent architecture guard prevented the old layer from creeping back in.
My visible contribution consisted mostly of prompts like these:
$ this is not newui is it ? diagnose
$ ok continue
$ what's the status here
That sounds like the setup for a breathless post about autonomous software engineering. It is not.
The agent did write and review a lot of code. But the interesting part was everything we had to build around the code generation before I could safely communicate at that level. The short prompts worked because scope, ownership, dependencies, tests, review state, CI, merge state and closure lived somewhere more durable than the chat.
That, for me, is what finding the groove with agentic engineering actually feels like. You stop managing keystrokes. You start designing the system in which an agent can make progress, prove what it did, get corrected, and know when the work is genuinely over.
It is less magical than the demos. It is also much more useful.
The unit of work is not code
The screenshot showed a page that technically ran inside our new application shell but still contained a mixture of old and new UI. Asking an agent to “fix the page” would have produced exactly that: one cleaner page and another layer of exceptions.
Instead, the first session traced the route, LiveView, layouts, components, Git history and existing issues. The staged migrations in our history had been reasonable. Complex space pages had deliberately been deferred. The problem was not one careless implementation; it was an architectural transition that nobody had yet finished.
So I changed the question from “can you restyle this?” to “what would it take to have only the new shell and canonical UI components everywhere in Data Rooms?”
The agent searched our issue history, reconciled overlapping work, inventoried 34 route patterns and created one self-contained epic with seven dependency-ordered children. Existing signing and PDF-viewer work stayed in its own chain rather than being reimplemented inside the migration. Stale tickets were superseded rather than silently forgotten.
The result was not a better prompt. It was an executable work graph.
observe a concrete mismatch
↓
diagnose architecture and history
↓
reconcile existing ownership
↓
write a self-contained dependency graph
↓
claim → test → implement → review → CI → merge
↓
verify closure → take the next unblocked issue
↓
delete the transition layer and prove it stays deleted
I cleared the session after planning. Thirty-one seconds later, a clean agent received only the epic and an execution contract. It found the first unblocked issue and started working.
That reset was deliberate. If clearing a chat destroys the plan, you do not have architecture. You have conversation history.
Aside: why we built harness-cli
Issue trackers are designed primarily for humans looking at boards. Agents need something closer to a state machine.
We built harness-cli so an agent can search, inspect, create, link, claim and close work without scraping a UI or treating an issue description as the whole truth. Dependencies are machine-readable. Claims are atomic. Closure is an operation with an explicit reason, not a checkbox somebody may or may not remember to click.
This mattered in ways that were not glamorous.
When the migration reached a signing dependency assigned to somebody else, Harness rejected the agent's claim with a conflict. The agent stopped. I explicitly changed ownership, and only then did it continue. Authority changed; scope did not. Each issue kept its own branch, PR, review boundary and history.
That is a small example of a much larger point: an agent should not infer permission from technical ability. The tool has to make ownership and authority real enough to block it.
Harness also gave us the outer loop. A merged PR did not automatically mean “done.” The agent verified that the issue had closed, checked the dependency graph again and only then claimed the next ready child. The parent epic closed after a final reconciliation of every child, retained blocker and superseded ticket.
Chat is a terrible database. The issue graph became the agent's durable memory.
The groove is outcome-level steering
Once execution started, I almost never told the agent which file or function to change.
I asked what was true. I told it to continue. I corrected review semantics when its assumptions were stale. I granted authority when ownership genuinely needed to move. The agent handled the implementation details inside those boundaries.
This is not “human out of the loop.” It is a different loop.
Traditional software management often decomposes work down to tasks a person can estimate and perform. With an agent, I increasingly steer at four levels:
- Outcome: What has to be true when we finish?
- Evidence: What would prove that it is true?
- Authority: What may the agent change, merge, release or take over?
- Continuation: Given the live state, what is the next unblocked action?
The agent can usually figure out the code. It is much worse at knowing whether a plausible local success is the same thing as the outcome I intended.
A passing test is not a merged change. A merged change is not a released change. An issue closed by commit syntax is not proof that its acceptance criteria were satisfied. A healthy production endpoint is not proof that the intended commit reached it.
The groove arrived when we stopped letting any one of those signals impersonate completion.
Review comments are hypotheses
The migration looked like UI work. The review process found cross-organisation identifier leaks, forgeable Google Drive events, stale authorization at mutation time, unstable selection identities, URL trust problems, lifecycle cleanup bugs and a two-tab race in one-click signing.
Some findings were real. Some were nonsense.
That distinction is the entire review problem with language models. Generating a serious-sounding concern is cheap. Establishing that it exists in the runtime path, reproducing it and proving the correction is expensive.
The rule became simple:
- A confirmed defect gets a reproducer, a fix, validation and review of the new commit.
- An unsupported claim gets an evidence-backed dismissal.
- A code change invalidates the verdict on the previous commit.
- A model's confidence and severity wording do not count as evidence.
This sounds obvious. It is surprisingly hard to maintain across a long-running agent session.
At one point the PDF-viewer PR reached “Round 15.” I asked what that actually meant and why we were doing so many. The answer revealed two things at once. First, the rounds had found real interactions involving trusted navigation, overlays, stale loads, cross-origin credentials and focus behavior. Second, our convergence process was wasting rounds re-litigating findings that had already been dismissed.
That led us to improve the tool while the delivery was running.
Aside: why we built RCL
RCL - Review Council - is our multi-model adversarial review tool. We built it because “ask a few models to review this diff” is not a review system.
RCL pins a review to an exact Git head, runs multiple reviewers, gives findings stable identities, deduplicates them across rounds and records whether each gating finding was fixed or dismissed. If the code changes, the old approval no longer applies. If a dismissed claim returns unchanged, the ledger remembers it. If reviewers disagree, the disagreement remains visible instead of being averaged into confident prose.
The exact-head constraint is the important bit. A review of commit A does not approve commit B, even if B contains only the fix requested by the review of A. That fix may be wrong or may break something else.
The finding ledger is nearly as important. Without it, multi-model review becomes an expensive goldfish: every round rediscovers the same concern, phrases it differently and demands another round to verify that the concern remains dismissed.
We eventually added a dismissal-only convergence path. If every new gating finding is disproved on an unchanged head and no code changed, the review can finish. There is no value in launching another set of models to prove that code we did not change is still the same code.
RCL is not there to make model output authoritative. It is there to make model output accountable.
The agent still needed babysitting
“Babysitting” is unfair to the amount of work the agent completed, but honest about the operational experience.
Long-running sessions accumulate stale assumptions. Tools change versions. CI flakes. An issue thought to be unowned turns out to sit in somebody else's active branch. A status request can be misread as an instruction to stop. A review rule that made sense yesterday becomes pathological after the review tool learns to deduplicate findings.
The steering was sparse, but it mattered:
- “What is the status?” forced a refresh of issue state, PR head, CI and review evidence.
- “Continue” distinguished an informational checkpoint from a terminal condition.
- “Two-thirds of reviewers is enough for a conclusive report” corrected an all-model health assumption.
- “Take these over” supplied authority the agent correctly refused to invent.
- “Show me the review history” exposed whether round 15 represented useful defects or process churn.
This is the part missing from most agent demos. The hard problem is not getting an agent to produce a convincing patch. It is keeping a long-running delivery aligned while the repository, issue graph, review state and external systems continue to change.
The answer was not a longer master prompt. It was frequent re-grounding against live state.
We also got the finish wrong
The final child deleted the remaining legacy modules and replaced a transitional debt manifest with a permanent zero-exception architecture guard. The agent ran the route matrix, tests, browser checks, CI and review, merged the PR, verified child closure and reconciled the epic.
Then it reported that nothing had been released to production because the execution session had no release authority.
That was wrong.
The session had not released anything, but separately authorized workflows had shipped parts of the dependency chain while it was working. Session authority and production history are different facts. The agent had correctly respected its boundary and still made an incorrect statement about the world.
A later audit found two review exceptions as well. One retained PR had merged after a final review round that fixed a real issue but never reached a clean exact-head verdict. Another independent PR had review evidence for an earlier commit, not its merged final head.
We corrected the record rather than sanding those details out of the story.
The final architecture, dependency order, CI results, merge ancestry, issue closure and zero-debt proof were verified. The claim that every piece had uniform clean review was not. The claim that nothing had reached production was not.
This is why I do not trust agent summaries simply because they are specific. Specificity is not provenance.
What “good” now looks like for us
I do not have a universal agentic engineering methodology. I have a set of scars that turned into rules:
- Start with the end state, not the edit. “Only AppNew and NewUI everywhere” created an architectural migration. “Fix this screen” would have created a nicer exception.
- Search before creating work. Existing ownership and canonical foundations matter more when an agent can duplicate a month's work in an afternoon.
- Put durable detail in durable systems. Repository rules hold conventions. Harness holds scope and dependencies. Tests hold behavior. RCL holds review identities and verdicts. GitHub holds exact heads, checks and merge state.
- Keep issue, branch and PR boundaries aligned. One acceptance contract, one diff, one review boundary, one closing event and one rollback unit.
- Treat every review finding as a hypothesis. Confirm it in source and tests or dismiss it with evidence.
- Steer on outcomes, evidence and authority. Let the agent choose the implementation until a real product or architecture decision needs a human.
- Make continuation mechanical. The next task comes from the live dependency graph, not from whatever the model remembers about the plan.
- Prove closure independently. Scope, review, CI, merge, tracker state and release evidence must agree. Any one of them can lie by omission.
The visible inputs to this delivery were one screenshot, a planning conversation, an execution contract and occasional steering. The invisible part was the control plane we had built around the agent.
That is the part I now consider agentic engineering.
The code generation is useful, sometimes astonishingly so. But the real leverage starts when the agent can pick up durable work, stay inside explicit authority, survive a cleared context, defend its changes against adversarial review and prove that the intended outcome exists outside its own transcript.
The groove does not feel like having an infinitely fast engineer in a chat window.
It feels like operating a small software delivery system that happens to talk back.
Source note
This article is condensed from the planning and execution records of an internal Data Rooms migration completed across 16-20 August 2026. The underlying record includes the Harness issue graph, GitHub PRs and immutable commits, CI runs, RCL finding ledgers and a later completion audit. Internal resource identifiers and private session paths are intentionally omitted.
