Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 38 additions & 5 deletions .claude/skills/pre-push-gate/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,40 @@ the server's own `tsc`. An error in a test file only shows in `typecheck`.
Re-run just that suite to iterate: `npm test -w src/<server>`. Read the failure
before changing a timeout: an assertion that races is a bug in the test.

### `coverage`

A TypeScript file is below 90% on lines, statements, functions or branches.
Vitest names each file and dimension:

```
ERROR: Coverage for branches (71.42%) does not meet global threshold (90%) for roots-utils.ts
```

("global threshold" is Vitest's wording; with `perFile: true` it is checked
per file.) The root `npm run coverage` carries on into the remaining
workspaces after a failure, so **the failing report is not the last thing
printed**: find the `npm ERR!` block, which names the workspace
(`in workspace: @modelcontextprotocol/server-<name>`), and read the `ERROR:`
lines just above it.

1. Re-run that server alone: `npm run coverage -w src/<server>`.
2. Read its per-file table. The `Uncovered Line #s` column is where the
missing tests go (a long list is truncated to `...`, and a long file name
to `...-name.ts`; open `coverage/index.html` in the workspace, or narrow
the run, for the full list). A branch shortfall with no uncovered lines is
the untaken side of a condition, `??`, `?.` or default parameter.
3. **Write the tests.** Drive what a client sees through a `Client` over the
in-memory transport; call a helper directly only for its logic (`testing`
skill).
4. Only for code that genuinely cannot run, annotate it at the source with
its reason, `/* v8 ignore next -- <reason> */` (or `start`/`stop` around a
block). A branch that is merely awkward to reach is not unreachable.

**Never lower a threshold, drop `perFile`, or widen the coverage `exclude`**
to get green; the gate is the rule in `AGENTS.md` **Always test new or
modified code**. A failing _test_ in this stage is an ordinary test failure:
fix it as under `test`, above.

### `validate:py`

The summary at the end names the failing server, and the step that failed is
Expand Down Expand Up @@ -221,8 +255,7 @@ The details of the lease are in

## Not part of the gate

`npm run skills:eval` (real model calls), `npm run coverage` (a report; no
threshold is enforced yet) and `npm run pack:verify` (installs each package's
publish artifact and boots it; needs the network, and belongs to the release
flow) are separate commands. Run the eval suite when you
add a skill or change a description.
`npm run skills:eval` (real model calls) and `npm run pack:verify` (installs
each package's publish artifact and boots it; needs the network, and belongs to
the release flow) are separate commands. Run the eval suite when you add a
skill or change a description.
4 changes: 4 additions & 0 deletions .claude/skills/pre-push-gate/evals/evals.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
"prompt": "verify:no-test-retries is failing in my gate run but I never added a test retry. What is it matching?",
"expect": "pre-push-gate"
},
{
"prompt": "The coverage stage of my gate run went red, but the last report it printed was all green. How do I find what failed and fix it?",
"expect": "pre-push-gate"
},
{
"prompt": "What is 17 multiplied by 23?",
"expect": null
Expand Down
20 changes: 11 additions & 9 deletions .claude/skills/project-structure/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ includes the tests) and `vitest.config.ts`.
| Server | Layout | Where its features are registered |
| --- | --- | --- |
| `everything` | `index.ts` picks a transport from `argv`; `server/` holds the factory; `tools/`, `resources/`, `prompts/` hold one file per feature plus an `index.ts`; `transports/` holds one file per transport; `version.ts` reads the package version; `docs/` is shipped | Each feature file exports a `register…` function, wired into its area's `index.ts` (`registerTools`, `registerResources`, `registerPrompts`), which `server/index.ts` calls from `createServer()` |
| `filesystem` | `index.ts` is the server; `lib.ts` holds the file operations and path validation; `path-utils.ts`, `path-validation.ts` and `roots-utils.ts` are focused helpers; `version.ts` reads the package version | Inline in `index.ts`, with `server.registerTool(...)` |
| `memory` | `index.ts` is the server and the `KnowledgeGraphManager`; `version.ts` reads the package version | Inline in `index.ts`; the resource and its subscription handlers are exported `register…` functions in the same file |
| `sequentialthinking` | `index.ts` is the server; `lib.ts` holds `SequentialThinkingServer`, the logic; `version.ts` reads the package version | Inline in `index.ts` |
| `filesystem` | `index.ts` is the stdio entry point (argv → allowed directories, `main()`); `server.ts` exports `createServer(allowedDirectories)`; `lib.ts` holds the file operations and path validation, with the allow-list passed in rather than held globally; `path-utils.ts`, `path-validation.ts` and `roots-utils.ts` are focused helpers; `version.ts` reads the package version | Inline in `createServer()` in `server.ts`, with `server.registerTool(...)` |
| `memory` | `index.ts` holds the `KnowledgeGraphManager`, `createServer(memoryFilePath)` and the stdio `main()`; `version.ts` reads the package version | Inline in `createServer()`; the resource and its subscription handlers are exported `register…` functions in the same file |
| `sequentialthinking` | `index.ts` holds `createServer()` and the stdio `main()`; `lib.ts` holds `SequentialThinkingServer`, the logic; `version.ts` reads the package version | Inline in `createServer()` |

Three things about `everything` that the table cannot hold:

Expand All @@ -50,11 +50,13 @@ Three things about `everything` that the table cannot hold:
`structure.md`, and `src/everything/AGENTS.md` holds the rules that apply
only inside that directory.

`filesystem`, `memory` and `sequentialthinking` run on import: each `index.ts`
builds the server at module scope and connects stdio at the bottom of the
file. That is why their logic lives in a separate module (`lib.ts`) or is
exported from `index.ts` for the tests, and why a test cannot import a ready
server from them. `/testing` covers what that means for a new test.
**No server starts on import.** Each one builds its server in a
`createServer(...)` factory, and its entry file connects a transport only when
it is the process entry point (an `isEntryPoint()` or `isMainModule()` check
that compares real paths, so the npm bin symlink still starts it). Keep it that
way: a module that binds a port, connects stdio or installs a signal handler at
import cannot be driven in-process by the tests. `/testing` covers the
in-process harness.

## The Python servers

Expand Down Expand Up @@ -88,7 +90,7 @@ importable.
| --- | --- |
| A tool, resource or prompt for `everything` | Its own kebab-case file in `tools/`, `resources/` or `prompts/`, exporting a `register…` function, wired into that directory's `index.ts` |
| A transport for `everything` | `src/everything/transports/`, plus a `case` in `src/everything/index.ts` and a `start:…` script |
| A tool for `filesystem`, `memory` or `sequentialthinking` | A `server.registerTool(...)` call in that server's `index.ts`; the logic it calls goes in `lib.ts` (or the class it extends) so a test can reach it |
| A tool for `filesystem`, `memory` or `sequentialthinking` | A `server.registerTool(...)` call inside that server's `createServer()` (`server.ts` in `filesystem`, `index.ts` in the other two); the logic it calls goes in `lib.ts` (or the class it extends) |
| A helper module for `everything` | A kebab-case `.ts` file in the feature area it supports, beside its users (`server/logging.ts`, `server/roots.ts`, `resources/session.ts`), imported with the `.js` extension |
| A helper module for `filesystem`, `memory` or `sequentialthinking` | A kebab-case `.ts` file at the workspace root, imported with the `.js` extension |
| A tool for a Python server | `server.py`: the tool-name enum member (`git`, `time`), the model, the `list_tools` entry, the `call_tool` branch |
Expand Down
Loading
Loading