The frontend continued to show the user as signed in even though it no longer had a JWT. They could move through the interface as usual. The problem surfaced only when they triggered another request to the backend. The implementation agent had not handled that state; another agent found it during review.
This happened while we were building a multi-level permissions system. The reviews also found a separate problem in the token refresh flow, along with permission edge cases and ticket requirements that had only been partly implemented. These were ordinary gaps in the implementation, but they mattered because the feature controlled what people could see and change.
Our workflow is designed around that problem. Agents help us plan and implement a feature. Review and integration run as separate jobs with their own context. The permissions system is a useful example of how that works in practice.
Defining the boundary of a flexible permissions system
Our previous permissions model was fairly flat. Its replacement had to distinguish between organisations, teams and individual users. We needed roles such as organisation admin and billing admin at organisation level, and team admin, team lead and analyst within teams. Delegation rules also had to cover cases such as a colleague editing someone else’s data while that person was away.
“A more flexible permissions system” did not give an implementation agent enough direction. If I gave that brief to two engineers, one might add six predefined roles while the other rebuilt AWS IAM by Friday. Both would have made a defensible interpretation of the word “flexible”.
We therefore set a specific boundary. The application would provide predefined roles and allow some features or permissions to be switched on or off within them. Users would not be able to define entirely custom roles. That was explicitly out of scope.
This left room for teams and organisations to adapt the system to their way of working without turning the feature into a general-purpose policy engine. More importantly for implementation, the agents could distinguish between technical choices they were allowed to make and product decisions that had already been settled.
Planning the product and the implementation
We start with the product behaviour. For the permissions system, we had to decide what users in each role could see, what they could change and which data they must not see. We use specialised planning agents for UI and UX, backend, data and security. They bring up options and open questions, which we then discuss as a team.
For larger features, we often put the plan aside for a day before reviewing it together. Reading it again the next morning catches a surprising amount of wishful thinking.
Technical planning comes next. We work out which existing components can be reused, how the role model should be represented and which interfaces will change. Architecture and significant security decisions are recorded before implementation starts.
We then split the feature into tickets. Each ticket contains the relevant technical detail, acceptance criteria, dependencies and sections labelled In Scope and Out of Scope. Dependencies also control execution: a ticket that relies on a new data model does not start before the ticket introducing that model has finished.
The tickets do not prescribe every line of code. An implementation agent can choose technical details within the agreed architecture and scope. If it encounters an unresolved product, architecture or security question, it must escalate the decision instead of filling the gap with a plausible assumption.
The five stages for each ticket
Once its dependencies are complete, a ticket moves through five stages:
- An implementation agent changes the code.
- A separate agent reviews the result.
- The review findings are fixed and the ticket is finalised.
- A conflict gate handles conflicts from parallel Git work.
- The changes are integrated, checked across implementations and prepared as a pull request.
The reviewer records its findings in a review document, which becomes the input for the next stage. It sees the ticket, the code and the project context, but not the implementation agent’s account of why each decision seemed reasonable.
After the dependent tickets are done, we run another review across the whole epic, followed where needed by fixes, integration and security checks. Human review and approval remain part of that process.
Context depends on the role
An implementation agent gets context suited to its ticket. A frontend agent concentrates on the affected UI, but can inspect backend code and API schemas when it needs to understand an endpoint or reuse an existing contract. It has access to the repository without having to read the entire codebase before making a small change.
The review agent gets the ticket, requirements, changed code and relevant project rules, including our AGENTS.md and specialised skills. It can inspect existing test results and adjacent components.
It also works in a prepared development environment. The application is ready to run, with a database seeded with example data, so the reviewer can exercise the code as well as inspect the diff. That matters for issues at component boundaries. A missing JWT-state check in the frontend is easy to overlook when attention stays on the UI change itself; a review that includes authentication behaviour and the backend interface has a better chance of finding it.
At integration, another agent uses a different prompt, skills and focus to examine several tickets and components together. For the permissions system, that meant looking across the role model, frontend, backend and authentication rather than treating each change as an isolated unit.
Each handover comes with a different set of questions. Running the same task again with the same context mostly repeats the first agent’s blind spots.
Feature ownership stays with a person
Agents wrote almost all of the implementation code for the permissions system. The product model, scope, architecture and significant security decisions remained human-led. Agents contributed during planning, then implemented, reviewed and helped integrate the decisions we had made.
One person owns each feature from planning to release. That person follows the work across tickets, judges the review findings and has the final say on whether the feature is ready for production. This is especially important for permissions: if the system grants the wrong access, responsibility cannot be assigned to an implementation session or a review prompt.
We now spend more of our time defining expected behaviour, scope and dependencies before implementation starts. If an agent reaches a decision we have not made, it has to stop and ask. The feature owner decides whether the result ships.
