|
| 1 | +# Claude Code — Project Instructions |
| 2 | + |
| 3 | +This file is read automatically by Claude Code at the start of every session. Follow these rules when working in this repo. |
| 4 | + |
| 5 | +--- |
| 6 | + |
| 7 | +## Documentation Requirements |
| 8 | + |
| 9 | +**Every PR that adds, modifies, or removes an MCP tool must update documentation.** The full set of places to update: |
| 10 | + |
| 11 | +| What changed | Where to update | |
| 12 | +|---|---| |
| 13 | +| New MCP tool | `docs/mcp.md` (add tool entry with schema + example), `docs/mcp-pilot-guide.md` (add evaluation scenario if user-facing), `README.md` (update tool count if referenced) | |
| 14 | +| Modified tool description / parameters / errors | `docs/mcp.md` (update the relevant tool section) | |
| 15 | +| Removed tool | `docs/mcp.md`, `docs/mcp-pilot-guide.md`, `README.md` | |
| 16 | +| New error code or suggestion field | `docs/mcp.md` (Troubleshooting or Error Codes section) | |
| 17 | +| Security model change (path policy, licence, transport) | `docs/mcp.md` (Security Model section), `docs/mcp-pilot-guide.md` (Security Model section) | |
| 18 | +| New NitroX tool or schema rule | `docs/mcp.md` (NitroX section), `docs/mcp-pilot-guide.md` (Scenario 7) | |
| 19 | +| Smoke test count change | Update `TOTAL_EXPECTED` in `scripts/mcp-smoke.cjs` | |
| 20 | + |
| 21 | +**External / customer-facing docs** (`docs/provar-mcp-public-docs.md`, `docs/university-of-provar-mcp-course.md`) are maintained separately by the Provar team — flag changes that affect public-facing behaviour in your PR description so those can be updated manually. |
| 22 | + |
| 23 | +--- |
| 24 | + |
| 25 | +## Test Coverage Requirements |
| 26 | + |
| 27 | +Every PR must include tests for new or changed behaviour: |
| 28 | + |
| 29 | +- **New MCP tool** → unit tests in `test/unit/mcp/<toolGroup>Tools.test.ts` covering: happy path, path policy rejection, missing required fields, and any tool-specific error codes |
| 30 | +- **Modified error handling** → at least one positive test (error path fires) and one negative test (does not fire for non-matching input) |
| 31 | +- **New validation rule** → test that the rule fires correctly and that a valid input passes |
| 32 | +- **Smoke test** → add an entry in `scripts/mcp-smoke.cjs` for each new tool; update `TOTAL_EXPECTED` |
| 33 | + |
| 34 | +Run before every commit: |
| 35 | +```sh |
| 36 | +yarn test:only # unit tests — must all pass |
| 37 | +node scripts/mcp-smoke.cjs 2>/dev/null # smoke — must show all PASS |
| 38 | +yarn compile # TypeScript — must be clean |
| 39 | +``` |
| 40 | + |
| 41 | +--- |
| 42 | + |
| 43 | +## MCP Tool Authoring Standards |
| 44 | + |
| 45 | +### Tool description quality |
| 46 | + |
| 47 | +Every tool description must answer these questions for an AI agent reading it cold: |
| 48 | + |
| 49 | +1. **What does it do?** (one sentence) |
| 50 | +2. **What prerequisite tools must run first?** (e.g. `config.load` before `metadata.download`) |
| 51 | +3. **What are the correct flags / parameters?** Include a concrete example in the `flags` field description when flags are free-form |
| 52 | +4. **What does a failure mean?** If a known error pattern exists (e.g. `[DOWNLOAD_ERROR]` = auth failure), say so in the description or return a `details.suggestion` |
| 53 | + |
| 54 | +### Field descriptions |
| 55 | + |
| 56 | +- Fields that accept a **string key or password** must say "string value, NOT a file path" if there is any risk of confusion with a path |
| 57 | +- Fields that accept a **file path** must note if the path must be within `--allowed-paths` |
| 58 | +- Optional fields that have a dangerous default (e.g. overwriting existing files) must call that out |
| 59 | + |
| 60 | +### Error responses |
| 61 | + |
| 62 | +- Return `details: { suggestion: '...' }` when a known error pattern maps to a common root cause and there is an actionable fix |
| 63 | +- Never pass `details: {}` — omit `details` entirely when there is nothing extra to say (keeps the response shape stable) |
| 64 | +- Error codes follow `SCREAMING_SNAKE_CASE`; document new codes in `docs/mcp.md` |
| 65 | + |
| 66 | +### Path safety |
| 67 | + |
| 68 | +- Call `assertPathAllowed(path, config.allowedPaths)` on **every** path input before any file operation — not just the output path |
| 69 | +- Use `path.resolve()` before `fs.existsSync` / `fs.readFileSync` / `fs.writeFileSync` |
| 70 | +- Never construct shell commands from user input; use `spawnSync` with an args array |
| 71 | + |
| 72 | +--- |
| 73 | + |
| 74 | +## Branch and PR Conventions |
| 75 | + |
| 76 | +- Feature branches off `develop`: `feature/<description>` |
| 77 | +- Bug/fix branches off `develop`: `fix/<description>` |
| 78 | +- Release branches off `develop`: `release-v<semver>` |
| 79 | +- PRs target `develop`; releases are merged develop → main |
| 80 | +- Version in `package.json` follows `<major>.<minor>.<patch>-beta.<n>` on develop |
| 81 | +- Bump the beta suffix (`beta.N → beta.N+1`) on any PR that triggers a publish |
| 82 | + |
| 83 | +--- |
| 84 | + |
| 85 | +## Lint |
| 86 | + |
| 87 | +The project uses ESLint with `@typescript-eslint` strict rules. Common gotchas: |
| 88 | + |
| 89 | +- `complexity` max is **20** — extract helpers if a function grows past that |
| 90 | +- `no-unsafe-assignment` / `no-unsafe-call` — cast through `unknown` not `any` |
| 91 | +- `no-unnecessary-type-assertion` — TypeScript narrows after `typeof x === 'string'` checks; remove the redundant cast |
| 92 | +- `camelcase` — `nitroX` is valid camelCase (capital X starts the next word) |
| 93 | + |
| 94 | +CI runs lint as part of `sf-prepack` — do not skip with `--no-verify` on the final merge commit. |
0 commit comments