[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6RVVQN23XMZ0AT676R5CFNF":3,"skill-same:01M6RVVQN23XMZ0AT676R5CFNF":69},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":22,"publishedAt":40,"linkOnly":41,"markdownContent":42,"markdownBody":43,"frontMatter":44,"refName":50,"commitSha":51,"skillDirectory":52,"forksCount":13,"repositoryHtmlUrl":53,"repositoryHomepageUrl":6,"ownerHtmlUrl":54,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":55,"install":56,"resources":68},"01M6RVVQN23XMZ0AT676R5CFNF","plankton-code-quality",null,"Write-time code quality enforcement using Plankton — auto-formatting, linting, and Claude-powered fixes on every file edit via hooks.","sakamoto-family-smile\u002Fagent_monorepo","sakamoto-family-smile","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F132812403?v=4","01M6RTAT3H8PMWX5SJ65KP3VYF","01M6RTAV321WB5RAHCWTZMX5CV",0,"Apache-2.0","https:\u002F\u002Fgithub.com\u002Fsakamoto-family-smile\u002Fagent_monorepo\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fecc\u002Fplankton-code-quality\u002FSKILL.md",[17],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39],"code","code quality","plankton code quality","quality","plankton","fixes","linting","via","formatting","time","community","enforcement","hooks","auto","edit","write","file","2026-11-10 10:12:30",false,"---\nname: be-jira-auto\ndescription: \"Jira-to-commit orchestrator that implements a ticket's own stated Technical Approach directly when present, or drafts a Proposed Solution and stops for user confirmation when not, classifies the ticket into a tier (easy\u002Fnormal\u002Fextreme) to scale the review gate, and drives the full be-crud -> be-code -> be-verify -> (be-review + be-security) -> be-fix -> be-commit pipeline end to end via the Skill tool, instead of the user running each be-* skill one at a time\"\nargument-hint: \"\u003CJIRA-KEY> [notes: \u003Ctext>]\"\nuser-invocable: true\nallowed-tools: Bash, Read, Write, Edit, Grep, Glob, Skill, Agent, ToolSearch\n---\n\n# be-jira-auto — Jira Auto Orchestrator\n\nOrchestrator skill. Given a Jira issue key, it derives the same inputs a\nhuman would type into `be-crud`\u002F`be-code`, then delegates every actual\nstep to the plugin's own `be-*` skills via the `Skill` tool -- it never\nreimplements scaffold generation, TDD, verification, review, or fix logic\nitself. This skill is the automated counterpart of manually running\n`be-crud` -> `be-code` -> `be-verify` -> `be-review` -> `be-fix` ->\n`be-commit` in sequence (see `CLAUDE.md` § Pipeline).\n\n**A skill, not a subagent, on purpose.** `be-code`, `be-build`, `be-review` and `be-fix` each\nlaunch an agent (`implement`, `build-doctor`, `code-reviewer`, `review-fixer`) with the `Agent`\ntool, and a Claude Code subagent has no `Agent` tool — it cannot spawn subagents. Run as an agent,\nfour of the seven pipeline steps below could not execute as written. As a skill it runs in the\nmain session, where `Skill` and `Agent` both exist.\n\n## Golden Rules\n\n- One skill owns each step (`be-crud`, `be-code`, `be-verify`, `be-build`,\n  `be-review`, `be-fix`, `be-commit`). Call it through `Skill`, read its\n  output, then move on -- never skip a step, never reorder, never\n  reimplement a skill's job inline (the one exception is Step 3.5's\n  scaffold-level extension of an existing entity, for which no skill exists;\n  it follows `be-crud`'s templates).\n- This skill runs unattended: it cannot answer a skill's interactive\n  confirmation prompts mid-run. Resolve every input a skill would\n  otherwise ask for (data profile, domain, fields, scenarios) *before*\n  calling that skill, and pass it explicitly. When a question genuinely\n  cannot be answered from the ticket, stop with `NEEDS-INPUT` rather than\n  guessing.\n- **The ticket's own Technical Approach outranks this skill's judgment.**\n  When the Jira issue already states a technical approach\u002Fsolution, that\n  is the design -- extract from it and implement directly, do not\n  re-derive or second-guess it (see Step 1). Only when the ticket has no\n  stated approach does this skill draft one itself, and a self-drafted\n  design must be confirmed by the user before implementation starts (see\n  Step 1.5) -- a self-drafted design is a proposal, not a mandate.\n- Never skip `be-verify` or `be-review`, even for a ticket that looks\n  small -- CLAUDE.md § Verification Philosophy explicitly rejects \"the\n  change is small, no need to verify\" as a rationalization, and this\n  agent is bound by the same rule. Tiering (see Step 1) only scales\n  whether the parallel `be-security` gate runs alongside `be-review` --\n  it never skips `be-verify` or `be-review` themselves.\n- Never push, open a pull request, or comment on \u002F transition the Jira\n  issue. The plugin's own pipeline (`CLAUDE.md` § Pipeline) ends at\n  `be-commit` -- stay there. Push\u002FPR\u002FJira-status is a manual decision for\n  the user, made outside this skill.\n- Report in the working language read from\n  `.claude\u002Fbackend-webflux-plugin.json` (`workingLanguage`), matching the\n  language every other skill in this plugin already reports in.\n\n## Input Parameters\n\nThe caller (a slash-command invocation, or the top-level session) provides\nthese in the prompt:\n\n- `jiraKey` -- Jira issue key, e.g. `OMH-1234`, `ELS-3225` (required): the first token of the argument\n- `projectRoot` -- the current working directory: every delegated skill, git command and script runs there, so another directory cannot be named\n- `notes` -- (optional) everything after `notes:` in the argument (`\u002Fbackend-webflux-plugin:be-jira-auto OMH-1234 notes: jira-mcp: mcp__atlassian__…; start over`): extra constraints or a preferred approach from the\n  user, carried verbatim into Step 0.5, Step 1, and Step 2 -- this is also\n  where a Jira MCP preference from a prior `NEEDS-INPUT` round comes back\n  in (see Step 0.5)\n\nIf `jiraKey` is missing from the prompt, stop immediately with status\n`NEEDS-INPUT` and a single-sentence request for the key -- do not guess a\nticket.\n\n## Pipeline\n\n### Step 0: Repo Guard\n\n1. Read `.claude\u002Fbackend-webflux-plugin.json` from `projectRoot`.\n2. Missing -- stop with status `ABORTED`: \"backend-webflux-plugin is not\n   initialized in `{projectRoot}` -- run `\u002Fbackend-webflux-plugin:be-init`\n   first.\" Do not guess config values, do not run any git\u002Fgradle command\n   after this.\n3. Record `buildCommand`, `testCommand`, `basePackage`, `sourceDir`,\n   `testDir`, `workDocDir`, `dataProfile`, `webLayer`, `workingLanguage`\n   for use in every later step.\n4. `pluginRoot`: the one line of `${CLAUDE_CONFIG_DIR:-$HOME\u002F.claude}\u002Fplugins\u002Fdata\u002Fbackend-webflux-plugin\u002FpluginRoot` (plugin CLAUDE.md § Configuration) — every `templates\u002F…` path in this document is `{pluginRoot}\u002Ftemplates\u002F…`; missing -- stop with `NEEDS-INPUT`: start a new session so the hook writes it.\n\n### Step 0.5: Discover the Jira MCP Tool\n\nThis skill does not hardcode which Jira integration is wired up -- a\nproject may have a cloud Atlassian connector, a local\u002Fself-hosted MCP\ngateway, or both, and the exact tool name differs per setup (e.g.\n`mcp__claude_ai_Atlassian__getJiraIssue` vs.\n`mcp__MCP_DOCKER__getJiraIssue`). Resolve it once, at the start:\n\n1. If `notes` already states a Jira MCP preference from a prior\n   `NEEDS-INPUT` round (see below), use it directly and skip to Step 1 --\n   never re-discover once the user has already picked one for this run.\n2. Otherwise call `ToolSearch` with a keyword query such as\n   `\"jira issue get\"` (and, if that returns nothing, a broader `\"jira\"`)\n   to enumerate every connected MCP tool that can fetch a single issue by\n   key -- look for names ending in something like `getJiraIssue` \u002F\n   `get_issue` under any `mcp__\u003Cserver>__...` prefix.\n3. **Exactly one candidate** -- load it, use it for the rest of this run,\n   and record which server it came from for the final report (\"Jira\n   source: {server}\"). Also resolve that same server's JQL-search\n   counterpart (e.g. `searchJiraIssuesUsingJql` \u002F `search_issues`) the\n   same way, for the related-ticket check in Step 1 -- it is optional, so\n   proceed without it if the server does not expose one.\n4. **Zero candidates** -- stop with status `NEEDS-INPUT`: no Jira MCP tool\n   is connected in this session; ask the user to connect one (cloud\n   Atlassian connector or a local MCP gateway) and re-invoke.\n5. **More than one candidate** -- stop with status `NEEDS-INPUT`, listing\n   every candidate found (server name + tool name), and ask the user to\n   pick one. On the next invocation, expect the choice back via `notes`\n   (e.g. `\"jira-mcp: mcp__claude_ai_Atlassian\"`) and use point 1 above --\n   never guess between two connected Jira sources, since they can point\n   at different Jira instances entirely.\n\n### Step 1: Understand the Ticket\n\nRead `agents\u002Fbackend-planner.md` first -- this step and Step 1.5 apply its\nPhase 1 (existing-code scan) and Phase 2 (spec-to-CQRS mapping) rules by\nreference throughout; without reading it here those rules are not actually\nin context when this step needs to apply them, since a fresh agent\ninvocation does not inherit any other agent's file reads.\n\nCall the issue-lookup tool resolved in Step 0.5 with `{jiraKey}`.\n\n1. Read summary, description, acceptance criteria, comments, linked\n   issues. If a JQL-search counterpart was also resolved in Step 0.5, use\n   it to check for related tickets already in flight if the description\n   references one -- skip this check when no search tool was found.\n\n2. **Check whether the ticket already states a technical approach.**\n   Look at the description and comments for an explicit\n   approach\u002Fsolution section -- a heading or clearly-labeled block such\n   as \"Technical Approach\", \"Solution\", \"Technical Design\",\n   \"Implementation Approach\", or the Vietnamese equivalents (\"Giải pháp\n   kỹ thuật\", \"Giải pháp\", \"Hướng triển khai\") -- typically written by a\n   tech lead\u002Farchitect as part of grooming, not just a passing mention of\n   a class name in a comment.\n\n   - **Found**: this is the binding design. Extract the entity list,\n     `field:Type` pairs, endpoints, exceptions, and the extend-vs-new-entity\n     call directly from what it states -- do not re-derive or replace a\n     product\u002Fdesign decision the approach already made. Apply\n     `agents\u002Fbackend-planner.md` Phase 2's mapping rules only to fill in\n     mechanical detail the approach left implicit (e.g. it says \"add a\n     `status` field\" without naming a column type that\n     `templates\u002Fentity-conventions.md` already standardizes). Skip Step\n     1.5 -- go straight to Step 2 once the extraction below is complete.\n   - **Not found**: investigate the existing codebase yourself -- scan\n     `{sourceDir}\u002F{basePackage}\u002Fdata\u002F` for entities that already exist,\n     scan `{sourceDir}\u002F{basePackage}\u002F` for existing domain packages, and\n     glob `src\u002Fmain\u002Fresources\u002Fmigration\u002F` for the next migration version\n     (mirror `agents\u002Fbackend-planner.md` Phase 1's scan). Draft a\n     **Proposed Solution** using Phase 2's mapping rules from the\n     summary\u002Fdescription\u002FAC alone. This proposal is not authoritative --\n     Step 1.5 must confirm it with the user before Step 2 touches\n     anything.\n\n3. Either way, resolve and write down before moving on (from the stated\n   approach when found, from the draft otherwise):\n   - Whether this ticket needs a brand-new entity (`be-crud` applies) or\n     only extends an existing one (`be-crud` does not apply -- see Step\n     3.5).\n   - The domain (one lowercase package segment, `[a-z][a-z0-9]*` — no hyphen, it\n     is spliced into `package …{domain}.api;`; used for the `{domain}\u002Fapi` package and the\n     URL prefix).\n   - The entity list, in FK-dependency order if more than one (referenced\n     entity first) -- same rule as `agents\u002Fbackend-planner.md` § 2.8.\n   - Per entity: `field:Type` pairs, validation rules, exceptions with\n     their HTTP status, endpoints (method, path, status code).\n   - Test scenarios: single sentence, present tense, lowercase first word\n     (usable as a snake_case test method name), `- [ ]` checkbox format,\n     per `templates\u002Ftest-scenario-template.md`.\n   - **Tier** -- classify the ticket to scale the Step 7 gate:\n     - `easy`: no new entity, no new public endpoint -- a logic\u002Fbug fix on\n       code that already exists.\n     - `normal`: one new entity scaffolded (one `be-crud` call), or one or\n       more new public endpoints on existing entities, within one domain.\n     - `extreme`: more than one new entity, or the change spans more than\n       one domain\u002Fmodule.\n     Tier never changes whether `be-verify`\u002F`be-review` run (see Golden\n     Rules) -- it only decides whether the parallel `be-security` gate in\n     Step 7 is mandatory. Regardless of tier, force `be-security` to run\n     if the ticket description\u002FAC mentions anything security-sensitive\n     (auth, permission, PII, payment, token, secret) -- tier is a\n     complexity signal, not a security override.\n\n4. **Gap inside a stated approach**: if a found Technical Approach leaves\n   something genuinely unresolved (a field with no declared type, a\n   business rule with no stated behavior) -- stop with status\n   `NEEDS-INPUT`, quoting the exact gap. Never fill it with a guess just\n   because \"most of the approach\" was already clear.\n\n### Step 1.5: Confirm the Proposed Solution (only when Step 1 found no stated approach)\n\nSkip this step entirely when Step 1 extracted from a stated Technical\nApproach -- re-confirming the ticket author's own design back to them is\nredundant, and the Golden Rule above says implement it directly.\n\nWhen Step 1 had to draft its own Proposed Solution:\n\n1. Stop the run here with status `NEEDS-INPUT`, before Step 2 touches git\n   or anything else. Report the full Proposed Solution exactly as Step\n   3\u002F3.5\u002F4 would consume it (entity list, fields\u002Ftypes, endpoints,\n   exceptions, extend-vs-new-entity call per entity, migration strategy\n   for any \"extend\" entity, tier), plus up to 3-5 open questions -- points\n   the draft had to guess where a wrong guess would change the design.\n2. On the *next* invocation, the caller passes the user's confirmation or\n   corrections back via the `notes` input parameter. Treat `notes` as\n   amending the Proposed Solution (apply corrections literally, do not\n   reinterpret them) and proceed straight through to Step 2 -- do not\n   re-enter Step 1.5 for the same ticket. If `notes` itself leaves a point\n   unresolved, that is an ordinary Step 1 point 4 gap, not a reason to\n   loop back into another proposal-and-confirm round.\n\n### Step 2: Prepare the Branch\n\n1. `git status --porcelain -z` (NUL-separated, the form Step 9 diffs against). Paths under `{workDocDir}\u002F.progress\u002F` and `.claude\u002Fbackend-webflux-plugin.json` are this plugin's own bookkeeping and never count as dirty (the run state above is written before any branch exists). Not clean otherwise -- stop with `NEEDS-INPUT`: ask the\n   user to commit or stash their own in-progress work first. Never run\n   `git stash` or `git checkout .` to clear it yourself. **Exception -- a\n   resume of this ticket:** when the current branch already carries\n   `{jiraKey}` (item 2) and every dirty path lies under `{sourceDir}`,\n   `{testDir}`, `src\u002Fmain\u002Fresources\u002F`, `config\u002F`, `gradle\u002F`, `buildSrc\u002F`,\n   `{workDocDir}`, or is a `build.gradle(.kts)` \u002F `settings.gradle(.kts)` \u002F\n   `gradle.properties` \u002F `gradlew` file (be-crud edits `application.yml`,\n   `be-build` may edit the build) **and is in the run state's `dirty`\n   list** (a path that is not was edited during the pause: stop with\n   `NEEDS-INPUT` naming it — two exceptions: the security fix a Step 7 stop\n   asked for, when its paths lie under `{sourceDir}`, `{testDir}` or\n   `src\u002Fmain\u002Fresources\u002F` (be-security's credential rules point at\n   `application*.yml`), and a resume with no run state or after a crash,\n   when `notes` says `own-dirty` — the user vouching that every dirty path\n   is this pipeline's), the\n   tree is this pipeline's own in-progress work left by a `NEEDS-INPUT` exit (a\n   three-failure pause, a security finding, an escalation); keep it and\n   continue from the step and feature `{workDocDir}\u002F.progress\u002Fjira\u002F{jiraKey}.json`\n   names (written at every early stop and after the commit -- see Gates;\n   absent → `NEEDS-INPUT` asking which step; `committed`\u002F`DONE` → the\n   ticket is finished: stop and say so, a fresh run on the same branch\n   starts over at Step 3 only when the user asks for it in `notes`). The\n   feature's own progress file wins over an older state: a step the state\n   names that the feature has already passed by hand (`done` on the current\n   tree, `verification.committed`) is skipped, not replayed. Then,\n   **capped at Step 6 when\n   the code changed since it was verified**: a report naming Step 7, 8 or 9\n   re-enters at Step 6 instead whenever `{pluginRoot}\u002Fscripts\u002F\n   source-tree-hash.sh` (exit 0 and a 40-hex id, else `NEEDS-INPUT`: the\n   tooling is broken, or the `{pluginRoot}` file is missing -- start a new session)\n   differs from the feature's\n   `pipeline.verification.tree` (a manual security fix, an escalation\n   resolved by hand: the review that may already have written `done`\n   describes the old tree). A report naming Step 3, 4 or 5 resumes there\n   regardless -- the work is not finished, and verifying it would only\n   certify a subset. Any dirty path outside those locations is still\n   someone else's work: stop.\n2. If the current branch name already starts with `{jiraKey}` followed by\n   a `-` or `_` (case-insensitive) -- not merely *contains* it, since\n   `jiraKey = \"OMH-10\"` is a substring of an unrelated branch named\n   `OMH-100-refactor-pricing` -- stay on it -- skip branch creation, note\n   this in the final report, and read the run state (item 1) even when the\n   tree is clean: a `committed`\u002F`DONE` ticket is not implemented twice.\n3. Otherwise: resolve the default branch\n   (`git symbolic-ref refs\u002Fremotes\u002Forigin\u002FHEAD`, falling back to `main`\n   then `master`); with no `origin` remote (`git remote get-url origin`\n   fails — a local-only checkout) skip the fetch and branch from the local\n   default branch, saying so in the report; otherwise `GIT_TERMINAL_PROMPT=0 GIT_SSH_COMMAND=\"ssh -o BatchMode=yes\" git fetch` (an expired credential, a passphrase or an unknown host key must fail, not prompt an unattended run — `GIT_TERMINAL_PROMPT` covers git's own credential prompt only, `BatchMode` covers SSH's), then\n   `git checkout -b {jiraKey}-{slug} origin\u002F{default}` -- with the start\n   point spelled out; without it the branch forks from whatever HEAD is. `{slug}` is a short kebab-case form of the Jira summary (up to\n   ~5 meaningful words).\n4. Confirm the working tree is on the right branch and clean -- or, on a\n   resume, dirty only under item 1's locations -- before Step 3.\n\n### Step 3: Scaffold (conditional) -- `be-crud`\n\nOnly for entities Step 1\u002F1.5 marked as brand-new, in dependency order:\n\n```\nSkill(skill: \"backend-webflux-plugin:be-crud\", args: \"{EntityName} field1:Type1[:unique][:nullable][:max=N][:pattern=email|phone|url] ... --domain {domain} --profile {r2dbc|mybatis}\")\n```\n\n- Before the first call, look for `{workDocDir}\u002F.progress\u002F{kebab-case-entity}.json` for **every**\n  entity to scaffold: one at `implementing` or later (`scaffolded` does not prompt) → `be-crud`'s\n  Step 2.5 would ask \"Continue?\" — stop with `NEEDS-INPUT` naming the entity before anything is\n  written, unless `notes` says to start it over, in which case add `--yes`.\n- `--domain` and `--profile` are the answers `be-crud` would otherwise ask\n  for; passing them is what keeps this run unattended -- both were already\n  decided in Step 1. The field flags carry what Step 1 read off the ticket:\n  a field the ticket calls unique gets `:unique` (that is the only thing that\n  makes `be-crud` emit the `existsBy` pre-check, the named constraint mapping\n  and `Duplicate{Field}Exception`), a bounded one `:max=N`, an email\u002Fphone\u002F\n  url one `:pattern=…`. A field the ticket calls optional gets `:nullable` — without it the column is `NOT NULL` and a \"request without {field}\" scenario fails at the database. A flag left off is a validator (or a nullability) that does not exist. If `config.dataProfile == \"both\"` and the skill still\n  prompts, answer with the value decided in Step 1 (default `r2dbc` unless\n  Step 1 found a reason to match an existing `mybatis` module).\n- Entity already exists (extend, not create): do **not** call `be-crud` --\n  see Step 3.5 instead.\n- No entity involved at all (pure logic\u002Fbug-fix ticket on an existing\n  endpoint): note \"Step 3: skipped -- no new entity\" and continue to Step 4.\n\n### Step 3.5: Extend an Existing Entity (conditional) -- this skill's own tools\n\nFor every entity Step 1\u002F1.5 marked \"extend, not create\", performed by\nthis skill directly (`Write`\u002F`Edit`\u002F`Bash`), **before** Step 4 authors the\nwork document -- schema, entity field and mapping are scaffold, the same\nkind of untested output `be-crud` produces for a new entity (behavior is\nstill written RED → GREEN by `be-code` in Step 5); there is no \"alter\"\nskill in this plugin, so this is not\n`be-crud`'s job and not `implement`'s job either; `implement` only ever\nsees a scenario list, never \"this entity needs a new column\" as a task in\nits own right:\n\n1. Determine `{next}` the same way `skills\u002Fbe-crud\u002FSKILL.md`'s Shared\n   Derivation Rules do (glob `src\u002Fmain\u002Fresources\u002Fmigration\u002FV*__*.sql`,\n   take the max version + 1), and write\n   `src\u002Fmain\u002Fresources\u002Fmigration\u002FV{next}__alter_{snake_case_table}_add_{field}.sql`\n   with the new column(s) -- one migration per entity, even when it gains\n   more than one field.\n2. Edit the entity class (R2DBC: `@Column`-annotated field; MyBatis: plain\n   field + the corresponding `\u003Cresult>` mapping in `{EntityName}Mapper.xml`)\n   directly, following `templates\u002Fentity-conventions-r2dbc.md` or\n   `templates\u002Fentity-conventions-mybatis.md` conventions matching the entity's\n   profile (Lombok `@Getter`\u002F`@Setter` when `config.lombokEnabled == true`) -- so\n   the class already compiles with the new field before `be-code`'s TDD\n   cycle starts.\n3. Add a repository\u002Fmapper query method only if a scenario in Step 1\u002F1.5\n   actually needs one (e.g. `existsBy{NewField}` for a uniqueness check);\n   otherwise leave the repository\u002Fmapper untouched. A field the ticket calls\n   **unique** gets the same three parts `be-crud` emits for one: the ALTER\n   migration adds `CONSTRAINT uk_{table}_{column} UNIQUE ({column})` (the\n   `existsBy` pre-check alone is a race -- two concurrent creates both pass\n   it, and only the constraint stops the second row), the executor maps a\n   `DataIntegrityViolationException` naming that constraint to\n   `Duplicate{Field}Exception`, and the web layer maps that to 409.\n4. Do not touch command\u002Fquery\u002Fview DTOs or router\u002Fhandler code here --\n   that is ordinary TDD scope and belongs to `be-code` in Step 5, exactly\n   like any other scenario.\n\n### Step 4: Author the Work Document Before Calling `be-code`\n\nMandatory, even when Step 3 already generated\n`{workDocDir}\u002F{kebab-case-entity}.md` via `be-crud` -- this skill cannot\nanswer `be-code`'s \"review and confirm to proceed\" prompt (`skills\u002Fbe-code\u002FSKILL.md`\nStep 3), so the work document must already exist and be final before Step\n5 runs.\n\n1. If `{workDocDir}\u002F{feature}.md` already exists (from `be-crud`): merge\n   in any scenario from Step 1 that the default scaffold does not cover\n   (a ticket-specific business rule, a non-CRUD action).\n2. If it does not exist (editing an existing entity, no scaffold run):\n   create `{workDocDir}\u002F{feature}.md` from\n   `templates\u002Fwork-document-template.md` with the scenario list decided\n   in Step 1, `- [ ]` format, no `?` markers -- every uncertain scenario\n   must already have been resolved in Step 1; nothing marked `?` reaches\n   this file, since nobody is present to confirm or drop it.\n3. `feature` = kebab-case of the primary entity name, or kebab-case of\n   `{jiraKey}` when the ticket is not centered on one entity.\n4. **Every entity Step 3 scaffolded is a feature of its own**: `be-crud`\n   wrote `{workDocDir}\u002F{kebab-case-entity}.md` for each, so do items 1-2\n   for each of them, not only for the primary -- a secondary entity whose\n   document is left at the scaffold's defaults never reaches `be-code`,\n   `be-verify` or `be-review`. Keep the list (`features`, in Step 1's\n   dependency order); Steps 5-8 iterate it.\n\n### Step 5: Implement (TDD) -- `be-code`\n\nFor each entry of `features` (Step 4 item 4), in dependency order:\n\n```\nSkill(skill: \"backend-webflux-plugin:be-code\", args: \"{workDocDir}\u002F{one feature}.md --yes\")\n```\n\n- Because the work document already exists, `be-code` enters file-path\n  mode directly (its Step 1 -> Step 3.5) and skips the interactive\n  approval flow entirely. `--yes` answers its demotion prompt: a second\n  ticket on an existing entity finds `.progress\u002F{feature}.json` at `done`\n  from the first, and re-implementing it is exactly what this ticket asks\n  for — the prompt is the operator's, and here the operator is Step 1.\n- The skill runs RED -> GREEN per scenario and writes its own tests --\n  there is no separate \"write unit tests\" step in this plugin's pipeline.\n- If `be-code`'s own report leaves `pipeline.status` at `\"implementing\"`\n  with a scenario unfinished (3 consecutive failures) -- stop with\n  `NEEDS-INPUT`, naming exactly which scenario is unfinished and the\n  reason the skill reported. If every scenario is `- [x]` and only its\n  final full build failed (checkstyle first runs there, never in the\n  per-class cycles) -- go to Step 6.1: that is what `be-build` is for.\n\nSteps 6–8 run **per entry of `features`** (Step 4 item 4): `{feature}` below is the one being\nprocessed, and a FAIL on any entry stops the run at that entry (later entries depend on it).\n\n### Step 6: Verify -- `be-verify`\n\n```\nSkill(skill: \"backend-webflux-plugin:be-verify\", args: \"{feature} --yes\")\n```\n\n- `--yes` answers `be-verify`'s demotion\u002Fstaleness confirmations (a resume re-entering here from `reviewed`\u002F`done`\u002F`escalated`) — this run decided the re-entry; the report is still read in full. A `be-verify`\u002F`be-review` stop on unfinished `- [ ]` scenarios (a work document edited during a pause) is `NEEDS-INPUT` naming them: the scenario has to go through Step 5 first.\n- Read the 5-row report (Compilation\u002FCheckstyle\u002FTests\u002FBuild\u002FCoverage).\n- The coverage percentage is report-only (`docs\u002Fdecisions.md` Decision 6)\n  -- carry it into the final report, never treat the number as a failure\n  condition. A Coverage row that FAILS (no report produced) is part of\n  `Overall`, like any other row.\n- Overall PASS -- go to Step 7.\n- Overall FAIL -- go to Step 6.1.\n\n#### Step 6.1: Auto-fix the build -- `be-build` (at most one call)\n\n```\nSkill(skill: \"backend-webflux-plugin:be-build\", args: \"\")   # be-build takes no argument: it builds the project, not a feature\n```\n\n`be-build` already retries internally up to 3 times -- call it **once**,\nnever wrap it in an outer retry loop of this skill's own. Then re-run\n`be-verify {feature} --yes` once to confirm:\n\n- PASS -- go to Step 7.\n- Still FAIL -- stop with status `ABORTED`, listing the exact FAIL rows\n  from the latest `be-verify` report.\n\n### Step 7: Gate -- `be-review` (always) + `be-security` (tiered)\n\nA `Skill` call loads that skill's steps into this same session -- nothing\nruns in parallel, and two multi-step procedures loaded in one turn\ninterleave their stops and lock handling. Run them one after the other,\n`be-security` first (read-only, no lock, no report file -- its findings\nare read from its own output before `be-review`'s steps begin):\n\n```\nSkill(skill: \"backend-webflux-plugin:be-security\", args: \"\")   # no argument = its default scope: the whole base package plus src\u002Fmain\u002Fresources (a dotted basePackage is not a path)\nSkill(skill: \"backend-webflux-plugin:be-review\", args: \"{feature} --yes\")\n```\n\nRun `be-security` when tier is `normal` or `extreme`, or when Step 1's\nsecurity-sensitive override fired regardless of tier. At `easy` tier with\nno override, skip it -- note \"Step 7: be-security skipped -- easy tier, no\nnew entity\u002Fendpoint surface\" and treat this step as `be-review`-only.\n\n**`be-review` branch:**\n- **First, confirm `be-review` wrote a verdict in this call**: read\n  `{workDocDir}\u002F.progress\u002F{feature}.json` — `pipeline.status` must now be\n  `reviewed`, `done` or `review-failed` (be-review sets one of them only\n  after saving the report). Still `verified`: be-review stopped without\n  writing (its Step 3.5 validation failed), and the\n  `review-report-{feature}.json` on disk is a previous round's or ticket's\n  — nothing removes old reports. Stop with `NEEDS-INPUT` quoting be-review's\n  own stop message; never read the report in that case.\n- Then read `review-report-{feature}.json` (path returned by\n  `skills\u002Fbe-review\u002FSKILL.md` Step 4): verdict, critical\u002Fwarning\u002F\n  suggestion counts.\n- Verdict PASS -- with or without warnings\u002Fsuggestions -- and no security\n  block (below): skip Step 8, go straight to Step 9. A PASS with warnings\n  leaves the feature `reviewed`, and `be-fix` on a `reviewed` feature asks\n  \"Continue?\" (its Step 2.5 demotion check) -- a prompt this run cannot\n  answer. Carry the warnings into the Step 10 summary instead.\n- Verdict FAIL -- go to Step 8.\n\n**`be-security` branch (when run):**\n- `be-security` has no persisted report file and no `be-fix` integration\n  in this plugin -- read its findings directly from the skill's own\n  report text (Critical \u002F Warnings \u002F Suggestions, per\n  `skills\u002Fbe-security\u002FSKILL.md` Step 4).\n- **Any Critical finding blocks the pipeline.** There is no automated\n  security-fix skill in this plugin, so do not attempt to route these\n  into `be-fix` or fix them inline yourself. Stop with status\n  `NEEDS-INPUT`, quoting every Critical finding verbatim (`file:line`,\n  description, suggestion) and asking the user to fix them manually (or\n  via a manual `be-code`\u002F`implement` edit), then re-run\n  `\u002Fbackend-webflux-plugin:be-security` to confirm before resuming this\n  agent — the resume re-enters at Step 6, not here: the fix changed the\n  tree, and the `be-review` that ran alongside may already have written\n  `reviewed`\u002F`done` for code that no longer exists (Step 2's tree rule).\n- Warnings\u002FSuggestions are non-blocking -- carry them into the Step 9\u002Ffinal\n  report as-is; they do not gate progression to Step 8\u002F9.\n\n### Step 8: Fix Loop (conditional, at most 2 rounds) -- `be-fix` -> `be-verify` -> `be-review`\n\n```\nSkill(skill: \"backend-webflux-plugin:be-fix\", args: \"{feature}\")\n```\n\nthen -- a fix changed code, and `be-review` refuses a `fixing` feature until it is re-verified:\n\n```\nSkill(skill: \"backend-webflux-plugin:be-verify\", args: \"{feature} --yes\")\n```\n\n(`Overall: FAIL` here → one `be-build` + re-verify exactly as Step 6.1; still FAIL → `ABORTED`.) Then\n\n```\nSkill(skill: \"backend-webflux-plugin:be-review\", args: \"{feature} --yes\")\n```\n\n(the same freshness check as Step 7: `pipeline.status` must have left\n`verified`, or the report on disk is stale — `NEEDS-INPUT`.)\n\n- **Read `pipeline.fix.round` before every `be-fix` call**, not only the\n  first. The counter persists across runs (be-review zeroes it only on a\n  clean PASS, be-commit only before a commit); if it is already >= 2, one\n  more call reaches round 3 and `be-fix` Step 3's \"Continue anyway?\"\n  prompt -- stop with `NEEDS-INPUT` instead of calling. (A feature\n  entering at round 1 passes the first check and would reach round 3 on\n  the second call without this.)\n- **Read `{workDocDir}\u002F.progress\u002Ffix-report-{feature}.json` (the path\n  `pipeline.fix.reportFile` records) and `pipeline.status` before calling\n  `be-verify`\u002F`be-review`.** If `escalated[]` is non-empty, or the status\n  is `escalated` (the post-fix build failed even with every issue marked\n  fixed -- `be-verify` would prompt on it) -- stop with `NEEDS-INPUT` and\n  list the escalated issues, or the build failure, verbatim. A partially escalated fix is a known unresolved issue;\n  re-verifying and re-reviewing around it can PASS-with-warnings and reach\n  the commit with that issue still open. (`be-review` refuses `escalated`\n  outright, and `be-verify` would re-admit the partial fix silently.)\n- **Hard bound: call `be-fix` at most 2 times** for a given feature.\n  Reason: `skills\u002Fbe-fix\u002FSKILL.md` Step 3 blocks on a \"Continue anyway?\n  (y\u002Fn)\" prompt once `pipeline.fix.round >= 3` -- a third call would hang\n  on a prompt this unattended agent cannot answer, so it must never be\n  made.\n- If review is still FAIL, or still has a `critical` issue, after 2\n  rounds -- stop with status `ABORTED`, listing the remaining issues\n  verbatim (severity, `file:line`, message) from the latest\n  `review-report-{feature}.json`. Never assume issues are resolved without\n  a report confirming it.\n- Review PASS (even with non-critical suggestions) after round 1 or 2 --\n  stop the loop, go to Step 9.\n\n### Step 9: Stage and Commit -- `be-commit`\n\n0. Settle the tree first: Steps 6–8 ran per feature, and a later feature's\n   `be-fix`\u002F`be-build` changed the tree every earlier feature was verified\n   on. For each feature (in `features` order) whose\n   `pipeline.verification.tree` differs from the current\n   `{pluginRoot}\u002Fscripts\u002Fsource-tree-hash.sh`, run\n   `be-verify {feature} --yes` then `be-review {feature} --yes` (Step 7's\n   freshness check applies); a FAIL goes\n   through Step 8 for that feature (its bounds apply). A pass that changed\n   nothing settles the tree; a pass in which a fix changed it is followed by\n   at most **one** more pass -- two features whose fixes keep invalidating\n   each other do not converge, so a third pass is `NEEDS-INPUT` naming both.\n1. Diff the current `git status --porcelain -z` (NUL-separated: a quoted\n   or renamed record is otherwise misread) against the Step 2 baseline\n   (captured before any implementation work) to get the exact set of\n   files this feature touched. On a resume, the baseline already held this\n   pipeline's own dirty files (Step 2's exception) -- add the paths the\n   run state's `dirty` list names (the pipeline's own files at the last\n   stop) as well, or the migration and entity from the first run are\n   never staged and the commit is a partial feature. A dirty path under\n   the Step 2 locations that is in neither set was edited by someone\n   during the pause: stop with `NEEDS-INPUT` naming it rather than commit\n   it as this ticket's work — unless Step 2 admitted it (a security fix,\n   or `notes: own-dirty`), in which case it is staged with the rest.\n2. `git add \u003Cfile1> \u003Cfile2> ...` -- name every file explicitly. Never\n   `git add -A` or `git add .`.\n2a. `be-commit` Step 1.5 asks \"Continue with commit?\" whenever ANY other\n   feature under `{workDocDir}\u002F.progress\u002F` is not `reviewed`\u002F`done` -- a\n   prompt this run cannot answer. Read every progress file first — this\n   feature's included: it must be `reviewed` or `done`, and any file in\n   any other status stops the run with `NEEDS-INPUT` naming it instead of\n   calling `be-commit`. Its Step 1.5\n   also prompts when a `reviewed`\u002F`done` feature not yet\n   `pipeline.verification.committed` has a `pipeline.verification.tree`\n   that differs from `{pluginRoot}\u002Fscripts\u002Fsource-tree-hash.sh\n   --staged` -- compute that once after item 2 and compare; after item 0 a\n   mismatch here means item 2 missed a file: stage it (a file outside the\n   Step 2 locations is not this feature's -- stop with `NEEDS-INPUT`).\n3. ```\n   Skill(skill: \"backend-webflux-plugin:be-commit\", args: \"topic: {jiraKey} \u003Cone-line summary>\")\n   ```\n4. Read `be-commit`'s own report; take the short hash from the\n   `git rev-parse --short HEAD` output it printed -- never fabricate one --\n   and write it to the run state at once (`status: committed`, `commit`).\n5. **Do not push, do not open a pull request, do not transition or\n   comment on the Jira issue.** This is the pipeline's final step, exactly\n   as `CLAUDE.md` § Pipeline defines it (`be-plan -> be-crud -> be-code ->\n   be-verify -> be-review \u003C-> be-fix -> be-commit`, no push\u002FPR step).\n\n## Gates (fail fast)\n\n| Gate | Condition to proceed | On failure |\n|---|---|---|\n| Step 0 | `.claude\u002Fbackend-webflux-plugin.json` exists | `ABORTED` -- tell the user to run `be-init` |\n| Step 0.5 | Exactly one Jira MCP tool resolved (or one already confirmed via `notes`) | `NEEDS-INPUT` -- report zero or multiple candidates found, ask the user to connect\u002Fpick one |\n| After Step 1 | Stated approach has no gap, or a Proposed Solution was fully drafted | `NEEDS-INPUT` -- quote the exact gap in the stated approach |\n| Step 1.5 | Only when Step 1 drafted its own proposal (no stated approach): user has confirmed\u002Fcorrected it | `NEEDS-INPUT` -- report the full proposal + open questions, stop before any git\u002Fscaffold action |\n| Step 2 | Working tree clean before branching | `NEEDS-INPUT` -- ask the user to handle their own uncommitted work |\n| After Step 5 | `be-code` reports every scenario `- [x]` | `NEEDS-INPUT` -- name the unfinished scenario\u002Fentity (a failed final build with every scenario done goes to Step 6.1 instead) |\n| After Step 6\u002F6.1 | `be-verify` Overall PASS (one `be-build` attempt allowed) | `ABORTED` -- list the FAIL rows |\n| Step 7 (`be-security` branch) | Zero Critical findings (when the gate ran) | `NEEDS-INPUT` -- quote every Critical finding, ask for a manual fix |\n| After Step 8 | `be-review` verdict PASS (at most 2 `be-fix` rounds) | `ABORTED` -- list remaining critical\u002Fwarning issues |\n| Step 9 | `be-commit` exits 0 with a confirmed short hash | Report the commit failure verbatim, stop -- no retry |\n\nEvery early stop (`NEEDS-INPUT`\u002F`ABORTED`) writes the run state to\n`{workDocDir}\u002F.progress\u002Fjira\u002F{jiraKey}.json` (`mkdir -p` first; no lock — the file is this run's alone, not a feature's\nprogress file; a stop before Step 0 resolved `workDocDir` or `jiraKey`\nwrites nothing — there is nothing to resume; a field not known yet is\n`null`, `features` `[]`) — a\nsubdirectory, so the\n`.progress\u002F*.json` scans of be-commit and the other skills never read it\nas a progress file — `{ \"step\": \"{N}\", \"status\": \"NEEDS-INPUT|ABORTED|\ncommitted|DONE\", \"feature\": \"{the entry being processed}\", \"features\":\n[...], \"dirty\": [\"{every path `git status --porcelain -z` lists under the\nStep 2 locations at this stop -- the pipeline's own files}\"], \"commit\":\n\"{short hash, once be-commit returned it}\", \"timestamp\": \"{ISO 8601 Z}\" }`. Step 9 item 4 writes `committed` with the hash the\nmoment be-commit reports it (a crash before `DONE` must not replay the\ncommit); the Output section writes `DONE`. Step 2 reads it whenever the\nbranch carries `{jiraKey}` (a resume with no file stops with `NEEDS-INPUT`\nasking which step to resume at) — and every stop must report which\npipeline step it stopped at and the current `pipeline.status` for each affected feature\n(read from `{workDocDir}\u002F.progress\u002F{feature}.json` when it exists), so the\nuser knows exactly which `be-*` skill to resume with by hand. Never stop\nsilently.\n\n## Anti-patterns\n\n- Assuming a specific Jira MCP server name instead of resolving it via\n  `ToolSearch` in Step 0.5 -- the tool that exists in one project's\n  session (cloud connector, local gateway, or something else entirely)\n  is not guaranteed to exist, or be the right one, in another's.\n- Guessing which Jira MCP tool to use when `ToolSearch` returns more than\n  one candidate -- two connected Jira sources can point at two different\n  Jira instances; stop and ask instead of picking one silently.\n- Re-deriving a design the ticket's own Technical Approach already states\n  -- extract from it, do not second-guess a decision the ticket already\n  made.\n- Implementing a self-drafted Proposed Solution (Step 1.5) without\n  stopping for confirmation first -- a self-drafted design is a\n  proposal, not a mandate, and this skill has no way to detect the user\n  silently disagreed with it once code already exists.\n- Calling `be-crud` on an entity that already exists (discards its\n  pipeline history -- see `skills\u002Fbe-crud\u002FSKILL.md` Step 2.5).\n- Letting `be-code` draft scenarios and wait for interactive approval\n  instead of authoring the work document up front in Step 4.\n- Calling `be-fix` a third time on the same feature (hangs on the\n  round-3 confirmation prompt).\n- Skipping `be-verify` or `be-review` because the ticket looks small (tier\n  only scales the `be-security` gate, never these two).\n- Routing a `be-security` Critical finding into the `be-fix` loop, or\n  fixing it inline -- there is no automated security-fix contract in this\n  plugin; stop with `NEEDS-INPUT` instead.\n- Loading `be-review` and `be-security` in the same turn \"to run them\n  concurrently\" -- a `Skill` call runs inline in this session; two loaded\n  at once interleave their stops and lock handling. `be-security` first,\n  then `be-review`.\n- Running `git add -A`\u002F`git add .`, or `git stash`\u002F`git checkout .` to\n  discard the user's own uncommitted work without asking.\n- Pushing, opening a pull request, or commenting on \u002F transitioning the\n  Jira issue -- none of that is part of this plugin's pipeline, and none\n  of it has this skill's explicit authorization to act on the user's\n  behalf.\n- Reporting `DONE` without a real short hash confirmed via\n  `git rev-parse --short HEAD`.\n\n## Output\n\nWrite `{workDocDir}\u002F.progress\u002Fjira\u002F{jiraKey}.json` with the final status (`DONE` closes the\nresume path: a later run on the same branch starts over at Step 3 only with the user's say-so),\nthen report, in `workingLanguage`, starting with a status line:\n\n```\nStatus: DONE | NEEDS-INPUT | ABORTED (stopped at Step N)\n\nJira: {jiraKey} -- {summary}\nJira source: {mcp server resolved in Step 0.5}\nApproach: {\"ticket-stated\" | \"proposed, confirmed via notes on {date}\"}\nTier: {easy|normal|extreme}\nBranch: {branch}\nEntities\u002Ffeatures: {list}\nFiles changed: {count}\nVerify: {PASS\u002FFAIL per row}\nReview: {overallScore}\u002F10, {critical} critical fixed over {round} be-fix round(s)\nSecurity: {\"not run (easy tier)\" | \"PASS, N warning(s)\" | \"BLOCKED, N critical\"}\nCoverage: {linePercent}% (report-only)\nCommit: {short hash, or \"none\"}\n\nNot pushed, no pull request opened -- push\u002FPR\u002FJira transition is a manual\nnext step for the user.\n```\n\nFor `NEEDS-INPUT`, the report must contain the exact questions the user\nneeds to answer before re-invoking this skill.\n","# be-jira-auto — Jira Auto Orchestrator\n\nOrchestrator skill. Given a Jira issue key, it derives the same inputs a\nhuman would type into `be-crud`\u002F`be-code`, then delegates every actual\nstep to the plugin's own `be-*` skills via the `Skill` tool -- it never\nreimplements scaffold generation, TDD, verification, review, or fix logic\nitself. This skill is the automated counterpart of manually running\n`be-crud` -> `be-code` -> `be-verify` -> `be-review` -> `be-fix` ->\n`be-commit` in sequence (see `CLAUDE.md` § Pipeline).\n\n**A skill, not a subagent, on purpose.** `be-code`, `be-build`, `be-review` and `be-fix` each\nlaunch an agent (`implement`, `build-doctor`, `code-reviewer`, `review-fixer`) with the `Agent`\ntool, and a Claude Code subagent has no `Agent` tool — it cannot spawn subagents. Run as an agent,\nfour of the seven pipeline steps below could not execute as written. As a skill it runs in the\nmain session, where `Skill` and `Agent` both exist.\n\n## Golden Rules\n\n- One skill owns each step (`be-crud`, `be-code`, `be-verify`, `be-build`,\n  `be-review`, `be-fix`, `be-commit`). Call it through `Skill`, read its\n  output, then move on -- never skip a step, never reorder, never\n  reimplement a skill's job inline (the one exception is Step 3.5's\n  scaffold-level extension of an existing entity, for which no skill exists;\n  it follows `be-crud`'s templates).\n- This skill runs unattended: it cannot answer a skill's interactive\n  confirmation prompts mid-run. Resolve every input a skill would\n  otherwise ask for (data profile, domain, fields, scenarios) *before*\n  calling that skill, and pass it explicitly. When a question genuinely\n  cannot be answered from the ticket, stop with `NEEDS-INPUT` rather than\n  guessing.\n- **The ticket's own Technical Approach outranks this skill's judgment.**\n  When the Jira issue already states a technical approach\u002Fsolution, that\n  is the design -- extract from it and implement directly, do not\n  re-derive or second-guess it (see Step 1). Only when the ticket has no\n  stated approach does this skill draft one itself, and a self-drafted\n  design must be confirmed by the user before implementation starts (see\n  Step 1.5) -- a self-drafted design is a proposal, not a mandate.\n- Never skip `be-verify` or `be-review`, even for a ticket that looks\n  small -- CLAUDE.md § Verification Philosophy explicitly rejects \"the\n  change is small, no need to verify\" as a rationalization, and this\n  agent is bound by the same rule. Tiering (see Step 1) only scales\n  whether the parallel `be-security` gate runs alongside `be-review` --\n  it never skips `be-verify` or `be-review` themselves.\n- Never push, open a pull request, or comment on \u002F transition the Jira\n  issue. The plugin's own pipeline (`CLAUDE.md` § Pipeline) ends at\n  `be-commit` -- stay there. Push\u002FPR\u002FJira-status is a manual decision for\n  the user, made outside this skill.\n- Report in the working language read from\n  `.claude\u002Fbackend-webflux-plugin.json` (`workingLanguage`), matching the\n  language every other skill in this plugin already reports in.\n\n## Input Parameters\n\nThe caller (a slash-command invocation, or the top-level session) provides\nthese in the prompt:\n\n- `jiraKey` -- Jira issue key, e.g. `OMH-1234`, `ELS-3225` (required): the first token of the argument\n- `projectRoot` -- the current working directory: every delegated skill, git command and script runs there, so another directory cannot be named\n- `notes` -- (optional) everything after `notes:` in the argument (`\u002Fbackend-webflux-plugin:be-jira-auto OMH-1234 notes: jira-mcp: mcp__atlassian__…; start over`): extra constraints or a preferred approach from the\n  user, carried verbatim into Step 0.5, Step 1, and Step 2 -- this is also\n  where a Jira MCP preference from a prior `NEEDS-INPUT` round comes back\n  in (see Step 0.5)\n\nIf `jiraKey` is missing from the prompt, stop immediately with status\n`NEEDS-INPUT` and a single-sentence request for the key -- do not guess a\nticket.\n\n## Pipeline\n\n### Step 0: Repo Guard\n\n1. Read `.claude\u002Fbackend-webflux-plugin.json` from `projectRoot`.\n2. Missing -- stop with status `ABORTED`: \"backend-webflux-plugin is not\n   initialized in `{projectRoot}` -- run `\u002Fbackend-webflux-plugin:be-init`\n   first.\" Do not guess config values, do not run any git\u002Fgradle command\n   after this.\n3. Record `buildCommand`, `testCommand`, `basePackage`, `sourceDir`,\n   `testDir`, `workDocDir`, `dataProfile`, `webLayer`, `workingLanguage`\n   for use in every later step.\n4. `pluginRoot`: the one line of `${CLAUDE_CONFIG_DIR:-$HOME\u002F.claude}\u002Fplugins\u002Fdata\u002Fbackend-webflux-plugin\u002FpluginRoot` (plugin CLAUDE.md § Configuration) — every `templates\u002F…` path in this document is `{pluginRoot}\u002Ftemplates\u002F…`; missing -- stop with `NEEDS-INPUT`: start a new session so the hook writes it.\n\n### Step 0.5: Discover the Jira MCP Tool\n\nThis skill does not hardcode which Jira integration is wired up -- a\nproject may have a cloud Atlassian connector, a local\u002Fself-hosted MCP\ngateway, or both, and the exact tool name differs per setup (e.g.\n`mcp__claude_ai_Atlassian__getJiraIssue` vs.\n`mcp__MCP_DOCKER__getJiraIssue`). Resolve it once, at the start:\n\n1. If `notes` already states a Jira MCP preference from a prior\n   `NEEDS-INPUT` round (see below), use it directly and skip to Step 1 --\n   never re-discover once the user has already picked one for this run.\n2. Otherwise call `ToolSearch` with a keyword query such as\n   `\"jira issue get\"` (and, if that returns nothing, a broader `\"jira\"`)\n   to enumerate every connected MCP tool that can fetch a single issue by\n   key -- look for names ending in something like `getJiraIssue` \u002F\n   `get_issue` under any `mcp__\u003Cserver>__...` prefix.\n3. **Exactly one candidate** -- load it, use it for the rest of this run,\n   and record which server it came from for the final report (\"Jira\n   source: {server}\"). Also resolve that same server's JQL-search\n   counterpart (e.g. `searchJiraIssuesUsingJql` \u002F `search_issues`) the\n   same way, for the related-ticket check in Step 1 -- it is optional, so\n   proceed without it if the server does not expose one.\n4. **Zero candidates** -- stop with status `NEEDS-INPUT`: no Jira MCP tool\n   is connected in this session; ask the user to connect one (cloud\n   Atlassian connector or a local MCP gateway) and re-invoke.\n5. **More than one candidate** -- stop with status `NEEDS-INPUT`, listing\n   every candidate found (server name + tool name), and ask the user to\n   pick one. On the next invocation, expect the choice back via `notes`\n   (e.g. `\"jira-mcp: mcp__claude_ai_Atlassian\"`) and use point 1 above --\n   never guess between two connected Jira sources, since they can point\n   at different Jira instances entirely.\n\n### Step 1: Understand the Ticket\n\nRead `agents\u002Fbackend-planner.md` first -- this step and Step 1.5 apply its\nPhase 1 (existing-code scan) and Phase 2 (spec-to-CQRS mapping) rules by\nreference throughout; without reading it here those rules are not actually\nin context when this step needs to apply them, since a fresh agent\ninvocation does not inherit any other agent's file reads.\n\nCall the issue-lookup tool resolved in Step 0.5 with `{jiraKey}`.\n\n1. Read summary, description, acceptance criteria, comments, linked\n   issues. If a JQL-search counterpart was also resolved in Step 0.5, use\n   it to check for related tickets already in flight if the description\n   references one -- skip this check when no search tool was found.\n\n2. **Check whether the ticket already states a technical approach.**\n   Look at the description and comments for an explicit\n   approach\u002Fsolution section -- a heading or clearly-labeled block such\n   as \"Technical Approach\", \"Solution\", \"Technical Design\",\n   \"Implementation Approach\", or the Vietnamese equivalents (\"Giải pháp\n   kỹ thuật\", \"Giải pháp\", \"Hướng triển khai\") -- typically written by a\n   tech lead\u002Farchitect as part of grooming, not just a passing mention of\n   a class name in a comment.\n\n   - **Found**: this is the binding design. Extract the entity list,\n     `field:Type` pairs, endpoints, exceptions, and the extend-vs-new-entity\n     call directly from what it states -- do not re-derive or replace a\n     product\u002Fdesign decision the approach already made. Apply\n     `agents\u002Fbackend-planner.md` Phase 2's mapping rules only to fill in\n     mechanical detail the approach left implicit (e.g. it says \"add a\n     `status` field\" without naming a column type that\n     `templates\u002Fentity-conventions.md` already standardizes). Skip Step\n     1.5 -- go straight to Step 2 once the extraction below is complete.\n   - **Not found**: investigate the existing codebase yourself -- scan\n     `{sourceDir}\u002F{basePackage}\u002Fdata\u002F` for entities that already exist,\n     scan `{sourceDir}\u002F{basePackage}\u002F` for existing domain packages, and\n     glob `src\u002Fmain\u002Fresources\u002Fmigration\u002F` for the next migration version\n     (mirror `agents\u002Fbackend-planner.md` Phase 1's scan). Draft a\n     **Proposed Solution** using Phase 2's mapping rules from the\n     summary\u002Fdescription\u002FAC alone. This proposal is not authoritative --\n     Step 1.5 must confirm it with the user before Step 2 touches\n     anything.\n\n3. Either way, resolve and write down before moving on (from the stated\n   approach when found, from the draft otherwise):\n   - Whether this ticket needs a brand-new entity (`be-crud` applies) or\n     only extends an existing one (`be-crud` does not apply -- see Step\n     3.5).\n   - The domain (one lowercase package segment, `[a-z][a-z0-9]*` — no hyphen, it\n     is spliced into `package …{domain}.api;`; used for the `{domain}\u002Fapi` package and the\n     URL prefix).\n   - The entity list, in FK-dependency order if more than one (referenced\n     entity first) -- same rule as `agents\u002Fbackend-planner.md` § 2.8.\n   - Per entity: `field:Type` pairs, validation rules, exceptions with\n     their HTTP status, endpoints (method, path, status code).\n   - Test scenarios: single sentence, present tense, lowercase first word\n     (usable as a snake_case test method name), `- [ ]` checkbox format,\n     per `templates\u002Ftest-scenario-template.md`.\n   - **Tier** -- classify the ticket to scale the Step 7 gate:\n     - `easy`: no new entity, no new public endpoint -- a logic\u002Fbug fix on\n       code that already exists.\n     - `normal`: one new entity scaffolded (one `be-crud` call), or one or\n       more new public endpoints on existing entities, within one domain.\n     - `extreme`: more than one new entity, or the change spans more than\n       one domain\u002Fmodule.\n     Tier never changes whether `be-verify`\u002F`be-review` run (see Golden\n     Rules) -- it only decides whether the parallel `be-security` gate in\n     Step 7 is mandatory. Regardless of tier, force `be-security` to run\n     if the ticket description\u002FAC mentions anything security-sensitive\n     (auth, permission, PII, payment, token, secret) -- tier is a\n     complexity signal, not a security override.\n\n4. **Gap inside a stated approach**: if a found Technical Approach leaves\n   something genuinely unresolved (a field with no declared type, a\n   business rule with no stated behavior) -- stop with status\n   `NEEDS-INPUT`, quoting the exact gap. Never fill it with a guess just\n   because \"most of the approach\" was already clear.\n\n### Step 1.5: Confirm the Proposed Solution (only when Step 1 found no stated approach)\n\nSkip this step entirely when Step 1 extracted from a stated Technical\nApproach -- re-confirming the ticket author's own design back to them is\nredundant, and the Golden Rule above says implement it directly.\n\nWhen Step 1 had to draft its own Proposed Solution:\n\n1. Stop the run here with status `NEEDS-INPUT`, before Step 2 touches git\n   or anything else. Report the full Proposed Solution exactly as Step\n   3\u002F3.5\u002F4 would consume it (entity list, fields\u002Ftypes, endpoints,\n   exceptions, extend-vs-new-entity call per entity, migration strategy\n   for any \"extend\" entity, tier), plus up to 3-5 open questions -- points\n   the draft had to guess where a wrong guess would change the design.\n2. On the *next* invocation, the caller passes the user's confirmation or\n   corrections back via the `notes` input parameter. Treat `notes` as\n   amending the Proposed Solution (apply corrections literally, do not\n   reinterpret them) and proceed straight through to Step 2 -- do not\n   re-enter Step 1.5 for the same ticket. If `notes` itself leaves a point\n   unresolved, that is an ordinary Step 1 point 4 gap, not a reason to\n   loop back into another proposal-and-confirm round.\n\n### Step 2: Prepare the Branch\n\n1. `git status --porcelain -z` (NUL-separated, the form Step 9 diffs against). Paths under `{workDocDir}\u002F.progress\u002F` and `.claude\u002Fbackend-webflux-plugin.json` are this plugin's own bookkeeping and never count as dirty (the run state above is written before any branch exists). Not clean otherwise -- stop with `NEEDS-INPUT`: ask the\n   user to commit or stash their own in-progress work first. Never run\n   `git stash` or `git checkout .` to clear it yourself. **Exception -- a\n   resume of this ticket:** when the current branch already carries\n   `{jiraKey}` (item 2) and every dirty path lies under `{sourceDir}`,\n   `{testDir}`, `src\u002Fmain\u002Fresources\u002F`, `config\u002F`, `gradle\u002F`, `buildSrc\u002F`,\n   `{workDocDir}`, or is a `build.gradle(.kts)` \u002F `settings.gradle(.kts)` \u002F\n   `gradle.properties` \u002F `gradlew` file (be-crud edits `application.yml`,\n   `be-build` may edit the build) **and is in the run state's `dirty`\n   list** (a path that is not was edited during the pause: stop with\n   `NEEDS-INPUT` naming it — two exceptions: the security fix a Step 7 stop\n   asked for, when its paths lie under `{sourceDir}`, `{testDir}` or\n   `src\u002Fmain\u002Fresources\u002F` (be-security's credential rules point at\n   `application*.yml`), and a resume with no run state or after a crash,\n   when `notes` says `own-dirty` — the user vouching that every dirty path\n   is this pipeline's), the\n   tree is this pipeline's own in-progress work left by a `NEEDS-INPUT` exit (a\n   three-failure pause, a security finding, an escalation); keep it and\n   continue from the step and feature `{workDocDir}\u002F.progress\u002Fjira\u002F{jiraKey}.json`\n   names (written at every early stop and after the commit -- see Gates;\n   absent → `NEEDS-INPUT` asking which step; `committed`\u002F`DONE` → the\n   ticket is finished: stop and say so, a fresh run on the same branch\n   starts over at Step 3 only when the user asks for it in `notes`). The\n   feature's own progress file wins over an older state: a step the state\n   names that the feature has already passed by hand (`done` on the current\n   tree, `verification.committed`) is skipped, not replayed. Then,\n   **capped at Step 6 when\n   the code changed since it was verified**: a report naming Step 7, 8 or 9\n   re-enters at Step 6 instead whenever `{pluginRoot}\u002Fscripts\u002F\n   source-tree-hash.sh` (exit 0 and a 40-hex id, else `NEEDS-INPUT`: the\n   tooling is broken, or the `{pluginRoot}` file is missing -- start a new session)\n   differs from the feature's\n   `pipeline.verification.tree` (a manual security fix, an escalation\n   resolved by hand: the review that may already have written `done`\n   describes the old tree). A report naming Step 3, 4 or 5 resumes there\n   regardless -- the work is not finished, and verifying it would only\n   certify a subset. Any dirty path outside those locations is still\n   someone else's work: stop.\n2. If the current branch name already starts with `{jiraKey}` followed by\n   a `-` or `_` (case-insensitive) -- not merely *contains* it, since\n   `jiraKey = \"OMH-10\"` is a substring of an unrelated branch named\n   `OMH-100-refactor-pricing` -- stay on it -- skip branch creation, note\n   this in the final report, and read the run state (item 1) even when the\n   tree is clean: a `committed`\u002F`DONE` ticket is not implemented twice.\n3. Otherwise: resolve the default branch\n   (`git symbolic-ref refs\u002Fremotes\u002Forigin\u002FHEAD`, falling back to `main`\n   then `master`); with no `origin` remote (`git remote get-url origin`\n   fails — a local-only checkout) skip the fetch and branch from the local\n   default branch, saying so in the report; otherwise `GIT_TERMINAL_PROMPT=0 GIT_SSH_COMMAND=\"ssh -o BatchMode=yes\" git fetch` (an expired credential, a passphrase or an unknown host key must fail, not prompt an unattended run — `GIT_TERMINAL_PROMPT` covers git's own credential prompt only, `BatchMode` covers SSH's), then\n   `git checkout -b {jiraKey}-{slug} origin\u002F{default}` -- with the start\n   point spelled out; without it the branch forks from whatever HEAD is. `{slug}` is a short kebab-case form of the Jira summary (up to\n   ~5 meaningful words).\n4. Confirm the working tree is on the right branch and clean -- or, on a\n   resume, dirty only under item 1's locations -- before Step 3.\n\n### Step 3: Scaffold (conditional) -- `be-crud`\n\nOnly for entities Step 1\u002F1.5 marked as brand-new, in dependency order:\n\n```\nSkill(skill: \"backend-webflux-plugin:be-crud\", args: \"{EntityName} field1:Type1[:unique][:nullable][:max=N][:pattern=email|phone|url] ... --domain {domain} --profile {r2dbc|mybatis}\")\n```\n\n- Before the first call, look for `{workDocDir}\u002F.progress\u002F{kebab-case-entity}.json` for **every**\n  entity to scaffold: one at `implementing` or later (`scaffolded` does not prompt) → `be-crud`'s\n  Step 2.5 would ask \"Continue?\" — stop with `NEEDS-INPUT` naming the entity before anything is\n  written, unless `notes` says to start it over, in which case add `--yes`.\n- `--domain` and `--profile` are the answers `be-crud` would otherwise ask\n  for; passing them is what keeps this run unattended -- both were already\n  decided in Step 1. The field flags carry what Step 1 read off the ticket:\n  a field the ticket calls unique gets `:unique` (that is the only thing that\n  makes `be-crud` emit the `existsBy` pre-check, the named constraint mapping\n  and `Duplicate{Field}Exception`), a bounded one `:max=N`, an email\u002Fphone\u002F\n  url one `:pattern=…`. A field the ticket calls optional gets `:nullable` — without it the column is `NOT NULL` and a \"request without {field}\" scenario fails at the database. A flag left off is a validator (or a nullability) that does not exist. If `config.dataProfile == \"both\"` and the skill still\n  prompts, answer with the value decided in Step 1 (default `r2dbc` unless\n  Step 1 found a reason to match an existing `mybatis` module).\n- Entity already exists (extend, not create): do **not** call `be-crud` --\n  see Step 3.5 instead.\n- No entity involved at all (pure logic\u002Fbug-fix ticket on an existing\n  endpoint): note \"Step 3: skipped -- no new entity\" and continue to Step 4.\n\n### Step 3.5: Extend an Existing Entity (conditional) -- this skill's own tools\n\nFor every entity Step 1\u002F1.5 marked \"extend, not create\", performed by\nthis skill directly (`Write`\u002F`Edit`\u002F`Bash`), **before** Step 4 authors the\nwork document -- schema, entity field and mapping are scaffold, the same\nkind of untested output `be-crud` produces for a new entity (behavior is\nstill written RED → GREEN by `be-code` in Step 5); there is no \"alter\"\nskill in this plugin, so this is not\n`be-crud`'s job and not `implement`'s job either; `implement` only ever\nsees a scenario list, never \"this entity needs a new column\" as a task in\nits own right:\n\n1. Determine `{next}` the same way `skills\u002Fbe-crud\u002FSKILL.md`'s Shared\n   Derivation Rules do (glob `src\u002Fmain\u002Fresources\u002Fmigration\u002FV*__*.sql`,\n   take the max version + 1), and write\n   `src\u002Fmain\u002Fresources\u002Fmigration\u002FV{next}__alter_{snake_case_table}_add_{field}.sql`\n   with the new column(s) -- one migration per entity, even when it gains\n   more than one field.\n2. Edit the entity class (R2DBC: `@Column`-annotated field; MyBatis: plain\n   field + the corresponding `\u003Cresult>` mapping in `{EntityName}Mapper.xml`)\n   directly, following `templates\u002Fentity-conventions-r2dbc.md` or\n   `templates\u002Fentity-conventions-mybatis.md` conventions matching the entity's\n   profile (Lombok `@Getter`\u002F`@Setter` when `config.lombokEnabled == true`) -- so\n   the class already compiles with the new field before `be-code`'s TDD\n   cycle starts.\n3. Add a repository\u002Fmapper query method only if a scenario in Step 1\u002F1.5\n   actually needs one (e.g. `existsBy{NewField}` for a uniqueness check);\n   otherwise leave the repository\u002Fmapper untouched. A field the ticket calls\n   **unique** gets the same three parts `be-crud` emits for one: the ALTER\n   migration adds `CONSTRAINT uk_{table}_{column} UNIQUE ({column})` (the\n   `existsBy` pre-check alone is a race -- two concurrent creates both pass\n   it, and only the constraint stops the second row), the executor maps a\n   `DataIntegrityViolationException` naming that constraint to\n   `Duplicate{Field}Exception`, and the web layer maps that to 409.\n4. Do not touch command\u002Fquery\u002Fview DTOs or router\u002Fhandler code here --\n   that is ordinary TDD scope and belongs to `be-code` in Step 5, exactly\n   like any other scenario.\n\n### Step 4: Author the Work Document Before Calling `be-code`\n\nMandatory, even when Step 3 already generated\n`{workDocDir}\u002F{kebab-case-entity}.md` via `be-crud` -- this skill cannot\nanswer `be-code`'s \"review and confirm to proceed\" prompt (`skills\u002Fbe-code\u002FSKILL.md`\nStep 3), so the work document must already exist and be final before Step\n5 runs.\n\n1. If `{workDocDir}\u002F{feature}.md` already exists (from `be-crud`): merge\n   in any scenario from Step 1 that the default scaffold does not cover\n   (a ticket-specific business rule, a non-CRUD action).\n2. If it does not exist (editing an existing entity, no scaffold run):\n   create `{workDocDir}\u002F{feature}.md` from\n   `templates\u002Fwork-document-template.md` with the scenario list decided\n   in Step 1, `- [ ]` format, no `?` markers -- every uncertain scenario\n   must already have been resolved in Step 1; nothing marked `?` reaches\n   this file, since nobody is present to confirm or drop it.\n3. `feature` = kebab-case of the primary entity name, or kebab-case of\n   `{jiraKey}` when the ticket is not centered on one entity.\n4. **Every entity Step 3 scaffolded is a feature of its own**: `be-crud`\n   wrote `{workDocDir}\u002F{kebab-case-entity}.md` for each, so do items 1-2\n   for each of them, not only for the primary -- a secondary entity whose\n   document is left at the scaffold's defaults never reaches `be-code`,\n   `be-verify` or `be-review`. Keep the list (`features`, in Step 1's\n   dependency order); Steps 5-8 iterate it.\n\n### Step 5: Implement (TDD) -- `be-code`\n\nFor each entry of `features` (Step 4 item 4), in dependency order:\n\n```\nSkill(skill: \"backend-webflux-plugin:be-code\", args: \"{workDocDir}\u002F{one feature}.md --yes\")\n```\n\n- Because the work document already exists, `be-code` enters file-path\n  mode directly (its Step 1 -> Step 3.5) and skips the interactive\n  approval flow entirely. `--yes` answers its demotion prompt: a second\n  ticket on an existing entity finds `.progress\u002F{feature}.json` at `done`\n  from the first, and re-implementing it is exactly what this ticket asks\n  for — the prompt is the operator's, and here the operator is Step 1.\n- The skill runs RED -> GREEN per scenario and writes its own tests --\n  there is no separate \"write unit tests\" step in this plugin's pipeline.\n- If `be-code`'s own report leaves `pipeline.status` at `\"implementing\"`\n  with a scenario unfinished (3 consecutive failures) -- stop with\n  `NEEDS-INPUT`, naming exactly which scenario is unfinished and the\n  reason the skill reported. If every scenario is `- [x]` and only its\n  final full build failed (checkstyle first runs there, never in the\n  per-class cycles) -- go to Step 6.1: that is what `be-build` is for.\n\nSteps 6–8 run **per entry of `features`** (Step 4 item 4): `{feature}` below is the one being\nprocessed, and a FAIL on any entry stops the run at that entry (later entries depend on it).\n\n### Step 6: Verify -- `be-verify`\n\n```\nSkill(skill: \"backend-webflux-plugin:be-verify\", args: \"{feature} --yes\")\n```\n\n- `--yes` answers `be-verify`'s demotion\u002Fstaleness confirmations (a resume re-entering here from `reviewed`\u002F`done`\u002F`escalated`) — this run decided the re-entry; the report is still read in full. A `be-verify`\u002F`be-review` stop on unfinished `- [ ]` scenarios (a work document edited during a pause) is `NEEDS-INPUT` naming them: the scenario has to go through Step 5 first.\n- Read the 5-row report (Compilation\u002FCheckstyle\u002FTests\u002FBuild\u002FCoverage).\n- The coverage percentage is report-only (`docs\u002Fdecisions.md` Decision 6)\n  -- carry it into the final report, never treat the number as a failure\n  condition. A Coverage row that FAILS (no report produced) is part of\n  `Overall`, like any other row.\n- Overall PASS -- go to Step 7.\n- Overall FAIL -- go to Step 6.1.\n\n#### Step 6.1: Auto-fix the build -- `be-build` (at most one call)\n\n```\nSkill(skill: \"backend-webflux-plugin:be-build\", args: \"\")   # be-build takes no argument: it builds the project, not a feature\n```\n\n`be-build` already retries internally up to 3 times -- call it **once**,\nnever wrap it in an outer retry loop of this skill's own. Then re-run\n`be-verify {feature} --yes` once to confirm:\n\n- PASS -- go to Step 7.\n- Still FAIL -- stop with status `ABORTED`, listing the exact FAIL rows\n  from the latest `be-verify` report.\n\n### Step 7: Gate -- `be-review` (always) + `be-security` (tiered)\n\nA `Skill` call loads that skill's steps into this same session -- nothing\nruns in parallel, and two multi-step procedures loaded in one turn\ninterleave their stops and lock handling. Run them one after the other,\n`be-security` first (read-only, no lock, no report file -- its findings\nare read from its own output before `be-review`'s steps begin):\n\n```\nSkill(skill: \"backend-webflux-plugin:be-security\", args: \"\")   # no argument = its default scope: the whole base package plus src\u002Fmain\u002Fresources (a dotted basePackage is not a path)\nSkill(skill: \"backend-webflux-plugin:be-review\", args: \"{feature} --yes\")\n```\n\nRun `be-security` when tier is `normal` or `extreme`, or when Step 1's\nsecurity-sensitive override fired regardless of tier. At `easy` tier with\nno override, skip it -- note \"Step 7: be-security skipped -- easy tier, no\nnew entity\u002Fendpoint surface\" and treat this step as `be-review`-only.\n\n**`be-review` branch:**\n- **First, confirm `be-review` wrote a verdict in this call**: read\n  `{workDocDir}\u002F.progress\u002F{feature}.json` — `pipeline.status` must now be\n  `reviewed`, `done` or `review-failed` (be-review sets one of them only\n  after saving the report). Still `verified`: be-review stopped without\n  writing (its Step 3.5 validation failed), and the\n  `review-report-{feature}.json` on disk is a previous round's or ticket's\n  — nothing removes old reports. Stop with `NEEDS-INPUT` quoting be-review's\n  own stop message; never read the report in that case.\n- Then read `review-report-{feature}.json` (path returned by\n  `skills\u002Fbe-review\u002FSKILL.md` Step 4): verdict, critical\u002Fwarning\u002F\n  suggestion counts.\n- Verdict PASS -- with or without warnings\u002Fsuggestions -- and no security\n  block (below): skip Step 8, go straight to Step 9. A PASS with warnings\n  leaves the feature `reviewed`, and `be-fix` on a `reviewed` feature asks\n  \"Continue?\" (its Step 2.5 demotion check) -- a prompt this run cannot\n  answer. Carry the warnings into the Step 10 summary instead.\n- Verdict FAIL -- go to Step 8.\n\n**`be-security` branch (when run):**\n- `be-security` has no persisted report file and no `be-fix` integration\n  in this plugin -- read its findings directly from the skill's own\n  report text (Critical \u002F Warnings \u002F Suggestions, per\n  `skills\u002Fbe-security\u002FSKILL.md` Step 4).\n- **Any Critical finding blocks the pipeline.** There is no automated\n  security-fix skill in this plugin, so do not attempt to route these\n  into `be-fix` or fix them inline yourself. Stop with status\n  `NEEDS-INPUT`, quoting every Critical finding verbatim (`file:line`,\n  description, suggestion) and asking the user to fix them manually (or\n  via a manual `be-code`\u002F`implement` edit), then re-run\n  `\u002Fbackend-webflux-plugin:be-security` to confirm before resuming this\n  agent — the resume re-enters at Step 6, not here: the fix changed the\n  tree, and the `be-review` that ran alongside may already have written\n  `reviewed`\u002F`done` for code that no longer exists (Step 2's tree rule).\n- Warnings\u002FSuggestions are non-blocking -- carry them into the Step 9\u002Ffinal\n  report as-is; they do not gate progression to Step 8\u002F9.\n\n### Step 8: Fix Loop (conditional, at most 2 rounds) -- `be-fix` -> `be-verify` -> `be-review`\n\n```\nSkill(skill: \"backend-webflux-plugin:be-fix\", args: \"{feature}\")\n```\n\nthen -- a fix changed code, and `be-review` refuses a `fixing` feature until it is re-verified:\n\n```\nSkill(skill: \"backend-webflux-plugin:be-verify\", args: \"{feature} --yes\")\n```\n\n(`Overall: FAIL` here → one `be-build` + re-verify exactly as Step 6.1; still FAIL → `ABORTED`.) Then\n\n```\nSkill(skill: \"backend-webflux-plugin:be-review\", args: \"{feature} --yes\")\n```\n\n(the same freshness check as Step 7: `pipeline.status` must have left\n`verified`, or the report on disk is stale — `NEEDS-INPUT`.)\n\n- **Read `pipeline.fix.round` before every `be-fix` call**, not only the\n  first. The counter persists across runs (be-review zeroes it only on a\n  clean PASS, be-commit only before a commit); if it is already >= 2, one\n  more call reaches round 3 and `be-fix` Step 3's \"Continue anyway?\"\n  prompt -- stop with `NEEDS-INPUT` instead of calling. (A feature\n  entering at round 1 passes the first check and would reach round 3 on\n  the second call without this.)\n- **Read `{workDocDir}\u002F.progress\u002Ffix-report-{feature}.json` (the path\n  `pipeline.fix.reportFile` records) and `pipeline.status` before calling\n  `be-verify`\u002F`be-review`.** If `escalated[]` is non-empty, or the status\n  is `escalated` (the post-fix build failed even with every issue marked\n  fixed -- `be-verify` would prompt on it) -- stop with `NEEDS-INPUT` and\n  list the escalated issues, or the build failure, verbatim. A partially escalated fix is a known unresolved issue;\n  re-verifying and re-reviewing around it can PASS-with-warnings and reach\n  the commit with that issue still open. (`be-review` refuses `escalated`\n  outright, and `be-verify` would re-admit the partial fix silently.)\n- **Hard bound: call `be-fix` at most 2 times** for a given feature.\n  Reason: `skills\u002Fbe-fix\u002FSKILL.md` Step 3 blocks on a \"Continue anyway?\n  (y\u002Fn)\" prompt once `pipeline.fix.round >= 3` -- a third call would hang\n  on a prompt this unattended agent cannot answer, so it must never be\n  made.\n- If review is still FAIL, or still has a `critical` issue, after 2\n  rounds -- stop with status `ABORTED`, listing the remaining issues\n  verbatim (severity, `file:line`, message) from the latest\n  `review-report-{feature}.json`. Never assume issues are resolved without\n  a report confirming it.\n- Review PASS (even with non-critical suggestions) after round 1 or 2 --\n  stop the loop, go to Step 9.\n\n### Step 9: Stage and Commit -- `be-commit`\n\n0. Settle the tree first: Steps 6–8 ran per feature, and a later feature's\n   `be-fix`\u002F`be-build` changed the tree every earlier feature was verified\n   on. For each feature (in `features` order) whose\n   `pipeline.verification.tree` differs from the current\n   `{pluginRoot}\u002Fscripts\u002Fsource-tree-hash.sh`, run\n   `be-verify {feature} --yes` then `be-review {feature} --yes` (Step 7's\n   freshness check applies); a FAIL goes\n   through Step 8 for that feature (its bounds apply). A pass that changed\n   nothing settles the tree; a pass in which a fix changed it is followed by\n   at most **one** more pass -- two features whose fixes keep invalidating\n   each other do not converge, so a third pass is `NEEDS-INPUT` naming both.\n1. Diff the current `git status --porcelain -z` (NUL-separated: a quoted\n   or renamed record is otherwise misread) against the Step 2 baseline\n   (captured before any implementation work) to get the exact set of\n   files this feature touched. On a resume, the baseline already held this\n   pipeline's own dirty files (Step 2's exception) -- add the paths the\n   run state's `dirty` list names (the pipeline's own files at the last\n   stop) as well, or the migration and entity from the first run are\n   never staged and the commit is a partial feature. A dirty path under\n   the Step 2 locations that is in neither set was edited by someone\n   during the pause: stop with `NEEDS-INPUT` naming it rather than commit\n   it as this ticket's work — unless Step 2 admitted it (a security fix,\n   or `notes: own-dirty`), in which case it is staged with the rest.\n2. `git add \u003Cfile1> \u003Cfile2> ...` -- name every file explicitly. Never\n   `git add -A` or `git add .`.\n2a. `be-commit` Step 1.5 asks \"Continue with commit?\" whenever ANY other\n   feature under `{workDocDir}\u002F.progress\u002F` is not `reviewed`\u002F`done` -- a\n   prompt this run cannot answer. Read every progress file first — this\n   feature's included: it must be `reviewed` or `done`, and any file in\n   any other status stops the run with `NEEDS-INPUT` naming it instead of\n   calling `be-commit`. Its Step 1.5\n   also prompts when a `reviewed`\u002F`done` feature not yet\n   `pipeline.verification.committed` has a `pipeline.verification.tree`\n   that differs from `{pluginRoot}\u002Fscripts\u002Fsource-tree-hash.sh\n   --staged` -- compute that once after item 2 and compare; after item 0 a\n   mismatch here means item 2 missed a file: stage it (a file outside the\n   Step 2 locations is not this feature's -- stop with `NEEDS-INPUT`).\n3. ```\n   Skill(skill: \"backend-webflux-plugin:be-commit\", args: \"topic: {jiraKey} \u003Cone-line summary>\")\n   ```\n4. Read `be-commit`'s own report; take the short hash from the\n   `git rev-parse --short HEAD` output it printed -- never fabricate one --\n   and write it to the run state at once (`status: committed`, `commit`).\n5. **Do not push, do not open a pull request, do not transition or\n   comment on the Jira issue.** This is the pipeline's final step, exactly\n   as `CLAUDE.md` § Pipeline defines it (`be-plan -> be-crud -> be-code ->\n   be-verify -> be-review \u003C-> be-fix -> be-commit`, no push\u002FPR step).\n\n## Gates (fail fast)\n\n| Gate | Condition to proceed | On failure |\n|---|---|---|\n| Step 0 | `.claude\u002Fbackend-webflux-plugin.json` exists | `ABORTED` -- tell the user to run `be-init` |\n| Step 0.5 | Exactly one Jira MCP tool resolved (or one already confirmed via `notes`) | `NEEDS-INPUT` -- report zero or multiple candidates found, ask the user to connect\u002Fpick one |\n| After Step 1 | Stated approach has no gap, or a Proposed Solution was fully drafted | `NEEDS-INPUT` -- quote the exact gap in the stated approach |\n| Step 1.5 | Only when Step 1 drafted its own proposal (no stated approach): user has confirmed\u002Fcorrected it | `NEEDS-INPUT` -- report the full proposal + open questions, stop before any git\u002Fscaffold action |\n| Step 2 | Working tree clean before branching | `NEEDS-INPUT` -- ask the user to handle their own uncommitted work |\n| After Step 5 | `be-code` reports every scenario `- [x]` | `NEEDS-INPUT` -- name the unfinished scenario\u002Fentity (a failed final build with every scenario done goes to Step 6.1 instead) |\n| After Step 6\u002F6.1 | `be-verify` Overall PASS (one `be-build` attempt allowed) | `ABORTED` -- list the FAIL rows |\n| Step 7 (`be-security` branch) | Zero Critical findings (when the gate ran) | `NEEDS-INPUT` -- quote every Critical finding, ask for a manual fix |\n| After Step 8 | `be-review` verdict PASS (at most 2 `be-fix` rounds) | `ABORTED` -- list remaining critical\u002Fwarning issues |\n| Step 9 | `be-commit` exits 0 with a confirmed short hash | Report the commit failure verbatim, stop -- no retry |\n\nEvery early stop (`NEEDS-INPUT`\u002F`ABORTED`) writes the run state to\n`{workDocDir}\u002F.progress\u002Fjira\u002F{jiraKey}.json` (`mkdir -p` first; no lock — the file is this run's alone, not a feature's\nprogress file; a stop before Step 0 resolved `workDocDir` or `jiraKey`\nwrites nothing — there is nothing to resume; a field not known yet is\n`null`, `features` `[]`) — a\nsubdirectory, so the\n`.progress\u002F*.json` scans of be-commit and the other skills never read it\nas a progress file — `{ \"step\": \"{N}\", \"status\": \"NEEDS-INPUT|ABORTED|\ncommitted|DONE\", \"feature\": \"{the entry being processed}\", \"features\":\n[...], \"dirty\": [\"{every path `git status --porcelain -z` lists under the\nStep 2 locations at this stop -- the pipeline's own files}\"], \"commit\":\n\"{short hash, once be-commit returned it}\", \"timestamp\": \"{ISO 8601 Z}\" }`. Step 9 item 4 writes `committed` with the hash the\nmoment be-commit reports it (a crash before `DONE` must not replay the\ncommit); the Output section writes `DONE`. Step 2 reads it whenever the\nbranch carries `{jiraKey}` (a resume with no file stops with `NEEDS-INPUT`\nasking which step to resume at) — and every stop must report which\npipeline step it stopped at and the current `pipeline.status` for each affected feature\n(read from `{workDocDir}\u002F.progress\u002F{feature}.json` when it exists), so the\nuser knows exactly which `be-*` skill to resume with by hand. Never stop\nsilently.\n\n## Anti-patterns\n\n- Assuming a specific Jira MCP server name instead of resolving it via\n  `ToolSearch` in Step 0.5 -- the tool that exists in one project's\n  session (cloud connector, local gateway, or something else entirely)\n  is not guaranteed to exist, or be the right one, in another's.\n- Guessing which Jira MCP tool to use when `ToolSearch` returns more than\n  one candidate -- two connected Jira sources can point at two different\n  Jira instances; stop and ask instead of picking one silently.\n- Re-deriving a design the ticket's own Technical Approach already states\n  -- extract from it, do not second-guess a decision the ticket already\n  made.\n- Implementing a self-drafted Proposed Solution (Step 1.5) without\n  stopping for confirmation first -- a self-drafted design is a\n  proposal, not a mandate, and this skill has no way to detect the user\n  silently disagreed with it once code already exists.\n- Calling `be-crud` on an entity that already exists (discards its\n  pipeline history -- see `skills\u002Fbe-crud\u002FSKILL.md` Step 2.5).\n- Letting `be-code` draft scenarios and wait for interactive approval\n  instead of authoring the work document up front in Step 4.\n- Calling `be-fix` a third time on the same feature (hangs on the\n  round-3 confirmation prompt).\n- Skipping `be-verify` or `be-review` because the ticket looks small (tier\n  only scales the `be-security` gate, never these two).\n- Routing a `be-security` Critical finding into the `be-fix` loop, or\n  fixing it inline -- there is no automated security-fix contract in this\n  plugin; stop with `NEEDS-INPUT` instead.\n- Loading `be-review` and `be-security` in the same turn \"to run them\n  concurrently\" -- a `Skill` call runs inline in this session; two loaded\n  at once interleave their stops and lock handling. `be-security` first,\n  then `be-review`.\n- Running `git add -A`\u002F`git add .`, or `git stash`\u002F`git checkout .` to\n  discard the user's own uncommitted work without asking.\n- Pushing, opening a pull request, or commenting on \u002F transitioning the\n  Jira issue -- none of that is part of this plugin's pipeline, and none\n  of it has this skill's explicit authorization to act on the user's\n  behalf.\n- Reporting `DONE` without a real short hash confirmed via\n  `git rev-parse --short HEAD`.\n\n## Output\n\nWrite `{workDocDir}\u002F.progress\u002Fjira\u002F{jiraKey}.json` with the final status (`DONE` closes the\nresume path: a later run on the same branch starts over at Step 3 only with the user's say-so),\nthen report, in `workingLanguage`, starting with a status line:\n\n```\nStatus: DONE | NEEDS-INPUT | ABORTED (stopped at Step N)\n\nJira: {jiraKey} -- {summary}\nJira source: {mcp server resolved in Step 0.5}\nApproach: {\"ticket-stated\" | \"proposed, confirmed via notes on {date}\"}\nTier: {easy|normal|extreme}\nBranch: {branch}\nEntities\u002Ffeatures: {list}\nFiles changed: {count}\nVerify: {PASS\u002FFAIL per row}\nReview: {overallScore}\u002F10, {critical} critical fixed over {round} be-fix round(s)\nSecurity: {\"not run (easy tier)\" | \"PASS, N warning(s)\" | \"BLOCKED, N critical\"}\nCoverage: {linePercent}% (report-only)\nCommit: {short hash, or \"none\"}\n\nNot pushed, no pull request opened -- push\u002FPR\u002FJira transition is a manual\nnext step for the user.\n```\n\nFor `NEEDS-INPUT`, the report must contain the exact questions the user\nneeds to answer before re-invoking this skill.\n",{"name":45,"description":46,"allowed-tools":47,"argument-hint":48,"user-invocable":49},"be-jira-auto","Jira-to-commit orchestrator that implements a ticket's own stated Technical Approach directly when present, or drafts a Proposed Solution and stops for user confirmation when not, classifies the ticket into a tier (easy\u002Fnormal\u002Fextreme) to scale the review gate, and drives the full be-crud -> be-code -> be-verify -> (be-review + be-security) -> be-fix -> be-commit pipeline end to end via the Skill tool, instead of the user running each be-* skill one at a time","Bash, Read, Write, Edit, Grep, Glob, Skill, Agent, ToolSearch","\u003CJIRA-KEY> [notes: \u003Ctext>]",true,"main","99f07e592261c66756a2927d0440fc5fef950507",".claude\u002Fskills\u002Fecc\u002Fplankton-code-quality","https:\u002F\u002Fgithub.com\u002Fsakamoto-family-smile\u002Fagent_monorepo","https:\u002F\u002Fgithub.com\u002Fsakamoto-family-smile","2026-11-08 20:29:14",{"source":8,"skillName":45,"commands":57,"prompt":67,"zipAvailable":49},[58,61,64],{"tool":59,"command":60},"npx","npx skills add sakamoto-family-smile\u002Fagent_monorepo --skill be-jira-auto",{"tool":62,"command":63},"bunx","bunx skills add sakamoto-family-smile\u002Fagent_monorepo --skill be-jira-auto",{"tool":65,"command":66},"pnpm","pnpm dlx skills add sakamoto-family-smile\u002Fagent_monorepo --skill be-jira-auto","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fsakamoto-family-smile\u002Fagent_monorepo\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fecc\u002Fplankton-code-quality\u002FSKILL.md",[],[70,105,113,128,151,180],{"skillNo":71,"name":72,"nameZh":6,"description":73,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":74,"categories":75,"keywords":84,"publishedAt":40},"01M6RW50THEFSKK42YNR8XFZA1","remotion-video-creation","Best practices for Remotion - Video creation in React. 29 domain-specific rules covering 3D, animations, audio, captions, charts, transitions, and more.","https:\u002F\u002Fgithub.com\u002Fsakamoto-family-smile\u002Fagent_monorepo\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fecc\u002Fremotion-video-creation\u002FSKILL.md",[76,81],{"categoryNo":77,"categoryName":78,"taxonomyType":79,"taxonomyTypeDesc":80},"01JBSEEDCAT000000000000009","前端开发","SCENARIO","使用场景",{"categoryNo":82,"categoryName":83,"taxonomyType":79,"taxonomyTypeDesc":80},"01JBSEEDCAT000000000000016","图像与多媒体",[85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104],"Video","remotion video","remotion video creation","creation","Remotion","Charts","Captions","Audio","3D","Composition","Animation","best practices","more","animations","domain-specific","domain","three","Rules","Lottie","for",{"skillNo":106,"name":107,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":108,"categories":109,"keywords":110,"publishedAt":40},"01M6VCJ23NPECPSZJKGY691F75","hotcook-recipes","https:\u002F\u002Fgithub.com\u002Fsakamoto-family-smile\u002Fagent_monorepo\u002Fblob\u002Fmain\u002Fhotcook-agent\u002Fdata\u002Fskills\u002Fhotcook-recipes\u002FSKILL.md",[],[111,112],"hotcook recipes","recipes",{"skillNo":114,"name":115,"nameZh":6,"description":116,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":117,"categories":118,"keywords":123,"publishedAt":40},"01M6VCHHE00X5XHSDRD1KH1BW2","code-helper","Code review and assistance skill","https:\u002F\u002Fgithub.com\u002Fsakamoto-family-smile\u002Fagent_monorepo\u002Fblob\u002Fmain\u002Fagent-system-2\u002Fskills\u002Fcode-helper\u002Fskill.md",[119,122],{"categoryNo":120,"categoryName":121,"taxonomyType":79,"taxonomyTypeDesc":80},"01JBSEEDCAT000000000000007","代码审查",{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},[124,125,23,126,127],"code helper","helper","code review","review",{"skillNo":129,"name":130,"nameZh":6,"description":131,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":132,"categories":133,"keywords":140,"publishedAt":40},"01M6VCH3Q31A20H6SQ1H0J7JB2","research-assistant","Web research assistant skill using Brave Search MCP","https:\u002F\u002Fgithub.com\u002Fsakamoto-family-smile\u002Fagent_monorepo\u002Fblob\u002Fmain\u002Fagent-system-1\u002Fskills\u002Fresearch-assistant\u002Fskill.md",[134,137],{"categoryNo":135,"categoryName":136,"taxonomyType":79,"taxonomyTypeDesc":80},"01JBSEEDCAT000000000000021","资料检索与研究",{"categoryNo":138,"categoryName":139,"taxonomyType":79,"taxonomyTypeDesc":80},"01JBSEEDCAT000000000000023","Skill与智能体开发",[141,142,143,144,145,146,147,148,149,150],"research assistant","research","assistant","MCP","web","search","brave search","web research","brave","web research assistant",{"skillNo":152,"name":153,"nameZh":6,"description":154,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":155,"categories":156,"keywords":161,"publishedAt":40},"01M6VCGZZGPNVJSCZ1JTMNZAHY","x-api","X\u002FTwitter API integration for posting tweets, threads, reading timelines, search, and analytics. Covers OAuth auth patterns, rate limits, and platform-native content posting. Use when the user wants to interact with X programmatically.","https:\u002F\u002Fgithub.com\u002Fsakamoto-family-smile\u002Fagent_monorepo\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fecc\u002Fx-api\u002FSKILL.md",[157,160],{"categoryNo":158,"categoryName":159,"taxonomyType":79,"taxonomyTypeDesc":80},"01JBSEEDCAT000000000000010","后端与接口",{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},[162,163,164,165,166,167,104,168,169,170,171,172,173,174,175,176,177,178,146,179],"x api","api","with","when","limits","rate","threads","reading","native","posting","platform","patterns","api integration","twitter","use","auth","analytics","OAuth",{"skillNo":181,"name":182,"nameZh":6,"description":183,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":184,"categories":185,"keywords":187,"publishedAt":40},"01M6VCGVX6DGB1FKTA53QBBCQB","workspace-surface-audit","Audit the active repo, MCP servers, plugins, connectors, env surfaces, and harness setup, then recommend the highest-value ECC-native skills, hooks, agents, and operator workflows. Use when the user wants help setting up Claude Code or understanding what capabilities are actually available in their environment.","https:\u002F\u002Fgithub.com\u002Fsakamoto-family-smile\u002Fagent_monorepo\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fecc\u002Fworkspace-surface-audit\u002FSKILL.md",[186],{"categoryNo":138,"categoryName":139,"taxonomyType":79,"taxonomyTypeDesc":80},[188,189,190,35,144,191,192,23,193,194,195,196,176,197,198,199,200,170,201,165],"workspace surface audit","workspace","audit","workflows","connectors","capabilities","harness","repo","environment","up","harness setup","active","env","value"]