AI is innovatively changing our lives. Developers, in particular, seem to be facing an environment where they work with new tools every week.
Yet, amidst this process, some things remain unchanged. We must generate sustainable code and write code that is easy for humans to read. Code that is difficult for us to understand is equally difficult for AI to understand.
If AI is not performing well, it seems we've reached a point where we should suspect issues with existing brownfield projects or question whether the team is developing in an incorrect manner.
Vibe Coding Is Not Real
It seems more than a year has passed since the term 'vibe coding' emerged. Initially, upon seeing the results of vibe coding, my friends and colleagues and I would joke, "Let's just go farm instead."
But what about the results? As of now, I think I can say with certainty: sustainable services cannot be launched through vibe coding.
If you explain to AI what kind of app to build, how to do it, the planning, etc., and then have it develop, it never works well on the first try. You end up repeatedly making corrections, often muttering, "This isn't right." Repeated modifications lengthen the context, gradually lose the previous context, and continuously create uncontrollable bugs. Only then do we look at the code we've set up and curse endlessly.
Vibe coding cannot exist. It's impossible even in the future. Simply saying "do it for me" cannot make AI 100% understand our desired approach from vast amounts of data. LLMs are essentially fill-in-the-blank models; there's no way they can just implement the features we want.
So, how can developers achieve sustainable coding with AI? What is the role of a developer in this era?
The Role of the Developer
I often hear that instead of direct development, the role of a developer is to constrain LLMs to perform the coding we desire and to code such environments. This means configuring skills and agents and building flows for repetitive commands.
The stage of doubting LLMs has passed. As developers, we should aim to create environments where LLMs can perform their tasks effectively.
Harness Engineering
Numerous open-source harness environments like OMC, OMO, and OMX have recently gained immense popularity. This is because no matter how much LLM models advance, we still need to clearly explain what we want. We must minimize the 'do it automatically' parts and reduce ambiguity.
These open-source harnesses restrict developer freedom, forcibly reduce ambiguity through flows provided by the harness environment, and enable sub-agents to work in parallel on clearly separated contexts. They provide good results by enforcing constraints, even if developers don't build each flow manually.
However, even these harness environments are ultimately not tailored for our team. Generic harnesses, unaware of our team's conventions, design systems, or deployment pipelines, have limitations. We concluded that we need to configure harnesses specifically for our team or individual needs.
My Workflow
Listening to how others work, it seemed they were all encountering the same problems and working in similar ways. I felt it was crucial to distinguish between what can and cannot be delegated to AI, and to clearly define the stages where human intervention is necessary.
Delegable Areas
Repetitive and clearly patterned tasks such as code generation, refactoring, test writing, documentation, commit message generation, and PR creation could be delegated to AI. If references were well-defined, the results sufficiently matched the intent.
Non-Delegable Areas
Design decisions, requirement interpretation, final judgments in code reviews, and subjective judgments about user experience still needed human involvement. Whether AI-generated results "work" and whether they are "correct" were different issues.
So, where should humans intervene?
Dividing these two areas made the moments requiring judgment clear.
- When interpreting requirements,
- When approving PRDs,
- When conducting code reviews
A structure was needed where humans verify at these three points, and AI executes the rest.
Therefore, I made each step an independent skill, and an orchestration skill called /haejo chains this entire flow. When you input "develop login page for me," it executes the following steps sequentially, asking "Proceed?" at the end of each step. This structure stops at moments requiring human judgment and delegates execution, which AI excels at, to AI.
/haejo "로그인 페이지 개발해줘"
Step 1: /prd-gen ── Reduce Ambiguity + PRD Separation
✅ 완료 → "Proceed?"
Step 2: /prd-exec ── PRD-specific Implementation + Self-Review
✅ 완료 → "Proceed?"
Step 3: /create-pr ── PR Creation
✅ 완료 → "Send Slack review request too?"
Step 4: /review-request ── Slack Notification (Optional)
Let's examine each step in detail.
Step 1: Reduce Ambiguity — /prd-gen
The first thing to do in feature development is to collect relevant context (Jira tickets, Slack threads, Figma designs, Confluence specs) and feed it into /prd-gen.
Internally, /prd-gen calls /deep-interview. It repeatedly asks questions and receives answers in a Socratic interview style, quantifying ambiguity and continuing to ask questions until ambiguity drops below 20%. Questions like "Should this feature work offline?" or "Should we extend the existing authentication middleware or create a separate flow?" emerge, revealing assumptions I hadn't considered.
Once the interview is complete, the results are separated into minimum viable PRDs. Each PRD should be small enough to be reviewable as a single PR, and common components or hooks are separated into distinct PRDs. A dependency graph is also generated, clarifying which PRDs should be worked on first and which can be run in parallel.
Step 2: PRD-specific Implementation — /prd-exec
Once a PRD is finalized, /prd-exec executes it in dependency order. For each PRD, the following process is repeated:
- Deep Interview once more — Further clarification at the PRD level. Catches details not apparent in the overall specification.
- Sub-branch creation — Creates PRD-specific sub-branches from the feature branch.
- Reference routing — When a
.tsxfile is modified, it automatically reads the UI implementation checklist, and for Form-related tasks, it additionally reads the Form architecture guide. These references are key to making Claude write code according to our team's conventions. - Implementation — Code is written based on the PRD's Acceptance Criteria. PRDs without dependencies are implemented concurrently in parallel in separate worktrees.
- Self-review — A code review agent validates the implementation in a separate context from the implementing agent. This separation is crucial because reviewing one's own code can lead to leniency. If issues are found, correction → re-validation is repeated up to 3 times.
- PR + User Review — A PR is raised from the sub-branch to the feature branch, and I review it directly. If approved, it's merged, and the process moves to the next PRD.
Reference routing originated from the experience of initially putting all rules into a single CLAUDE.md file, which then swelled to 341 lines. Detailed rules are separated by category under .claude/ref/, and the routing table only manages matching conditions like "read this ref when working on this file." A double safety mechanism with Hooks was also implemented because instructions alone sometimes led to omissions.
.claude/
├── CLAUDE.md (Routing Table + Common Rules)
└── ref/
├── ui/
│ ├── ui-implementation.md (Primitives, Props, CSS Policies)
│ └── figma-workflow.md (Figma→Code 4 Steps)
└── patterns/
├── form-architecture.md (Self-Contained Atomic Field)
├── feature-api.md (Mutation Hook Pattern)
└── api-error-handling.md (ApiException Pattern)
Step 3: PR Creation — /create-pr
Once all PRDs are merged, /create-pr generates a feature → main PR. If there are uncommitted changes, it categorizes them into logical units, separates the commits, and automatically creates a feature branch if work is being done on the main branch.
If a reviewer is selected, it automatically asks, "Send Slack review request too?" If "Yes," /review-request sends a review request message to Slack, including an @mention. If a review is not needed, it can be skipped.
Bug Fixing Flow
Bug fixing is simpler than feature development. Skills are called directly without going through /haejo.
1. Context Collection — Jira Ticket + Slack Thread + Related Discussions
2. /deep-interview — Bug Spec Clarification (Skip if simple)
3. /ralph — PRD-based Automatic Implementation + Validation Loop
4. /create-pr → /review-request
/ralph is a skill that repeats code writing → testing → modification until completion. Bugs rarely require splitting PRDs into multiple parts, so implementation proceeds directly without /prd-gen.
Key Skills Being Used
| Skill | Description |
|---|---|
/haejo |
Orchestrates the feature development flow. Chains the skills below step-by-step, with user confirmation at each stage |
/deep-interview |
Removes ambiguity from specs using a Socratic interview method. Repeats questions and answers to derive PRD-level specifications |
/prd-gen |
Clarifies requirements based on /deep-interview, separates into minimum viable PRDs + dependency graph. Saved in .omc/specs/ |
/prd-exec |
Executes PRD files in dependency order. Per-PRD: deep-interview → branch → implementation → self-review → PR → user review |
/ralph |
Receives a PRD and performs automatic implementation + validation loop. Repeats code writing → testing → modification until completion |
/simplify |
Performs self-review by checking the quality, reusability, and efficiency of changed code |
/create-pr |
Logically separates uncommitted changes, commits them, and creates a GitHub PR. Automatically asks for Slack review if a reviewer is selected |
/review-request |
Collects current PR information and sends a review request message to Slack (including @mention) |
/task-record |
Records work on Notion task cards + automatic difficulty assessment + Done processing |
Notion-Based Task Management
My current company barely uses Jira, so I manage tasks using personal Notion. When starting a task, I always designated or created a new Notion card to link, and when raising a PR, I used /task-record to summarize the session's work and record it on the Notion card.
Doing this, over 130 Notion cards accumulated in two months. It was great to have an automatic record of what I did each day for two months. Without needing to set aside separate time for retrospectives, I could just skim through the cards and see what tasks I worked on, where I got stuck, and what decisions I made.
Conclusion
No team can yet work with 100% trust in AI.
However, it's clear that most tasks can be delegated to AI.
Recently, our team also began standardizing AI workflows under the name "Becoming a SOTA-level Developer."
To implement it quickly, I first uploaded the flow I was using to the team repository, and we adopted an approach where team members review and refine it. We adopted OMC (oh-my-claudecode) as a common harness and configured skills and references based on Claude Code users.
Sharing our individual approaches, we found similar conclusions and agreed on directions such as separating the roles of CLAUDE.md, skills, and sub-agents, a Git strategy that distinguishes between team-shared and personal settings, and data-driven skill validation.
Reference documents (Figma workflow, code pattern guides, etc.) still contain my personal opinions. Team members will freely upload and review the references they are using.
It's still under construction, and concerns such as the limitations of test code, token optimization, and how to demonstrate value to team members who don't use AI are ongoing.
We must clearly recognize the unreliable parts, divide what humans can do and what AI can do within the team, and aim to build the correct flow.
There's still a long way to go.
The limitations of test code, token optimization, the ambiguity of quantification, how to conduct efficient reviews, and how to demonstrate value to team members who don't use AI—various concerns continue endlessly.
I suppose I'll post again if my thoughts are updated sometime...?
