Back to postsEngineering

The development workflow I refined with coding agents

Carry verified criteria from planning, implementation, checks, and review into the next task.

Carry verified criteria from planning, implementation, checks, and review into the next task.

I opened an E2E an agent had reported as successful. It waited for Uploading... to disappear from the banner drawer, but no code in the repository displayed that text. I could not tell whether it had waited for an upload or simply passed because the text was already absent.

My first Claude configuration did not define how I would accept finished work. Documents covered where forms belonged and how to build Query Options, but I still corrected detailed choices after reading the result. Many of my criteria had never reached the model. I added a push reviewer and skills that present a plan and wait, first in the admin monorepo and then in the portal.

One sprint focused on screen behavior without reading the code and produced many hotfixes. I returned to reading feature and refactoring changes alongside their tests. After ticket and plan review, agents write tests and implement; changed-scope checks come before my diff and UI review, followed by CI and a QA double check.

I judge plans, diffs, and screens; push gates and CI run automated checks.

I judge plans, diffs, and screens; push gates and CI run automated checks.

Resolve missing behavior before implementation

I read a ticket to consider whether code can solve it and whether the existing approach is appropriate. I joined some requirements discussions, but plans also reveal ambiguous behavior or necessary backend changes. I resolve those with the relevant person before implementation.

The portal follows designer mockups; other products mostly use wireframes. Figma MCP helps compare an implementation with a design, but wireframes leave behavior undecided. Global file uploads needed separate decisions about retaining verification-code input and displaying upload failures.

The agent finds related code and a close reference, then writes its plan. I distinguish established patterns, questions needing answers first, and finished screens or data requiring my inspection. Previously defined bug fixes and schema mismatches start with reproduction and verification.

Change direction before there is code to discard

Discovering a wrong direction in a finished diff means throwing implementation away. The ticket-branch skill therefore waits for my input after presenting its plan, even in auto mode.

The template covers the ticket summary, impact, work order, and review questions. I read the interpretation of behavior before the file list. Missing cases, state placement, completion conditions, or misunderstood APIs send the agent back to investigate. After I review a revised plan, implementation can begin without discarding product code.

Stop repeating corrections in every prompt

At first I appended cautions to each prompt. As they grew, I split them into skills for forms, Query, and FSD. Admin error handling stayed in a policy document; the portal design system has its own skill. AGENTS.md holds shared rules and points to the relevant detail.

When correcting generated code, I consider whether the mistake will recur. Import direction, slice boundaries, and raw query keys can be decided mechanically, so they moved into lint. I cleaned up existing violations before expanding enforcement, without forcing the same severity levels on both repositories.

Whether a component assembles a screen layout or presents domain data needs its callers read. That judgment remains in documents and review.

Record each recurring correction where its kind of judgment belongs.

Record each recurring correction where its kind of judgment belongs.

I developed this process with reference to Compound Engineering. It was not a complete system from the start. Repeated corrections improved the guidance, while improving models also produced results closer to my style.

Find differences in the screen and the server

For design work, the agent opens the UI and captures it at the same viewport. I compare spacing, typography, icons, responsive layout, open states, and errors. Differences are fixed and checked again, and I operate the feature myself.

Mocks once accepted requests that the real server rejected with 400. I changed them to enforce server constraints. When another constraint appears through the dev API, I update the form, mock, and tests together and check again against that server.

Read what a test actually waits for

Functions and schemas run in node; forms and components use jsdom or Browser Mode; navigation flows use Playwright. New admin tests use the dev API by default. MSW creates failure states that are difficult to prepare directly, in files marked .mock.

The environment cannot rescue an incorrect assertion. I changed the upload test from waiting for screen text to inspecting actual upload-item state.

typescript
// before: 저장소에 없는 화면 문구가 사라지길 기다린다
await expect(drawer.getByText('업로드 중...')).toBeHidden();
 
// after: 진행 중인 업로드 항목이 0개인지 본다
await expect(drawer.locator('.ant-upload-list-item-uploading')).toHaveCount(0);

Even that wait only establishes that nothing is uploading. It can pass if the upload never starts or fails, so the uploaded file and saved result need checks too. QueryClient configuration also had to match the app. I fixed tests whose initial failures never reached the Error Boundary and separated first-load failures from refetch failures with existing data.

New requirements go in BDD-style *.spec files; production and QA bugs go in *.test. Inputs, actions, and expectations need to be readable in the test. AGENTS.md requires tests before refactoring and deliberately breaking product code to check new test patterns. I also compare what each test asserts with the plan's success conditions.

Names distinguish specifications from bug reproduction, and testing starts where mocks are unnecessary.

Names distinguish specifications from bug reproduction, and testing starts where mocks are unnecessary.

Program review crosses hospital admin and Back-Office. Registration and a review request start in hospital admin; Back-Office marks the program under review and approves or rejects it. A separate Playwright configuration runs both dev servers on 3000 and 3002 against the dev API. Hospital admin uses another browser context because localhost shares cookie domains.

Looking for Reject text could pass without a state change because the drawer already had that button. I check that the rejection reason entered by the test reappears in details instead.

Verify rejection through the reason entered by the test, not a label already on screen.

Verify rejection through the reason entered by the test, not a label already on screen.

Separate independent tickets from shared changes

Independent tickets use separate Orca worktrees and sessions. Refactoring shared APIs and structures stays in one session. Either way, I read the finished diff and tests and explain deviations before asking for revisions.

Agent review findings also need inspection. I compare their reproduction conditions with the code and the behavior the plan intended to preserve. I treat that as different input from review by a colleague who helped agree on the design.

Independent tickets use separate sessions; related structural changes stay in one session for finished-diff review.

I separate sessions by dependencies and review the finished changes myself.

More sessions made checks overlap

Worktrees isolated branches and dependencies but did not stop every session from launching full lint and tests together. Turbo cold-ran all packages and occupied the CPU. Some overlapping checks ended with exit 143. That code alone did not establish the cause, but an unfinished check left no basis for pushing.

The original admin gate was full-package pnpm run lint. I narrowed the first checks to changed-file ESLint, affected-package typechecking, and related tests through vitest --changed. Typechecking includes affected consumers; Knip examines the repository graph. Admin CI runs lint and unit tests, with dev-API tests and E2E separately. Portal CI runs lint, typechecking, and Knip.

Checks run in the worktree containing the change, without temporary merges into the main checkout to reuse caches. Failures return to the plan, implementation, or tests according to their cause. I compare completion reports with the original requirements too, because following a plan does not prove the plan was correct.

Distinguish reasons to stop before pushing

A separate reviewer reads origin/develop...HEAD and reports Critical, Warning, and Nit findings with confidence. Both repositories initially reviewed first, avoiding long checks if a Critical finding would stop the change. The portal retains that order. Admin now runs review and checks together, waiting for both before pushing.

For admin changes classified as markup, wording, and style within one screen, the process skips reviewer and tests but runs ESLint, typechecking, and Knip. Changes to branches or data flow receive full review and checks even when small.

Critical findings are fixed and checked again. Unresolved items or decisions needing my judgment stop progress. Warning and Nit findings are reported without blocking by themselves. Lint, typecheck, and test failures also prevent the next step.

The agent fixes Critical findings and checks again. Unresolved findings and failed checks stop progress.

Critical findings are fixed and rechecked; unresolved items need my review.

I documented recurring false positives as exceptions. Similar src/app/api routes in Back-Office and hospital admin repeatedly attracted suggestions for a shared handler factory. Each was tied to its own backend and response types, so I retained separation and told the reviewer not to recommend that extraction again.

Read the combined diff before deployment

Changes that look reasonable in separate PRs can produce duplicate abstractions, conflicting names, or inconsistent FSD boundaries together. I read the combined diff while preparing a deployment PR.

A troublesome pattern after deployment can also lead to finding and changing similar code across the repository. Removing portal entities and blocking direct cross-page imports began this way and reached develop. It did not make admin and portal structures identical. The FSD article covers that change.

Chat code once excluded from checks is back under lint and tests, while routes with a reason to remain separate have a review exception. Repeated findings have led me to reconsider whether a check fits the actual code, rather than simply making every rule stricter.

References