Your AI writes the code. Who reviews it? Meet Enji Guard.

Created: May 19, 2026

Maria Zaichenko.

Maria Zaichenko Engineering Project Manager

AI-First Approach

[I'm a Project Manager, and I Shipped a Feature: Here's What That Looked Like]

Analyze with AI

Get AI-powered insights from this Enji tech article:

There's a version of the AI-first company that sounds good in a press release: everyone moves faster, every team is empowered, and every process is smarter; then there's the version that happens in practice, which is messier, more interesting, and considerably more useful to write about.

This is the second version.

I'm a project manager. My job is coordinating releases, managing delivery timelines, working with the team on prioritization, and making sure things that need to ship actually do. Writing code is not part of it; it has never been part of it. And yet, in the last release, four features I built myself shipped to users through real PRs, peer review, and staging builds.

This is a story about what it actually takes to go from "I have an idea" to "This is in production" when you're not a developer and what that process reveals about how AI is changing the boundary between roles.

The idea

Each of the four tasks started the same way: a concrete, specific problem that was sitting in the backlog, not because it was hard, but because it wasn't urgent enough to displace something bigger.

  1. A notification badge for the Absences section in the sidebar: approvers had no visual indicator that requests were waiting.
  2. An employee type filter in Global Worklogs: anyone handling payroll was doing manual sorting every month.
  3. A duplicate employee bug in the new project creation flow: adding an existing team member created a second database record instead of referencing the existing one.
  4. And a follow-up fix when the badge wasn't updating after a rejection action.

All of them were the kind of "quality of life" improvements that accumulate in backlogs for years while teams focus on major releases. I didn't set out to ship code: the tasks were concrete, the tools were accessible, and at some point, the line between "describing what needs to be done" and "doing it" blurred enough that I crossed it.

That crossing looked like this: opening Cursor, describing the problem in plain language, and working through it iteratively.

The process

The first task (the notification badge) is the most instructive, because it went wrong in exactly the ways you'd expect and recovered in ways I didn't anticipate.

Cursor located the relevant files: MainMenu.vue, MenuTree.vue. It created the necessary new files. I had never opened any of these before and had no idea where the sidebar code lived. I launched it and got a white screen and a console error:

TypeError: _ctx.badgeCount is not a function at MenuTree.vue:45

Cursor had added parentheses to badgeCount(), treating it as a function when it was actually a computed property. I copied the error, sent it back with an explanation, and it was fixed.

So that was my first lesson: even a simple feature rarely works on the first try.

I then realized the badge on "Absences" alone didn't solve the problem; the HR section is usually collapsed. We added an indicator dot to the parent menu item. Before submitting the PR, I asked Cursor to generate a checklist of what to test: edge cases, behavior with zero requests, collapsed states, and unnecessary API calls. That checklist significantly sped up my self-testing before handing it to QA.

The review came back with two comments: a deprecated color variable and an empty catch block missing a console.error. I fixed both with Cursor. Then the staging build failed with a TypeScript error, a typing issue in hasChildWithBadge where child nodes were typed as unknown[]. Cursor fixed it by extracting a proper TreeNode interface. One more PR.

Three PRs total for one badge. After that, standard testing passed, and the feature went live.

The follow-up bug arrived shortly after: the badge updated after an approval, but not after a rejection without a page refresh. Cursor analyzed the code and found it quickly; sendAbsenceSaved() was present in handleApprove and handleSave but missing in handleReject. It then checked the staging branch and found the call had been lost between merges, pushed to the branch after the main PR had already closed. The fix was a single line.

The second useful lesson: Cursor can diagnose discrepancies between local environments and staging. It did this by running:

git show origin/staging:path/to/file | grep -n "sendAbsenceSaved"

That's not a query I would have thought of unprompted.

The employee type filter touched both the frontend and backend simultaneously: my first time working across two repositories. The whole process took about two hours. The task wasn't technically complex, but that's precisely what made it instructive. It showed where the boundary between "describing a problem" and "solving it" has moved. A PM with two free hours and a clear task no longer needs to route it through a developer's queue.

The duplicate employee fix required understanding the difference between the create and update API modes. employee_id was only being passed when isUpdate = true, so adding a "new" member triggered a new database record instead of referencing the existing one. After fixing that, a new message appeared: "1 member was skipped." The backend returned a "skipped" status because the email already existed, which the frontend displayed as a warning even though it was technically a success. I adjusted the UX notification to reflect that correctly.

Throughout all of this, my workflow settled into a pattern:

  1. Describe the task in terms of behavior, not code: "The badge should update immediately after Reject without a refresh" performs better than asking for a specific function.
  2. Review the diff at the end, not at every step; early on, I was requiring confirmation for every move, which was a bottleneck.
  3. Ask why, not just what: "Explain what you found," "Why here?" and "What happens if we don't do it this way?" Every task became a learning opportunity.

I now understand what an event bus is and the difference between create and update API modes.

The infrastructure was the most unpredictable part: incompatible Node.js versions, Docker not seeing new files without a rebuild, and containers failing to restart. These require troubleshooting intuition I'm still building.

What shipped

Across all four tasks, the pattern held. Here's what made it into production:

  • Notification badge for Absences in the sidebar, with an indicator dot on the parent HR menu item.
  • Post-rejection badge refresh fix.
  • Employee type filter (Staff / Non-Staff) in Global Worklogs.
  • Duplicate employee fix in the new project creation flow.

Small features, by any measure, are the kind that don't make it into the headline of a release note. But that's partly the point.

What this says about the team

We build Enji on the premise that AI should make project intelligence accessible to people who aren't data engineers. It turns out the same argument applies to how we work, and I didn't expect to be the proof of concept.

When a manager can take an idea from observation to shipped feature without a full engineering sprint behind it, the organization moves differently, not because AI replaced the engineering team (the code went through review, it went through testing, and people with actual technical expertise were involved at the right moments). But the starting point shifted. The idea moved.

What made this possible was the environment in which the tools were operating. Enji has AGENTS.md, a style guide, documented service boundaries, and established PR processes. Cursor followed the rules the team had already set; a well-organized codebase allows non-developers to work differently.

As our earlier piece on multi-agent systems noted, written by our tech lead, AI scales whatever foundation it's given. My experience confirms this from the other side of the table.

What this doesn't say

This is not an argument that everyone should write code or that AI makes technical expertise unnecessary. The features I built were small and clearly scoped. The review process caught real issues: a deprecated variable, a missing error handler, and a typing problem that broke the staging build. Knowing the difference between "I can figure this out with AI" and "This needs an engineer" is itself a skill and one that takes time to develop.

What it is an argument for: that the line between "technical" and "non-technical" work is moving and that the people best positioned to notice where it's moved are the ones willing to test it.

Perhaps the most lasting effect isn't the speed or the autonomy, but the quality of understanding. When you follow a problem from the symptom to the specific line of code, you frame tasks differently, estimate complexity more accurately, and speak the team's language. That changes how you work with engineers, because you've seen what they see.

There's a lot of writing about AI adoption that treats it as a top-down initiative: a strategy, a rollout, a transformation program. What happened here was none of those things. It was one person on the team who noticed a problem, decided to try something, and ended up shipping it.

That's what an AI-first team looks like in practice.

You can also read:

Software Delivery

[Why Delivery Velocity Drops, and What Consistent Practice Actually Shows]

Delivery slowdowns follow predictable patterns across projects. Learn how to identify velocity degradation using cycle time, rework rate, and PR review data.

Engineering Management

[From Black Box to Boardroom Asset: How CEOs Gain Real Visibility Into R&D Spending]

A practical framework for CEOs to track feature cost, delivery health, and return attribution — and finally answer what R&D spending is producing.

AI

[How We Made AI ROI Visible to Engineers and to Clients]

Three metrics that make AI ROI visible to both engineering teams and clients: project margin, delivery predictability, and ghost FTE. A practical framework with real data.