{"_id":"@arocnies/fitgherkin","name":"@arocnies/fitgherkin","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@arocnies/fitgherkin","version":"0.1.0","description":"Check an implementation against a Gherkin feature contract","license":"MIT","repository":{"type":"git","url":"git+https://github.com/arocnies/fitgherkin.git","directory":"packages/fitgherkin"},"homepage":"https://github.com/arocnies/fitgherkin#readme","bugs":{"url":"https://github.com/arocnies/fitgherkin/issues"},"author":{"name":"Aaron Nies"},"keywords":["bdd","gherkin","cucumber","serenity-js","screenplay","living-documentation"],"type":"module","sideEffects":false,"engines":{"node":">=22.22.3"},"bin":{"fitgherkin":"dist/cli.js"},"main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./agent":{"types":"./dist/agent/index.d.ts","default":"./dist/agent/index.js"},"./package.json":"./package.json"},"publishConfig":{"access":"public"},"scripts":{"check":"npm run typecheck && npm run build && npm run test","build":"node -e \"fs.rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.build.json && node -e \"fs.chmodSync('dist/cli.js', 0o755)\"","prepack":"npm run build","typecheck":"tsc --noEmit","test":"vitest run"},"dependencies":{"@cucumber/cucumber-expressions":"^20.1.0","@cucumber/gherkin":"^42.0.1","@cucumber/messages":"^34.2.1","typescript":"^6.0.3"},"devDependencies":{"@types/node":"^26.4.0","vitest":"^4.1.11"},"gitHead":"588e8a29364f36a00ad238555c5433fb4ec1f72e","_id":"@arocnies/fitgherkin@0.1.0","_nodeVersion":"26.4.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-MFyXFyhUYywOnkKQvVdY4cMgtaiA3GIQr54uM1BX4Jdv4PbQTBqFEgdDOPT3m/ayYXMDq9tb7npaMIHvoCQ/sg==","shasum":"6dbe07eb815c7d958ff639e92008f9157dcbf9e1","tarball":"https://registry.npmjs.org/@arocnies/fitgherkin/-/fitgherkin-0.1.0.tgz","fileCount":78,"unpackedSize":555307,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCpDcOriwtLXlpcGQnlyFBVF3LVqe5JoB2PRcqV5HXqnwIhANmhItEExSAktlHUMqpilPnP8InQzNtjHbgRoKo+tB/s"}]},"_npmUser":{"name":"arocnies","email":"arocnies@gmail.com"},"directories":{},"maintainers":[{"name":"arocnies","email":"arocnies@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/fitgherkin_0.1.0_1788452133651_0.053879699268789105"},"_hasShrinkwrap":false}},"time":{"created":"2026-09-03T16:15:33.305Z","0.1.0":"2026-09-03T16:15:33.796Z","modified":"2026-09-03T16:15:34.092Z"},"maintainers":[{"name":"arocnies","email":"arocnies@gmail.com"}],"description":"Check an implementation against a Gherkin feature contract","homepage":"https://github.com/arocnies/fitgherkin#readme","keywords":["bdd","gherkin","cucumber","serenity-js","screenplay","living-documentation"],"repository":{"type":"git","url":"git+https://github.com/arocnies/fitgherkin.git","directory":"packages/fitgherkin"},"author":{"name":"Aaron Nies"},"bugs":{"url":"https://github.com/arocnies/fitgherkin/issues"},"license":"MIT","readme":"# FitGherkin\n\nFit the code to the features: check an implementation against a Gherkin feature contract.\n\nThe feature files are a user-defined contract for how the system behaves. `fitgherkin` binds every scenario step to its step definition with the matching engine the Cucumber runner uses, reads the glue statically, and reports every disagreement, deterministically, with no user code executed.\n\n- **A deterministic gate.** Same inputs, same findings, exit 1 on an error. Undefined, ambiguous and stub steps, unused glue, broken contracts. It needs no dependency install and loads no glue, so it runs in milliseconds in a bare sandbox.\n- **A way in for brownfield code.** A truthful contract fails on day one. [`draft`](#drafting-a-contract-from-an-existing-project) tags the gap `@drift`, counts it in every report, and proposes `@draft` scenarios from the tests and docs a project already has.\n- **A contract agents are held to.** Agents write more of the glue now. fitgherkin holds them to the features through the same CLI, ships the norms that keep \"edit the feature to silence the finding\" off the table, and, where configured, asks an agent whether the code truly does what each scenario says. See [For AI agents](#for-ai-agents).\n\n## Quickstart\n\n```sh\nnpm install --save-dev @arocnies/fitgherkin\nnpx fitgherkin init\nnpx fitgherkin\n```\n\n`init` writes a config, a starter feature with its glue, and an `AGENTS.md` block carrying [the norms](#for-ai-agents). It never overwrites an existing file. In a directory that already has feature files it writes only the config and the norms, in plain cucumber-js style, and points you at `draft`.\n\nA report names the contract's size, each finding with a hint, and the verdict:\n\n```text\n  1 feature · 3 scenarios · 4/5 steps bound · 3 step definitions\n\n  error  static-fit/undefined-step/features/cart.feature:6\n    \"I should see 1 item\" has no matching step definition\n    hint: run `fitgherkin glue` for a snippet\n    at features/cart.feature:6\n\n✖ 1 error\n  providers: scan gherkin-features, typescript-glue · resolve cucumber-expressions · validate static-fit\n```\n\nOn a brownfield repository the path to green is three commands:\n\n```sh\nnpx fitgherkin init --agent claude   # or codex; plain init scaffolds the gate without agents\nnpx fitgherkin draft                 # tags not-yet-fit scenarios @drift, proposes @draft from tests and docs\nnpx fitgherkin\n```\n\n**With `--agent claude` or `--agent codex`**, the scaffolded config also wires the agent providers around the CLI you are already logged into: `agentBehaviorScan` mines docs for behavior, `agentBehaviorFit` judges each gated scenario against the code it runs through, `agentSteps` turns drafted TODO steps into real Given/When/Then. Every call uses that CLI's login and billing; see [agent providers](#agent-providers) before enabling it in CI.\n\n**Requirements.** Node >= 22.22.3, because the CLI loads `.mts` configs with Node's native type stripping. The package depends on `typescript` for the compiler API that reads glue, which is most of the install weight.\n\n## Supported stacks\n\nThe deterministic tier reads glue written for **cucumber-js (TypeScript and JavaScript)**, **jest-cucumber** (ESM or CommonJS) and **Serenity/JS Screenplay**. Feature files from any stack parse and are checked for structure.\n\nOn glue in another ecosystem (godog, behave, pytest-bdd, cucumber-jvm, SpecFlow/Reqnroll, Behat) the deterministic tier says exactly that: one `glue-unreadable` error naming the stack, and no per-step verdict, because \"this step is undefined\" would be a guess about a file it never read. The agent tier carries fit on those repositories: `init --agent` detects the framework, points the behavior scan at that language's step files, and `agentBehaviorFit` judges each scenario against the Go, Python or Java glue directly, attesting per feature (`agent-foreign-glue`) that the verdict is a reading rather than verified binding.\n\nA project with a Gherkin contract and no BDD suite at all is served too. The deterministic tier reports one `no-glue-found` error, and `agentBehaviorFit` judges each scenario against the implementation it runs through, answering in three states: fits, does not fit, or `behavior-unverified`. \"I could not find the deciding code\" and \"the code disagrees\" are opposite findings, and a tool that collapses them is worth nothing. Verdicts from source are attested `agent-source-evidence`: nothing executes those scenarios, so the verdict is a reading of the code, not a test result.\n\nTwo audiences get the most out of it: teams whose agents write glue, who need a fast gate that executes nothing and norms that stop the agent weakening the features; and jest-cucumber projects, which have no dry-run at all. jest-cucumber's real semantics are modelled statically: per-test-block scoping, exact-match strings, scenarios nobody wrote a test block for.\n\n## Commands\n\n```sh\nnpx fitgherkin                    # check (default command); exit 0 fit, 1 errors, 2 usage or config problem\nnpx fitgherkin --json             # machine-readable PipelineResult; --json=findings for findings + summary only\nnpx fitgherkin init               # scaffold: config, starter feature, glue, AGENTS.md norms\nnpx fitgherkin init --agent claude  # + wire the agent providers, install the skill at .claude/skills/fitgherkin\nnpx fitgherkin draft              # day one: tag not-yet-fit scenarios @drift, propose @draft from tests and docs\nnpx fitgherkin glue               # a step-definition snippet for every unbound step\nnpx fitgherkin steps              # the cast and the step vocabulary (reuse before inventing)\n```\n\nOther flags: `--config <path>`, `--style screenplay|plain` (init, glue), `--out <dir>` (draft), `--verbose` (progress narration on stderr; quiet by default), `--version`, `--help`. Unknown flags are hard errors.\n\n`glue`, `steps` and `draft` work with no config at all, on the defaults `init` pins; only the check requires one, because what green certifies is a declared contract. `glue` speaks the project's dialect: when jest-cucumber is the only glue present, snippets come as exact-match strings for the right `test(...)` block. `--json` carries a `schemaVersion`; `--json=findings` drops the large observation and association arrays for consumers that only gate.\n\nEvery finding in the report is the fact on one line and, where the fix is not obvious, a `hint:` line under it, the way a compiler's help text follows an error. The hint is a pointer, not a diagnosis. Errors print first, then warnings, then infos; each rule prints at most 50 errors or warnings and 5 infos before a count line, and `--json` always carries everything.\n\n## Configuration\n\n`fitgherkin.config.mts` is an ES module, because providers are functions:\n\n```ts\nimport {\n  behaviorCoverage,\n  cucumberExpressionBinding,\n  defineConfig,\n  gherkinFeatures,\n  implementationSlice,\n  importScan,\n  staticFitRules,\n  testEvidence,\n  testTitles,\n  typescriptGlue,\n} from '@arocnies/fitgherkin'\n\nexport default defineConfig({\n  version: 1,\n  repositoryRoot: '.',\n  glueStyle: 'plain',\n  scan: [gherkinFeatures(), typescriptGlue(), importScan(), testTitles()],\n  resolve: [cucumberExpressionBinding(), implementationSlice(), testEvidence()],\n  validate: [staticFitRules(), behaviorCoverage()],\n})\n```\n\nAll three phase arrays are required; there are no hidden defaults, so the file says exactly what the gate runs. Deterministic and agent providers mix freely in every phase, and each phase's output feeds the next.\n\n| Phase | Question | Built-in providers |\n| --- | --- | --- |\n| `scan` | What features, glue, code and tests exist? | `gherkinFeatures`, `typescriptGlue`, `jestCucumberGlue`, `importScan`, `testTitles`, `agentBehaviorScan` |\n| `resolve` | Which glue binds each step, which code does each scenario run through, what proves it? | `cucumberExpressionBinding`, `implementationSlice`, `agentImplements`, `testEvidence` |\n| `validate` | Does the code fit the contract? | `staticFitRules`, `screenplayStepShape`, `behaviorCoverage`, `cucumberRunner`, `agentBehaviorFit` |\n\n`resolve` is a pipeline, and its order is load-bearing. It produces four kinds of association:\n\n- `binding`, a step to the definition that will match it. Always deterministic: it must predict what the runner does.\n- `implements`, a scenario to the source files it runs through, walked along the dependency graph out of the bound glue. This is the scenario's **evidence slice**, and it is what the semantic tier reads.\n- `proves`, a test to the scenario it demonstrates, graded `executed` > `bound` > `reachable` > `vocabulary`. A verdict resting on a test is a stronger claim than one resting on a reading of the implementation, and the report says which it had.\n- `covers`, an observed behavior to the scenario whose text accounts for it. A claim about the contract's wording, not about the code.\n\n`implementationSlice()` walks out of what `cucumberExpressionBinding()` bound; `agentImplements()` covers what the walk could not reach; `testEvidence()` comes last, because it grades a test `reachable` exactly when the test exercises code inside the slice.\n\n### Scan providers\n\n- `gherkinFeatures({ include })`: feature globs, default `**/*.feature` anywhere in the tree minus node_modules, vendor and build output. When a narrower glob misses the contract, `no-features-found` names the files it can see and the glob that would catch them.\n- `typescriptGlue({ include })`: glue globs, default `features/**`, any `steps/` or `step_definitions/` directory, `*.steps.ts`, and the `test/`, `tests/`, `e2e/` and `cypress/` trees, TS and JS.\n- `jestCucumberGlue({ include })`: step definitions in jest-cucumber's `defineFeature`/`given`/`when`/`then` style, with jest-cucumber's own semantics: exact-match strings with `<placeholder>` captures, definitions scoped to their `loadFeature` target and their `test('…')` block, so a scenario re-defining shared steps is idiom rather than ambiguity, and a scenario with no test block is the error the runner would raise.\n- `importScan({ roots, ignore })`: a deterministic multi-language import crawler (Python, JS/TS, Go, Rust, Java/Kotlin, Ruby, C/C++). Lexical, sub-second on thousands of files. It emits the `dependency` edges everything else walks; without it there is no evidence slice.\n- `testTitles({ include })`: one `behavior-candidate` per test title, traceable to its `file:line`. Default globs cover `.test`, `.spec`, `_test`, `_spec`, NestJS's `.e2e-spec` and `.int-spec`, and the `test/`, `tests/`, `spec/` and `__tests__/` directories.\n- `agentBehaviorScan({ exec, include })` (from `@arocnies/fitgherkin/agent`): reads docs and code for behavior (default: top-level `*.md` except changelogs, licences and contribution guides, plus `doc/`, `docs/`, `spec/`, `specs/`). A spec is behavior even when phrased as instructions to implementers; development-workflow guidance and descriptions of code organization are not, and the prompt says so. The block `init` wrote into `AGENTS.md` is blanked before the scan reads the file, because every model lists \"exits 1 when the code does not fit\" as a behavior of the project otherwise; the rest of the file is scanned as any document. Its candidates feed `behaviorCoverage()` in scan and the compose chain in `draft.discover`.\n\n### Resolve providers\n\n- `cucumberExpressionBinding({ serenityParameterTypes })`: registers approximations of Serenity/JS's `{actor}` and `{pronoun}` unless the project defines its own (default `true`).\n- `implementationSlice({ maxDistance, maxFiles })`: the `implements` associations, breadth-first out of the bound glue (defaults 3 hops, 40 files per scenario).\n- `agentImplements({ exec })` (agent): maps scenarios onto implementation where no deterministic resolver can reach them. One routing question per feature, answered from paths rather than contents, only for scenarios the walk did not reach, including bound scenarios whose slice never left the glue.\n- `testEvidence()`: the `proves` and `covers` associations.\n\n### Validate providers\n\n- `staticFitRules()`: the core rules below.\n- `behaviorCoverage()`: reports what `covers` and `proves` say in both directions. `uncovered-behavior` groups behaviors no scenario accounts for, one finding per file; `scenario-unproven` names gated scenarios nothing executes. A scenario with glue behind it is a test the runner executes, so the rule speaks only of glue-less scenarios, and stays silent when it could not see what would prove one.\n- `screenplayStepShape()`: warns when a step body is more than a one-line `actor.attemptsTo(...)` delegation, and when a Then re-runs a Task (`then-step-acts`). Screenplay projects only.\n- `cucumberRunner({ command, args, tags, timeout })`: execution fit. Runs the gated scenarios with the project's own cucumber-js and reads the Cucumber Messages back. Opt-in, because it executes real code; a runner that cannot run is an error, never a silent green.\n- `agentBehaviorFit({ exec })` (agent): semantic fit. Asks the agent whether the code does what each gated scenario says, one call per group of scenarios sharing seed files, each group against its own evidence pack: nearest slice files first, oversized files shown as the definitions most relevant to the group, a quarter of the budget reserved for tests, callers of each seed one hop out. An `unknown` that names what it could not see gets one ask-back with exactly that. Findings carry `data.observedGherkin` when the agent can state how reality differs.\n\n## Agent providers\n\n`import { agentBehaviorFit, agentBehaviorScan, agentImplements, agentSteps, claudeCli, codexCli } from '@arocnies/fitgherkin/agent'`.\n\n`claudeCli()` runs `claude -p` with no user settings, MCP servers or tools; `codexCli()` runs `codex exec` ephemeral, user config and rules ignored, read-only sandbox, from a scratch directory so the project's own `AGENTS.md` never becomes the judge's instructions. Both feed the prompt on stdin. `claudeCli({ explore: true })` lets the judge search the repository with read-only tools at the cost of exact reproducibility. Every provider degrades visibly: a CLI that fails is an `agent-unavailable` finding, and whatever a byte budget kept out of the agent's view is an `agent-truncated` finding, never a silent thinning of evidence.\n\nCalls run pooled, four in flight by default (`concurrency`), each announced on stderr before it starts with a count and an estimate. Two environment variables make the tier replayable: `FITGHERKIN_AGENT_CACHE=<file>` wraps every exec in record/replay through that JSON file, and `FITGHERKIN_AGENT_MODEL=<id>` pins the model when the config did not. The external evals run the config `init --agent` writes, unedited, through exactly these.\n\n## Drafting a contract from an existing project\n\n`fitgherkin draft` does two things. It tags every not-yet-fit chosen scenario `@drift`, so existing Gherkin starts green with the gap in the burn-down. And it proposes new `@draft` scenarios from observed behavior through a staged pipeline, `discover → compose → emit`, where any stage can be deterministic or agent-backed:\n\n- `testTitles()` and `agentBehaviorScan()` (discover) turn test titles and documented behavior into evidence-linked candidates.\n- `featureSkeletons()` (compose) groups them into features and `@draft` scenarios with a TODO step pointing at the evidence.\n- `agentSteps({ exec })` (compose) rewrites the TODO steps into Given/When/Then from a cast and reusable task phrasings it names first. A reply that skips scenarios gets one second ask; what stays unfilled keeps its TODO and is named in DRAFT.md.\n\nEvery drafted scenario is `@draft` with a `# drafted from file:line` comment anchored to the sentence or heading it came from. A draft restates the implementation, so it is a proposal: promote it by deleting the tag, or swap it to `@drift` for accepted-not-built. Keep the comment; the check reads it back, and when it names a test file the scenario gets a `drafted` proves link to that test, in any language. Drafted features land in `features/` by default (`draft.outputDir`, or `--out <dir>`); the tag marks them, not a folder.\n\n## The Cast: declaring Screenplay actors\n\nGherkin has no syntax for actors, so fitgherkin declares them in the feature description, plain text every parser preserves:\n\n```gherkin\nFeature: Payment processing\n\n  Cast:\n    Operator — runs payment operations for the store\n    Payment Processor — the third-party service settling charges\n```\n\nOne actor per line, `Name — role`. `fitgherkin steps` lists the cast above the step vocabulary, `agentSteps` writes the cast it names into drafted features, and two gentle rules follow: `unused-actor` (declared, never acts) and `uncast-actor` (acts, not declared). `Task.where` and `Question.about` bindings are tracked as the When and Then vocabulary; abilities and interactions stay code-side, because they never appear in the contract.\n\n## Rules\n\n| rule | severity | meaning |\n| --- | --- | --- |\n| `undefined-step` | error | a step no definition matches |\n| `pending-step-definition` | error | stub glue (empty, `throw`, `return 'pending'`, description-only `Task.where`) bound to a gated scenario |\n| `ambiguous-step` | error | a step more than one definition matches |\n| `duplicate-step-definition` | error | two definitions with the same pattern |\n| `duplicate-parameter-type` | error | `defineParameterType` registered twice for one name |\n| `uncompilable-step-definition` | error | a pattern references an unknown `{parameterType}` |\n| `feature-parse-error` | error | invalid Gherkin |\n| `no-features-found` | error | the scan matched zero feature files, so nothing was checked; the hint names the files it can see |\n| `no-glue-found` | error | steps are undefined and nothing readable defines any; ONE finding, not one per step |\n| `glue-unreadable` | error | nothing readable defines any step, but BDD glue for a stack this tier cannot parse is present; ONE finding, no per-step verdict guessed |\n| `scenario-missing-test` | error | a scenario in a jest-cucumber feature has no `test('…')` block |\n| `test-without-scenario` | error | a jest-cucumber `test('…')` block names no scenario |\n| `scenario-failing` | error | a gated scenario fails when executed (`cucumberRunner`) |\n| `runner-unavailable` | error | `cucumberRunner` could not run; never fails open |\n| `unused-step-definition` | warning | glue no step in the contract uses |\n| `opaque-step-definition` | warning | a non-literal pattern; cannot be checked |\n| `opaque-parameter-type` | warning | a non-literal `defineParameterType` |\n| `unrecognized-glue` | warning | a file imports @cucumber/cucumber but registers steps dynamically, or could not be scanned |\n| `no-scenarios` | warning | a feature compiles to zero scenarios (the classic `Scenario` missing its colon) |\n| `screenplay-step-shape` | warning | a step body holds logic instead of delegating to a Task (`screenplayStepShape`) |\n| `then-step-acts` | warning | a Then step's glue re-runs a Task; outcomes should observe via a Question (`screenplayStepShape`) |\n| `scenario-pending` | warning | a gated scenario is pending when executed (`cucumberRunner`) |\n| `behavior-drift` | warning | the agent judges a gated scenario untrue of the code (`agentBehaviorFit`) |\n| `behavior-unverified` | warning | the agent could not find the code that decides a scenario; neither drift nor a pass |\n| `step-keyword-mismatch` | info | a Given/When/Then step binds to glue registered under a different keyword; runners match on text alone, so it passes silently |\n| `unused-actor` | info | the Cast declares an actor no scenario mentions |\n| `uncast-actor` | info | an actor acts in a feature whose Cast does not declare them |\n| `drift-ready` | info | a `@drift` scenario now binds fully |\n| `uncovered-behavior` | info | behaviors no scenario describes, one finding per file (`behaviorCoverage`) |\n| `scenario-unproven` | info | a glue-less gated scenario with no test behind it at any strength |\n| `agent-test-evidence` | info | the semantic tier had a test in view, with the strength of the `proves` link |\n| `agent-source-evidence` | info | the verdict rests on implementation source; a reading of the code, not a test result |\n| `agent-foreign-glue` | info | the agent judged a feature by reading glue the deterministic tier cannot parse |\n| `agent-unavailable` | info | an agent provider degraded; scenarios left unjudged, never a silent pass |\n| `agent-truncated` | info | a byte budget kept part of the evidence out of an agent's view; raise the provider's `maxChars` |\n\n## Tags: @drift and @draft\n\n- `@drift`: **chosen** behavior reality does not match yet. The gate tolerates it, tracks it in a burn-down line (`drift: N scenarios declared, M ready to un-tag`), and says `drift-ready` when the glue catches up. There are no baseline files; drift lives in the contract, visibly.\n- `@draft`: **proposed** behavior awaiting review, from `draft` or an agent. The gate ignores it; only the user promotes it, by deleting the tag or swapping it to `@drift`.\n\n## What green means\n\nExit 0 with the default config certifies that every gated scenario step binds to exactly one step definition that is not a stub. It does not certify that the scenarios pass: add `cucumberRunner()` for execution fit, and `agentBehaviorFit()` for the semantic check on top.\n\nVersus `cucumber-js --dry-run`, which also finds undefined and ambiguous steps: fitgherkin needs no dependency install and executes no user code, so it runs in milliseconds in a bare sandbox, and it adds stub detection, `@drift` accounting, fail-closed reporting of what it could not analyze, and deterministic JSON. If you already run dry-run in CI and have no agents, the delta is smaller.\n\n## For AI agents\n\nfitgherkin's agent interface is the CLI itself: run it, read the report, fix what it names. Each finding's `hint:` says where to look; `--json=findings` gives the same as typed data. There is deliberately no MCP server.\n\n`init` writes a short block into `AGENTS.md`, or appends it once under its own heading when the file already exists. It says three things: the tool exists, when to run it, and where the guide is. The one norm it carries is the one an agent cannot infer from the CLI: **the features are the contract**, and editing them to match whatever the code does is the cheapest path to a green build. Everything else lives in the skill, so the block describes no behavior of fitgherkin's own for a behavior scan to mistake for the project's.\n\n```markdown\n## Feature contract (fitgherkin)\n\n- The Gherkin features under `features/` are this project's behavior\n  contract. Run `npx fitgherkin` before handing off any change to code,\n  `features/` or step definitions.\n- Fix the code, not the features, to get to green. Editing a feature is a\n  product decision to call out; never weaken, delete or tag a scenario to\n  silence a finding.\n- How to read findings, tags and write steps that fit: `node_modules/@arocnies/fitgherkin/skills/fitgherkin/SKILL.md`\n  (Claude Code: install it as a skill with `mkdir -p .claude/skills && cp -R node_modules/@arocnies/fitgherkin/skills/fitgherkin .claude/skills/fitgherkin`).\n```\n\nThe package also ships a Claude Code skill at `skills/fitgherkin/` covering the fuller workflow: reading findings, what a verdict rests on, drift etiquette, writing steps that fit. `init --agent claude` installs it at `.claude/skills/fitgherkin/`; otherwise copy it there, or reference it in place from `node_modules/@arocnies/fitgherkin/skills/fitgherkin/`.\n\n## License\n\n[MIT](LICENSE)\n","readmeFilename":"README.md","_rev":"1-6db8d57a6e50b9eb03b21552af518085"}