Blog · Agentic coding
Agentic Coding in Practice: A Workflow with Failsafes That Gets Agents to Ship
Agentic coding without hallucinated repo state: a session start, ten disciplined steps and a failsafe for each, so AI coding agents produce code you can merge.
You know the scene. You work on a bug with an AI coding agent. The agent writes a clean, confident fix. On push you find out it guessed the state of the repo: the branch does not exist, the pull request it refers to was merged days ago, and its idea of the database is two weeks old. That is the default failure mode of a naive agentic coding workflow.
At XALT we have built production software with coding agents for months. A process has settled that is robust enough to ship code to production, not only prototypes. It works more like an assembly line with clear validation gates than like improvisation.
This post shows the whole workflow: a session start and ten steps, each with a documented failsafe. One principle runs through all of them: validate, don't assume – at every point where the agent is tempted to guess.
Why naive workflows fail
Most teams use AI coding tools as a faster autocomplete: prompt in, diff out, merge. That works while the problem is small and no state is involved. As soon as branches, pull requests, databases or external services come in, the agent starts to guess. Guessing is where hallucination starts.
Patterns we see in code reviews:
- State is assumed, not checked. The agent says the pull request is open. It was merged hours ago, and nobody ran
gh pr view. - Identifiers get paraphrased.
customer_idbecomescustomerId;feature/billing-v2becomesfeat/billing-2. - A green build counts as done. Verification stops at the build, with no tests, smoke tests or real server checks.
- The reply text is treated as truth. "Done, the service responds correctly" – written without reading a single log line.
- Memory leaks between sessions. Every session starts from zero instead of from daily logs, ADRs and principles.
- Stacked pull requests without discipline. Three open pull requests built on each other, all nearly done, and one review comment breaks the stack.
The wider data points the same way. In the Stack Overflow Developer Survey 2025, 84% of developers use or plan to use AI tools, but more developers distrust the accuracy of the output (46%) than trust it (33%). The most common frustration, named by 66%, is output that is almost right but not quite. If you want AI code in production, you need a workflow that catches those errors by design.
Validate, don't assume
Hallucination is not a bug that a future model will remove. A tool-using language model produces plausible tokens, not verified facts. The lever you control is the workflow around it.
Our approach rests on three pillars:
- State validation before every step. Before every branch switch, pull request or "this also works in production", there is a tool call that proves it:
git fetch,gh pr view, a database query, a log tail. - A documented failsafe for every step. Each step names where the agent tends to stumble and how we prevent it. Failsafes live in
principles.md(operational rules) andlessons.md(the incidents behind them). - Memory discipline alongside the work. Daily logs are written during the work, not after it. A wrap-up before every break is mandatory.
The session start
Before anything else, the agent loads its context layers in parallel:
- Identity: who the agent is and how it works.
- People: the humans and agents involved, how to work with each, and any rules per person.
- Principles: the operational rules learned so far, above all identifier discipline and hallucination defence.
- Projects: what is open, with status, current issues and next steps.
Failsafe: do not skip the session start, even when the task looks obvious. The obvious tasks are where missing context leads to bad decisions.
Review and compact principles.md regularly. Otherwise it grows past a few kilobytes, collects prose and history, and stops working as a rulebook. Anything that is not a rule moves to the daily logs, where it stays available without filling the working context.
Kickoff and context check
You describe the problem. The agent checks the scope, looks for existing issues and verifies state with git fetch and gh pr list. Only then does it state a hypothesis.
Failsafe: no hypothesis without tool evidence.
Plan proposal: disagree or approve
The agent proposes order and scope, with reasons and alternatives. You approve, change it or propose your own. The agent may push back; a real opinion is more useful than agreement.
Failsafe: when you return to a problem after a detour, re-validate the problem first. Otherwise the old plan gets forced into a new situation.
Branch setup
A fresh branch from origin/main, or from a parent pull request if the stack is intended and documented. One open pull request at a time. Bugfixes get the smallest possible diff; refactoring goes into its own pull request.
Failsafes: one pull request at a time. Minimal diff for bugs. Never refactor and fix in the same branch.
Implementation in small steps
For larger changes, the ADR or documentation comes first, then the code. A fast check (for example npm run check) runs continuously, so errors show up early.
The verbatim-or-nothing rule matters most here. When a tool call fails, a naive agent fills the gap with a plausible commit hash or identifier. A disciplined agent checks every identifier against reality, notices its own hallucination and corrects it.
We have our agents record every such hallucination in a dedicated file. That corpus shows where agents stumble most often and tells us where the next failsafe or validation gate belongs.
Failsafe: verbatim or nothing for identifiers. No paraphrased variable names, branch names, ticket keys or endpoints. When in doubt, the agent asks.
Pre-merge verification, scaled to the change
Always required:
- The build passes.
- The tests pass.
- A real database, container or server check when server state is involved.
Depending on the change:
- Smoke tests.
- A manual
curlor load run. - A browser check for UI changes.
This assumes the agent was asked to write tests from the start, ideally from the acceptance criteria of the issue.
Failsafes: a curl call does not prove a browser form works. Server logs are the truth, not the agent's statement that the deployment succeeded.
Commit, push and pull request
Conventional commit messages, no free text. The pull request body follows What / Why / How verified, with test output as evidence. For UI changes it asks the reviewer for a live test before merge.
Check the branch out locally for review. The agent can write the setup script for you, so the old friction is gone.
Failsafe: the pull request body contains a reproducible test path, not a promise.
Review and merge, or back to the table
You review and merge, or send it back with precise feedback. During review, the agent stays quiet or works on unrelated documentation. Each repository documentation change still needs its own pull request from main.
Failsafe: no new feature pull request while a review is open.
Post-merge hygiene
git pull --ff-only, delete the branch, update the daily log. If the ticket taught something, it goes into lessons.md as a candidate. At the next review, the agent decides whether it is strong enough to become a rule in principles.md.
Failsafe: do the hygiene right after the merge. "Later" is where memory falls apart.
Memory discipline alongside everything
The daily log is written during the work. A memory sweep runs at the end of the day and before every longer break. MEMORY.md (or a database), principles.md and projects.md stay current. This is how the agent stays consistent across days.
Tell the agent when you go to lunch or stop for the day. It can then run its memory sweep instead of being cut off mid-task, and the next session starts where you left off.
Failsafe: files survive, the context window does not.
Respect the stop signal
When you signal a pause – "continue tomorrow", "lunch", "short break" – the agent closes cleanly. It finalises the daily log, marks open threads with a "resume here" note and does not run "just one more" iteration.
Failsafe: write the wrap-up into the daily log. The next session will not remember otherwise.
What sets this apart from a naive workflow
Four properties separate a production setup from a playground:
- State validation at kickoff is not optional. In our own work it has caught agents that were about to write code against a branch state that no longer existed. A
git fetchand agh pr viewdisproved the assumption at once; without them, each case would have meant detective work after the push. - Branch, scope and verification are the main axis. This is where "probably right" becomes a verified diff. Skip one and you pay for it later. We once went straight into an open stack for a one-line fix; cleaning that up cost two hours and produced a sharper failsafe.
- Memory discipline decides consistency over weeks. It is also what lets the approach scale to setups with several subagents.
- Failsafes are maintained.
principles.mdandlessons.mdare read and updated. That ongoing upkeep is the difference between a workflow on paper and one that still works months later.
Almost every step has a validate-don't-assume component: state at kickoff, identifiers during implementation, correctness before merge, pull request status at review. Once you see that pattern, you stop tuning the model and start building the workflow.
Takeaways
- Hallucination is structural. The counter is a workflow with documented validation points, not a better prompt.
- Validate, don't assume. State, identifiers, correctness claims and pull request status are all backed by tool calls.
- Memory discipline decides consistency across weeks.
- Stop signals are respected, so no memory gaps open between sessions.