@cyanheads/mcp-ts-core 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,48 +1,167 @@
1
1
  ---
2
2
  name: maintenance
3
3
  description: >
4
- Sync skills and dependencies after package updates. Use after running `bun update @cyanheads/mcp-ts-core` to ensure project skills are up to date, or periodically to check for drift.
4
+ Investigate, adopt, and verify dependency updates with special handling for `@cyanheads/mcp-ts-core`. Captures what changed, understands why, cross-references against the codebase, adopts framework improvements, syncs project skills, and runs final checks. Supports two entry modes: run the full flow end-to-end, or review updates you already applied.
5
5
  metadata:
6
6
  author: cyanheads
7
- version: "1.2"
7
+ version: "1.3"
8
8
  audience: external
9
9
  type: workflow
10
10
  ---
11
11
 
12
- ## Context
12
+ ## When to Use
13
13
 
14
- Skills flow from the package to the project:
14
+ - After running `bun update --latest` yourself and wanting to review the impact (**Mode B** — typical)
15
+ - To run the whole flow end-to-end — outdated check → update → investigate → adopt → verify (**Mode A**)
16
+ - Periodically, to check for skill drift from the package
15
17
 
16
- 1. **Package** — `node_modules/@cyanheads/mcp-ts-core/skills/` (canonical source, updated via `bun update`)
17
- 2. **Project** — `skills/` at project root (working copy, can have local overrides or server-specific skills)
18
+ ## Entry Modes
18
19
 
19
- After `bun update @cyanheads/mcp-ts-core`, the package may have newer skills than the project. This skill syncs them and handles general dependency upkeep.
20
+ | Mode | Starting Point | First Step |
21
+ |:-----|:---------------|:-----------|
22
+ | **A — Full flow** | Lockfile is current; want to update | Step 1 |
23
+ | **B — Post-update review** | User already ran `bun update --latest` + `bun run rebuild` + `bun run test` | Skip to Step 3 with the update output or `git diff bun.lock` |
24
+
25
+ Both modes converge at Step 3 and end at Step 8.
20
26
 
21
27
  ## Steps
22
28
 
23
- ### Sync project skills (Package Project)
29
+ ### 1. Survey what's outdated (Mode A only)
30
+
31
+ ```bash
32
+ bun outdated
33
+ ```
34
+
35
+ Note: `bun update --latest` crosses semver majors; `bun update` alone respects ranges. Use `--latest` unless a package is intentionally pinned.
36
+
37
+ ### 2. Apply the update (Mode A only)
38
+
39
+ ```bash
40
+ bun update --latest
41
+ ```
42
+
43
+ Capture the `↑ package old → new` lines from stdout — these feed Step 3. Alternatively, `git diff bun.lock` surfaces version deltas after the fact.
44
+
45
+ ### 3. Investigate changelogs
46
+
47
+ Invoke the **`changelog`** skill with the captured list of updated packages. It resolves each repo, fetches release notes (or CHANGELOG entries) between old and new versions, and cross-references changes against actual imports in `src/`. Output per package: what changed, impact on this project, action items.
48
+
49
+ Do not redo this investigation inline — the `changelog` skill handles tag-format detection, monorepo patterns, and fallbacks.
50
+
51
+ ### 4. Framework review (`@cyanheads/mcp-ts-core`)
52
+
53
+ If `@cyanheads/mcp-ts-core` was updated, do a deeper pass beyond what the `changelog` skill covers. Read:
54
+
55
+ ```bash
56
+ node_modules/@cyanheads/mcp-ts-core/CHANGELOG.md
57
+ ```
58
+
59
+ Extract entries between the old and new version. Scan specifically for:
60
+
61
+ | Area | Adoption Check |
62
+ |:-----|:---------------|
63
+ | New error factories in `/errors` | Replace ad-hoc `new McpError(...)` with factories where applicable |
64
+ | New utilities in `/utils` | Identify any that supersede local helper code |
65
+ | New context capabilities | Added `ctx.*` methods worth adopting |
66
+ | Provider/service APIs | Updates to `OpenRouterProvider`, `SpeechService`, `GraphService`, etc. |
67
+ | Deprecations | Migrate now, before the next breaking release |
68
+ | Config changes | New env vars, renamed keys, changed defaults |
69
+ | Linter rules | New definition-lint rules that may now flag existing tools/resources |
70
+
71
+ Cross-reference each finding against the server's code. Collect adoption opportunities for Step 6.
72
+
73
+ **Template review.** The framework also ships `templates/CLAUDE.md` and `templates/AGENTS.md` as scaffolding for consumer agent protocol files. The consumer's `CLAUDE.md`/`AGENTS.md` was copied at init time and has since diverged (local customizations, echo replacements, server-specific sections). Read the upstream template fresh:
74
+
75
+ ```bash
76
+ node_modules/@cyanheads/mcp-ts-core/templates/CLAUDE.md
77
+ ```
78
+
79
+ Skip the mechanical diff — consumer customizations create too much noise to filter. Instead, read end-to-end with fresh eyes, mentally comparing against the current `CLAUDE.md`. Look for: new conventions, updated skill references, expanded checklists, new callouts, clearer explanations, restructured sections. Present findings; let the user cherry-pick what to adopt. Never auto-merge — the consumer's file is theirs.
80
+
81
+ ### 5. Sync project skills
82
+
83
+ Skills flow in two hops: package → project `skills/` → agent directories.
84
+
85
+ **Phase A — Package → Project `skills/`**
86
+
87
+ 1. **Package** — `node_modules/@cyanheads/mcp-ts-core/skills/` (canonical source)
88
+ 2. **Project** — `skills/` at project root (working copy; may contain local overrides or server-specific skills)
89
+
90
+ Procedure:
24
91
 
25
92
  1. List all skill directories in `node_modules/@cyanheads/mcp-ts-core/skills/`
26
93
  2. For each skill with `metadata.audience: external` in its `SKILL.md` frontmatter:
27
- - If the skill does not exist in project `skills/`, copy the full directory
28
- - If it exists, compare `metadata.version` — if the package version is newer, replace the full directory
94
+ - If missing in project `skills/`, copy the full directory
95
+ - If present, compare `metadata.version` — replace if the package version is newer
29
96
  - If the local version is equal or newer, skip (local override)
30
97
  3. Do not touch skills in `skills/` that don't exist in the package (server-specific)
31
98
 
32
- ### Dependency updates
99
+ **Phase B — Project `skills/` → Agent directories**
100
+
101
+ The `setup` skill instructs consumers to copy `skills/*` into their agent's skill directory at init time. Those copies go stale unless re-synced. Detect which agent directories exist and propagate:
102
+
103
+ | Agent | Directory |
104
+ |:------|:----------|
105
+ | Claude Code | `.claude/skills/` |
106
+ | Generic / shared | `.agents/skills/` |
107
+ | Codex | `.codex/skills/` |
108
+ | Cursor | `.cursor/skills/` |
109
+ | Windsurf | `.windsurf/skills/` |
110
+
111
+ For each agent directory that exists:
112
+
113
+ 1. For every directory in project `skills/`, copy it into the agent dir (overwrite on match, add if missing)
114
+ 2. Do **not** delete skills in the agent dir that aren't in project `skills/` — they may be general-purpose skills sourced elsewhere (e.g., `code-security`, `cloudflare`, `changelog`)
115
+
116
+ If no agent directory exists, skip Phase B — the project hasn't opted in to per-agent skill copies.
117
+
118
+ **Report** which skills were added/updated in Phase A (with version deltas) and which agent directories were refreshed in Phase B. The user needs to know what new guidance is now available and where.
119
+
120
+ ### 6. Adopt changes in the codebase
121
+
122
+ Apply the findings from Steps 3 and 4:
123
+
124
+ - **Breaking changes** — fix call sites
125
+ - **Deprecations** — migrate now, while context is fresh
126
+ - **New framework features** — refactor targeted spots only; don't cargo-cult everywhere
127
+ - **New configuration** — update `.env.example`, server config schema, README if user-facing
128
+
129
+ Keep diffs focused. Don't sweep refactors beyond the update's scope.
130
+
131
+ ### 7. Rebuild and verify
132
+
133
+ ```bash
134
+ bun run rebuild
135
+ bun run devcheck
136
+ bun run test
137
+ ```
138
+
139
+ `rebuild` (clean + build) catches API surface and type-alignment issues that `devcheck` alone may miss — module resolution, path aliases, post-build processing. `devcheck` includes `bun audit` and `bun outdated`, so no separate audit step is needed.
140
+
141
+ In **Mode B**, the user already ran rebuild + test before invoking this skill, but run them again here — Step 6 made code changes that need verification.
142
+
143
+ Fix anything that fails. Re-run until clean.
144
+
145
+ ### 8. Summary
146
+
147
+ Present a concise numbered summary to the user:
33
148
 
34
- 1. Run `bun outdated` to see what's available
35
- 2. For any major version bumps, review changelogs before proceeding
36
- 3. Run `bun update` to apply updates
37
- 4. Run `bun audit` to check for vulnerabilities introduced by the update
38
- 5. Run `bun run devcheck` to confirm lint, definitions, types, and dependency/security checks still pass
39
- 6. Run `bun run test` to confirm runtime behavior still passes
149
+ 1. **Updated packages** short list with version deltas (N total)
150
+ 2. **Breaking changes handled** call sites fixed
151
+ 3. **Features adopted** new framework APIs now in use
152
+ 4. **Skills synced** added/updated with versions (Phase A) and agent directories refreshed (Phase B)
153
+ 5. **Needs attention** anything deferred, flagged for decision, or risky
154
+ 6. **Status** rebuild / devcheck / test results
40
155
 
41
156
  ## Checklist
42
157
 
43
- - [ ] Package skills compared against project `skills/` (version check)
44
- - [ ] New or updated skills copied to project `skills/`
45
- - [ ] Dependencies updated (`bun update`)
46
- - [ ] `bun audit` passes (no new vulnerabilities)
47
- - [ ] `bun run devcheck` passes
158
+ - [ ] Update applied (`bun update --latest`) Mode A, or already done by user — Mode B
159
+ - [ ] `changelog` skill invoked for each updated package
160
+ - [ ] Framework CHANGELOG reviewed if `@cyanheads/mcp-ts-core` was updated
161
+ - [ ] Adoption opportunities identified and applied
162
+ - [ ] Project `skills/` synced from package (Phase A), with a change report
163
+ - [ ] Agent skill directories (`.claude/skills/`, `.agents/skills/`, etc.) refreshed from project `skills/` (Phase B)
164
+ - [ ] `bun run rebuild` succeeds
165
+ - [ ] `bun run devcheck` passes (includes audit + outdated)
48
166
  - [ ] `bun run test` passes
167
+ - [ ] Numbered summary presented to user
@@ -11,7 +11,7 @@ metadata:
11
11
 
12
12
  ## Context
13
13
 
14
- This skill assumes `@cyanheads/mcp-ts-core init` has already run. The CLI created the project's `CLAUDE.md` and `AGENTS.md` for different agents, copied external skills to `skills/`, and scaffolded the directory structure with echo definitions as starting points. This skill covers what was created and what to do next.
14
+ This skill assumes `npx @cyanheads/mcp-ts-core init [name]` has already run. The CLI created the project's `CLAUDE.md` and `AGENTS.md` for different agents, copied external skills to `skills/`, and scaffolded the directory structure with echo definitions as starting points. This skill covers what was created and what to do next.
15
15
 
16
16
  ## Agent Protocol File
17
17
 
@@ -91,7 +91,7 @@ mkdir -p .claude/skills && cp -R skills/* .claude/skills/
91
91
 
92
92
  **For other agents** (Codex, Cursor, Windsurf, etc.) — copy to the equivalent directory (e.g., `.codex/skills/`, `.cursor/skills/`).
93
93
 
94
- After the initial copy, use the `maintenance` skill to keep them in sync after package updates.
94
+ This step is the **bootstrap** — it creates the agent directory. From then on, use the `maintenance` skill to refresh it after package updates (Phase B). Maintenance only refreshes directories that already exist; it won't create a new agent directory on your behalf.
95
95
 
96
96
  ## Project Scaffolding
97
97
 
@@ -14,8 +14,7 @@
14
14
 
15
15
  1. **Read the framework API** — `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md`
16
16
  2. **Run the `setup` skill** — read `skills/setup/SKILL.md` and follow its checklist (project orientation, agent protocol file selection, echo definition cleanup, skill sync)
17
- 3. **Check for Bun** — run `bun --version`. If [Bun](https://bun.sh) is available, it's the recommended runtime: update `package.json` scripts to use `bun` instead of `tsx` (e.g., `"devcheck": "bun scripts/devcheck.ts"`), prefer `bun run` over `npm run` for all commands, and update the Commands table and Checklist in this file to match.
18
- 4. **Design the server** — read `skills/design-mcp-server/SKILL.md` and work through it with the user to map the domain into tools, resources, and services before scaffolding
17
+ 3. **Design the server** — read `skills/design-mcp-server/SKILL.md` and work through it with the user to map the domain into tools, resources, and services before scaffolding
19
18
 
20
19
  ---
21
20
 
@@ -25,13 +24,13 @@ When the user asks what to do next, what's left, or needs direction, suggest rel
25
24
 
26
25
  1. **Re-run the `setup` skill** — ensures CLAUDE.md, skills, structure, and metadata are populated and up to date with the current codebase
27
26
  2. **Run the `design-mcp-server` skill** — if the tool/resource surface hasn't been mapped yet, work through domain design
28
- 3. **Add tools/resources/prompts** — scaffold new definitions using the `add-tool`, `add-resource`, `add-prompt` skills
27
+ 3. **Add tools/resources/prompts** — scaffold new definitions using the `add-tool`, `add-app-tool`, `add-resource`, `add-prompt` skills
29
28
  4. **Add services** — scaffold domain service integrations using the `add-service` skill
30
29
  5. **Add tests** — scaffold tests for existing definitions using the `add-test` skill
31
30
  6. **Field-test definitions** — exercise tools/resources/prompts with real inputs using the `field-test` skill, get a report of issues and pain points
32
31
  7. **Run `devcheck`** — lint, format, typecheck, and security audit
33
32
  8. **Run the `polish-docs-meta` skill** — finalize README, CHANGELOG, metadata, and agent protocol for shipping
34
- 9. **Run the `maintenance` skill** — sync skills and dependencies after framework updates
33
+ 9. **Run the `maintenance` skill** — investigate changelogs, adopt upstream changes, and sync skills after `bun update --latest`
35
34
 
36
35
  Tailor suggestions to what's actually missing or stale — don't recite the full list every time.
37
36
 
@@ -122,20 +121,26 @@ export const reviewCode = prompt('review_code', {
122
121
 
123
122
  ```ts
124
123
  // src/config/server-config.ts — lazy-parsed, separate from framework config
124
+ import { z } from '@cyanheads/mcp-ts-core';
125
+ import { parseEnvConfig } from '@cyanheads/mcp-ts-core/config';
126
+
125
127
  const ServerConfigSchema = z.object({
126
- myApiKey: z.string().describe('External API key'),
128
+ apiKey: z.string().describe('External API key'),
127
129
  maxResults: z.coerce.number().default(100),
128
130
  });
131
+
129
132
  let _config: z.infer<typeof ServerConfigSchema> | undefined;
130
133
  export function getServerConfig() {
131
- _config ??= ServerConfigSchema.parse({
132
- myApiKey: process.env.MY_API_KEY,
133
- maxResults: process.env.MY_MAX_RESULTS,
134
+ _config ??= parseEnvConfig(ServerConfigSchema, {
135
+ apiKey: 'MY_API_KEY',
136
+ maxResults: 'MY_MAX_RESULTS',
134
137
  });
135
138
  return _config;
136
139
  }
137
140
  ```
138
141
 
142
+ `parseEnvConfig` maps Zod schema paths → env var names so validation errors name the actual variable (`MY_API_KEY`) rather than the internal path (`apiKey`). It throws a `ConfigurationError` the framework catches and prints as a clean startup banner.
143
+
139
144
  ---
140
145
 
141
146
  ## Context
@@ -215,7 +220,7 @@ src/
215
220
 
216
221
  Skills are modular instructions in `skills/` at the project root. Read them directly when a task matches — e.g., `skills/add-tool/SKILL.md` when adding a tool.
217
222
 
218
- **Agent skill directory:** Copy skills into the directory your agent discovers (Claude Code: `.claude/skills/`, others: equivalent). This makes skills available as context without needing to reference `skills/` paths manually. After framework updates, re-copy to pick up changes.
223
+ **Agent skill directory:** Copy skills into the directory your agent discovers (Claude Code: `.claude/skills/`, others: equivalent). This makes skills available as context without needing to reference `skills/` paths manually. After framework updates, run the `maintenance` skill — it re-syncs the agent directory automatically (Phase B).
219
224
 
220
225
  Available skills:
221
226
 
@@ -232,7 +237,7 @@ Available skills:
232
237
  | `field-test` | Exercise tools/resources/prompts with real inputs, verify behavior, report issues |
233
238
  | `devcheck` | Lint, format, typecheck, audit |
234
239
  | `polish-docs-meta` | Finalize docs, README, metadata, and agent protocol for shipping |
235
- | `maintenance` | Sync skills and dependencies after updates |
240
+ | `maintenance` | Investigate changelogs, adopt upstream changes, sync skills to agent dirs |
236
241
  | `report-issue-framework` | File a bug or feature request against `@cyanheads/mcp-ts-core` via `gh` CLI |
237
242
  | `report-issue-local` | File a bug or feature request against this server's own repo via `gh` CLI |
238
243
  | `api-auth` | Auth modes, scopes, JWT/OAuth |
@@ -250,6 +255,8 @@ When you complete a skill's checklist, check the boxes and add a completion time
250
255
 
251
256
  ## Commands
252
257
 
258
+ **Runtime:** Scripts use `tsx` — both `npm run <cmd>` and `bun run <cmd>` work. Use whichever package manager you have; `bun` is slightly faster for invoking scripts but not required.
259
+
253
260
  | Command | Purpose |
254
261
  |:--------|:--------|
255
262
  | `npm run build` | Compile TypeScript |
@@ -281,7 +288,7 @@ import { getMyService } from '@/services/my-domain/my-service.js';
281
288
 
282
289
  ## Checklist
283
290
 
284
- - [ ] Zod schemas: all fields have `.describe()`, only JSON-Schema-serializable types (no `z.custom()`, `z.date()`, `z.transform()`, etc.)
291
+ - [ ] Zod schemas: all fields have `.describe()`, only JSON-Schema-serializable types (no `z.custom()`, `z.date()`, `z.transform()`, `z.bigint()`, `z.symbol()`, `z.void()`, `z.map()`, `z.set()`, `z.function()`, `z.nan()`)
285
292
  - [ ] Optional nested objects: handler guards for empty inner values from form-based clients (`if (input.obj?.field && ...)`, not just `if (input.obj)`)
286
293
  - [ ] JSDoc `@fileoverview` + `@module` on every file
287
294
  - [ ] `ctx.log` for logging, `ctx.state` for storage
@@ -14,8 +14,7 @@
14
14
 
15
15
  1. **Read the framework API** — `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md`
16
16
  2. **Run the `setup` skill** — read `skills/setup/SKILL.md` and follow its checklist (project orientation, agent protocol file selection, echo definition cleanup, skill sync)
17
- 3. **Check for Bun** — run `bun --version`. If [Bun](https://bun.sh) is available, it's the recommended runtime: update `package.json` scripts to use `bun` instead of `tsx` (e.g., `"devcheck": "bun scripts/devcheck.ts"`), prefer `bun run` over `npm run` for all commands, and update the Commands table and Checklist in this file to match.
18
- 4. **Design the server** — read `skills/design-mcp-server/SKILL.md` and work through it with the user to map the domain into tools, resources, and services before scaffolding
17
+ 3. **Design the server** — read `skills/design-mcp-server/SKILL.md` and work through it with the user to map the domain into tools, resources, and services before scaffolding
19
18
 
20
19
  ---
21
20
 
@@ -31,7 +30,7 @@ When the user asks what to do next, what's left, or needs direction, suggest rel
31
30
  6. **Field-test definitions** — exercise tools/resources/prompts with real inputs using the `field-test` skill, get a report of issues and pain points
32
31
  7. **Run `devcheck`** — lint, format, typecheck, and security audit
33
32
  8. **Run the `polish-docs-meta` skill** — finalize README, CHANGELOG, metadata, and agent protocol for shipping
34
- 9. **Run the `maintenance` skill** — sync skills and dependencies after framework updates
33
+ 9. **Run the `maintenance` skill** — investigate changelogs, adopt upstream changes, and sync skills after `bun update --latest`
35
34
 
36
35
  Tailor suggestions to what's actually missing or stale — don't recite the full list every time.
37
36
 
@@ -122,20 +121,26 @@ export const reviewCode = prompt('review_code', {
122
121
 
123
122
  ```ts
124
123
  // src/config/server-config.ts — lazy-parsed, separate from framework config
124
+ import { z } from '@cyanheads/mcp-ts-core';
125
+ import { parseEnvConfig } from '@cyanheads/mcp-ts-core/config';
126
+
125
127
  const ServerConfigSchema = z.object({
126
- myApiKey: z.string().describe('External API key'),
128
+ apiKey: z.string().describe('External API key'),
127
129
  maxResults: z.coerce.number().default(100),
128
130
  });
131
+
129
132
  let _config: z.infer<typeof ServerConfigSchema> | undefined;
130
133
  export function getServerConfig() {
131
- _config ??= ServerConfigSchema.parse({
132
- myApiKey: process.env.MY_API_KEY,
133
- maxResults: process.env.MY_MAX_RESULTS,
134
+ _config ??= parseEnvConfig(ServerConfigSchema, {
135
+ apiKey: 'MY_API_KEY',
136
+ maxResults: 'MY_MAX_RESULTS',
134
137
  });
135
138
  return _config;
136
139
  }
137
140
  ```
138
141
 
142
+ `parseEnvConfig` maps Zod schema paths → env var names so validation errors name the actual variable (`MY_API_KEY`) rather than the internal path (`apiKey`). It throws a `ConfigurationError` the framework catches and prints as a clean startup banner.
143
+
139
144
  ---
140
145
 
141
146
  ## Context
@@ -215,7 +220,7 @@ src/
215
220
 
216
221
  Skills are modular instructions in `skills/` at the project root. Read them directly when a task matches — e.g., `skills/add-tool/SKILL.md` when adding a tool.
217
222
 
218
- **Agent skill directory:** Copy skills into the directory your agent discovers (Claude Code: `.claude/skills/`, others: equivalent). This makes skills available as context without needing to reference `skills/` paths manually. After framework updates, re-copy to pick up changes.
223
+ **Agent skill directory:** Copy skills into the directory your agent discovers (Claude Code: `.claude/skills/`, others: equivalent). This makes skills available as context without needing to reference `skills/` paths manually. After framework updates, run the `maintenance` skill — it re-syncs the agent directory automatically (Phase B).
219
224
 
220
225
  Available skills:
221
226
 
@@ -232,7 +237,7 @@ Available skills:
232
237
  | `field-test` | Exercise tools/resources/prompts with real inputs, verify behavior, report issues |
233
238
  | `devcheck` | Lint, format, typecheck, audit |
234
239
  | `polish-docs-meta` | Finalize docs, README, metadata, and agent protocol for shipping |
235
- | `maintenance` | Sync skills and dependencies after updates |
240
+ | `maintenance` | Investigate changelogs, adopt upstream changes, sync skills to agent dirs |
236
241
  | `report-issue-framework` | File a bug or feature request against `@cyanheads/mcp-ts-core` via `gh` CLI |
237
242
  | `report-issue-local` | File a bug or feature request against this server's own repo via `gh` CLI |
238
243
  | `api-auth` | Auth modes, scopes, JWT/OAuth |
@@ -250,6 +255,8 @@ When you complete a skill's checklist, check the boxes and add a completion time
250
255
 
251
256
  ## Commands
252
257
 
258
+ **Runtime:** Scripts use `tsx` — both `npm run <cmd>` and `bun run <cmd>` work. Use whichever package manager you have; `bun` is slightly faster for invoking scripts but not required.
259
+
253
260
  | Command | Purpose |
254
261
  |:--------|:--------|
255
262
  | `npm run build` | Compile TypeScript |
@@ -281,7 +288,7 @@ import { getMyService } from '@/services/my-domain/my-service.js';
281
288
 
282
289
  ## Checklist
283
290
 
284
- - [ ] Zod schemas: all fields have `.describe()`, only JSON-Schema-serializable types (no `z.custom()`, `z.date()`, `z.transform()`, etc.)
291
+ - [ ] Zod schemas: all fields have `.describe()`, only JSON-Schema-serializable types (no `z.custom()`, `z.date()`, `z.transform()`, `z.bigint()`, `z.symbol()`, `z.void()`, `z.map()`, `z.set()`, `z.function()`, `z.nan()`)
285
292
  - [ ] Optional nested objects: handler guards for empty inner values from form-based clients (`if (input.obj?.field && ...)`, not just `if (input.obj)`)
286
293
  - [ ] JSDoc `@fileoverview` + `@module` on every file
287
294
  - [ ] `ctx.log` for logging, `ctx.state` for storage