From oh-my-harness
Backend-only harness builder. Scans the project root to detect language / framework / architecture_style / data_layer / api_style / test_stack, then generates the core 6 agents + 2 leaders + conditional specialists with concrete project evidence injected. Triggers: '백엔드 하네스 만들어줘', 'harness-be', 'backend harness', team setup on server projects (NestJS / Express / Fastify / FastAPI / Django / Spring / Go etc.), reconfiguring an existing harness from a backend perspective, and automatic invocation when the router skill (harness) branches to BE.
npx claudepluginhub moondongmin/oh-my-harness --plugin oh-my-harnessThis skill is limited to using the following tools:
Builds the agent team for a backend project. **Core principle**: do not assume any specific framework or architecture (DDD / Hexagonal / NestJS). Scan the project first, detect facts, and inject the detected evidence into the agent prompts.
Guides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Migrates code, prompts, and API calls from Claude Sonnet 4.0/4.5 or Opus 4.1 to Opus 4.5, updating model strings on Anthropic, AWS, GCP, Azure platforms.
Automates semantic versioning and release workflow for Claude Code plugins: bumps versions in package.json, marketplace.json, plugin.json; verifies builds; creates git tags, GitHub releases, changelogs.
Builds the agent team for a backend project. Core principle: do not assume any specific framework or architecture (DDD / Hexagonal / NestJS). Scan the project first, detect facts, and inject the detected evidence into the agent prompts.
All user-facing output must be in Korean. This file is written in English for token efficiency (Claude reads it as instructions), but anything the end user sees — AskUserQuestion text, progress messages, error messages, final summaries, CLAUDE.md blocks written into the project — must be rendered in natural Korean.
<!-- user-facing -->: literal templates, never translate.description Korean triggers: literal, never translate.Primary responsibilities of this skill:
<Project_Context> injectionharness-fingerprint block in CLAUDE.md — the tdd / implement skills read it later for reuse| Input | Behavior |
|---|---|
/oh-my-harness:harness-be | Backend detection → harness build |
/oh-my-harness:harness-be {feature} | Build + start working on the feature |
Invoked by router (/oh-my-harness:harness → BE branch) | Same |
Read the project's .claude/agents/, .claude/skills/, and CLAUDE.md.
If <!-- harness-fingerprint v1 --> exists in CLAUDE.md, read it to recover the previous detection result. Re-running with the same fingerprint avoids unnecessary re-scanning.
Run the detection tree defined in references/backend-detection-protocol.md. Store the result in memory using the following structure.
language: typescript | javascript | python | java | kotlin | go | rust | ruby | php | unknown
framework: nestjs | express | fastify | koa | hono | fastapi | flask | django | spring-boot | micronaut | quarkus | gin | echo | fiber | rails | laravel | unknown
architecture_style: hexagonal | clean | layered | mvc | modular-monolith | feature-sliced | simple | unknown
data_layer: prisma | typeorm | drizzle | sequelize | mikro-orm | sqlalchemy | gorm | hibernate | raw-sql | none
api_style: rest | graphql | grpc | trpc | hybrid | none
test_stack: jest | vitest | mocha | pytest | go-test | junit | rspec | none
infra: [docker, k8s, terraform, github-actions, ...] # array of detected tags
module_pattern: "src/modules/{name}/{name}.controller.ts, .service.ts, .repository.ts" # actual pattern string discovered
existing_modules: [user, order, payment, ...]
domain_terms: [Order, Invoice, Subscription, ...]
notable_files: [top 3 entry points — src/main.ts, etc.]
test_source_ratio: 0.42
Detection principles:
@nestjs/* is not enough — domain/ports/adapters directories must actually exist before declaring architecture_style: hexagonal.unknown and either ask the user or inject architecture_style: unknown into Project_Context as-is. Do not guess.When detection is ambiguous (architecture_style == unknown):
Ask the user via AskUserQuestion:
이 프로젝트의 주요 아키텍처 스타일은?
[1] Hexagonal (Ports & Adapters)
[2] Clean Architecture (use-cases/entities)
[3] Layered (controller/service/repository)
[4] MVC
[5] 기타 / 해당 없음
When the user answers, store it together with an architecture_style_user_declared: true flag.
Required: Read ../harness/references/model-selection-protocol.md and execute the procedure inside it exactly. That file defines the sequential AskUserQuestion flow for the core 6 agents, the option definitions, the response-interpretation rules, the final confirmation submit, and the fixed leader values.
The model_selection structure produced by the protocol is used in Phase 3 as each agent's frontmatter (provider/model). When Codex is selected, a codex_delegate: true flag is also recorded; Phase 3 reads that flag and generates the agent using the Codex CLI delegation template.
The two leaders (tdd-leader, team-leader) are pinned to Opus without asking, per protocol §6.
⚠️ Regression guard: an earlier version of this phase pointed to a Phase 1-1 block in
skills/harness/SKILL.md, which became orphaned after the router refactor removed it. This phase now reads the shared reference file directly, so drift cannot recur.
Generate each core agent at {project}/.claude/agents/{name}.md. Generation steps:
${CLAUDE_PLUGIN_ROOT}/agents/{name}.md. These files are neutralized and contain a <Project_Context> priority marker.<Project_Context>
<!-- injected by harness-be — authoritative over any generic assumption above -->
Skill: harness-be
Language: {language}
Framework: {framework} ({detected version if known})
Architecture style: {architecture_style} {"(user-declared)" if user-declared}
Data layer: {data_layer}
API style: {api_style}
Test stack: {test_stack}
Infrastructure: {infra joined}
Repeated module pattern: {module_pattern}
Existing modules: {existing_modules joined}
Key domain terms: {domain_terms joined}
Notable files: {notable_files joined}
Test-to-source ratio: {test_source_ratio}
Evidence that justified these detections:
- {list of concrete files/directories/deps that supported the detection}
</Project_Context>
<Project_Context> just before </Agent_Prompt> in the base prompt.{project}/.claude/agents/{name}.md.The two leaders (tdd-leader, team-leader) are produced the same way — read the originals at ${CLAUDE_PLUGIN_ROOT}/agents/{tdd-leader,team-leader}.md and inject <Project_Context> before saving. At the leader level, only architecture_style / framework / test_stack are included — detailed spawn logic branches inside the leader bodies themselves.
Detailed injection rules: see
references/backend-prompt-injection-guide.md.
Conditionally generate the specialist agents below based on the detection result. The judgment is grounded in detected facts, not in framework names.
| Condition | Agent generated | Injected content |
|---|---|---|
architecture_style ∈ {hexagonal, clean, modular-monolith} AND domain/ / entities/ files ≥ 5 | domain-expert | actual domain terms, discovered aggregate / entity names, domain directory paths |
api_style ∈ {rest, graphql, grpc, trpc} AND controller / router files ≥ 5 | api-specialist | detected API style, routing file paths, schema location |
data_layer ≠ none AND a migrations directory exists | data-engineer | detected ORM, schema files, migrations path |
infra tags include docker / k8s / terraform | infra-reviewer | detected infra tags, config file paths |
| Monorepo tooling detected (turbo / nx / lerna / workspaces) | monorepo-coordinator | detected monorepo tool, package list |
test_source_ratio < 0.3 | qa-agent | current ratio, areas with coverage gaps |
Critical change: domain-expert is only generated for hexagonal / clean / modular-monolith. It is not generated for a plain Express CRUD project (architecture_style: simple). This is the concrete realization of "remove framework assumptions + synthesize from detection".
Each specialist agent's prompt must inject at least 3 actual paths, file names, and domain terms collected in Phase 1. Do not generate generic specialists ("DDD expert").
Critical change: previously skills were auto-generated from a fixed "condition → skill name" matrix, which spawned generic skills the user never used. The flow is now derive candidates → user approval → generate only what was selected. Producing zero skills is a valid completion.
Read both of the following files. Skipping this step causes the LLM to fall back to matrix-matching mode.
../harness/references/skill-generation-guide.md — 5-step candidate derivation procedure + naming blocklist + user gate format../harness/references/skill-writing-guide.md — skill body authoring principles (pushy Description, Why-First, imperative)Follow guide §1's 5-step exploration (Step A–E) exactly. Summary:
module_pattern, existing_modules, domain_terms, notable_files) and the actual directory treeAskUserQuestion option cap of 4 + decision-fatigue mitigation)⚠️ Inline naming warning: if a candidate name is a generic noun like
migration-check,api-workflow,domain-check,cross-package,pipeline-check,config-sync, ortest-scaffold, reject and rename immediately. These names are pinned in guide §6's naming blocklist. A name that fits any NestJS project does not fit this project.
If there is at least one candidate, ask the user via AskUserQuestion (multiSelect=true). If there are zero candidates, skip this step, tell the user in one line that no auto-generatable repeated patterns were found for this build, and proceed straight to Phase 6.
question: "이 프로젝트에서 자동 생성할 보조 스킬을 선택해줘. 0개 선택도 OK."
header: "스킬 후보"
multiSelect: true
options: [최대 4개]
Each option's description must contain all 3 elements (guide §7):
label: order-field-sync
description: "src/modules/order/ 작업 시 prisma·migration·dto·controller 4곳 동기화.
증거: 기존 order/invoice/subscription 3개 모듈이 같은 패턴 반복.
트리거: '주문 필드 추가', '주문 마이그레이션', 'order schema'.
주입 컨텍스트: src/modules/order/, prisma/schema.prisma."
A zero-selection answer is fine — skip Step 4 and go to Step 5.
For each candidate the user selected, generate {project}/.claude/skills/{name}/SKILL.md.
When writing each skill:
references/backend-prompt-injection-guide.md for exactly which fields go wherereferences/ and leave only a pointer in the bodyRecord only the generated skill directory tree into CLAUDE.md immediately (separated from the Phase 6 fingerprint finalization). This is a provisional sync that protects against session interruption — it makes recovery possible by recording how far we got.
## 하네스 (Backend) — 빌드 진행 중
**스킬 (Phase 5 완료):**
- order-field-sync
- payment-webhook-scaffold
(fingerprint는 Phase 6에서 확정)
If zero skills were generated, leave this section blank.
If the user picked zero or there were zero candidates, advance to Phase 6 with .claude/skills/ left empty. The build completes normally. The core 6 + 2 leaders + conditional specialists were already created in Phases 3–4, so the harness itself is functional.
The fingerprint's skills_generated field is recorded as an empty array [].
⚠️ Do not force-fill: suppress the instinct to "make at least one anyway". Do not regenerate candidates the user rejected, and do not auto-create things under the label of "built-in skills". Zero means zero.
Remove the provisional sync section from Phase 5 Step 5 and replace it with the final context and fingerprint block. The tdd / implement skills read this block at pipeline execution time and reuse it.
## 하네스 (Backend)
**에이전트 팀:**
| 에이전트 | 역할 | 모델 |
|---------|------|------|
| architect | 설계·아키텍처 분석 | {선택} |
| test-engineer | 테스트 작성 | {선택} |
| ... |
**스킬:**
| 스킬 | 용도 | 사용 에이전트 |
|------|------|-------------|
| ... |
**실행 규칙:**
- **TDD 작업** → `/oh-my-harness:tdd`
- **대규모 구현/리팩토링** → `/oh-my-harness:implement`
- **도메인 특화 작업** → 생성된 오케스트레이터 스킬
<!-- harness-fingerprint v1 -->
skill: harness-be
language: {language}
framework: {framework}
architecture_style: {architecture_style}
data_layer: {data_layer}
api_style: {api_style}
test_stack: {test_stack}
infra: {infra joined}
module_pattern: "{module_pattern}"
existing_modules: {existing_modules joined}
core6_agents: architect, test-engineer, executor, code-reviewer, security-reviewer, debugger
leaders: tdd-leader, team-leader
extra_agents: {list of conditional agents spawned}
skills_generated: {list}
<!-- /harness-fingerprint -->
When invoked as /oh-my-harness:harness-be {feature}, hand off the feature request parsed in Phase 0 to an orchestrator skill or to the implement / tdd skill.
When an existing harness is present and Phase 0 routes here for "maintenance":
.claude/agents/ against the CLAUDE.md table and detect driftSkill gate idempotency: in maintenance mode, the Phase 5 gate is not raised again automatically. Unless the user explicitly requests "review skill candidates again", preserve the existing skills_generated list as-is. If a previous build chose zero, keep the empty array — do not auto-suggest "maybe try generating some this time".
{project}/.claude/agents/architect.md — all of the core 6 agents include a <Project_Context> block{project}/.claude/agents/tdd-leader.md and team-leader.md — pinned to Opus, with <Project_Context>{project}/.claude/agents/ — only the conditional specialists matching detection are generated (no generic "DDD expert"){project}/.claude/skills/ — only the candidates that passed the user gate (zero is valid). If any were generated, the names are derived from project module names / domain terms (no generics like migration-check / api-workflow){project}/CLAUDE.md — the Phase 5 Step 5 provisional sync is replaced by the final fingerprint block in Phase 6 (skills_generated may legitimately be an empty array)references/backend-detection-protocol.mdreferences/backend-prompt-injection-guide.md../harness/references/project-analysis-protocol.md../harness/references/agent-design-patterns.md../harness/references/skill-writing-guide.md