| name | knowject-api-to-types |
| description | Use when the user wants to generate TypeScript types from an OpenAPI document and
wire them into the typed client produced by knowject-read-api. Triggers on phrases
like "/knowject types", "把 openapi 转成 types", "给 read-api client 补类型", "生成
typed client 的类型", "rewrite the unknown placeholders", "wire types into the
generated client". Day-1 input is OpenAPI 3 only — non-OpenAPI inputs (Express
routes, Mongoose, Zod, Pydantic, Spring DTOs, Nest decorators, markdown specs,
etc.) are refused with framework-specific recommendations for exposing OpenAPI.
Two output modes: (1) primary — emit a sibling <module>.types.ts and rewrite
request<unknown>(...) in the read-api client to request<X>(...); (2) fallback —
emit types-only when no read-api client file is found. Both modes use the
diff-first / confirm-before-write safety gate established in Phase 2.
|
knowject-api-to-types
You generate TypeScript types from an OpenAPI 3 document and wire them into the typed client that knowject-read-api produced.
Hard rules
- OpenAPI 3 input only. If
api.sources[*].format is anything else (express / fastapi / nest / markdown / etc.), refuse and recommend the matching OpenAPI exposure tool per references/non-openapi-refusal.md. Do not attempt native parsing.
- Refuse without
knowject/context.yaml. Point at knowject-context-init, stop.
- Refuse without
api.client.output_dir. Cannot decide where to write .types.ts; ask the user, do not assume.
- Header-marker contract. The rewriter only modifies files whose content includes
Generated by knowject-read-api. Files without this marker are never written to by this Skill.
- Never overwrite silently. Show the unified diff of every file change and require confirmation before any write.
- Use the user's language for chat replies; generated TypeScript is always English.
- Day-1 scope is response types only.
request<unknown> becomes request<X>. The body: unknown parameter stays unknown; request-body typing is a v2 extension. See "What this Skill does NOT do" below.
Flow
Step 1 — Verify preconditions
Read knowject/context.yaml:
- File exists. Else → point at
knowject-context-init, stop.
api.sources non-empty. Else → tell the user to run knowject-read-api first or add an OpenAPI source via knowject-context-init, stop.
- For each source: if
format is not openapi, apply the refusal recipe from references/non-openapi-refusal.md. Process only OpenAPI sources.
api.client.output_dir present. Else → ask the user once, then proceed.
Step 2 — Derive the module name
Per OpenAPI source, derive a module name:
- If the source path ends in
/<name>.yaml or /<name>.json → use <name>.
- Else if the source is a directory → use its basename.
- Else → ask the user.
The module name drives the output filenames (<module>.types.ts) and the type-import path in the rewritten client.
Step 3 — Extract types
Run:
python3 <SKILLS_ROOT>/knowject-api-to-types/scripts/extract-types-from-openapi.py \
<openapi-source-path> --module <module-name>
Cache the JSON output ({module, types_ts, operations_mapping}) in memory and write the same JSON to a temp file if Mode A will run the rewriter.
If the extractor exits non-zero, surface its stderr to the user and stop. PyYAML missing (exit 3) → tell the user pip install pyyaml.
Step 4 — Pick the output mode
Look for <api.client.output_dir>/<module>.ts:
- File exists AND contains
Generated by knowject-read-api → Mode A (rewrite). Proceed to Step 5A.
- File missing, or file exists but lacks the marker → Mode B (emit-only). Proceed to Step 5B.
Step 5A — Mode A: emit types + rewrite client
-
Write the types_ts content and the full extraction JSON to temp locations.
-
Run:
python3 <SKILLS_ROOT>/knowject-api-to-types/scripts/rewrite-typed-client.py \
<api.client.output_dir>/<module>.ts \
<path-to-extraction-json> \
<module>
-
Show the user two diffs:
- The new file
<module>.types.ts (it does not exist on disk yet).
- The diff of
<module>.ts (existing client → rewritten client).
-
Ask: "Apply both changes? (yes / types-only / cancel)".
-
On yes → write both files. On types-only → write only the types file, skip the client rewrite. On cancel → stop, nothing written.
Step 5B — Mode B: emit types only
-
Show the user the diff of the new <module>.types.ts (does not exist on disk yet).
-
Ask: "Write <module>.types.ts? (yes / cancel)".
-
On yes → write the file. Output:
<module>.types.ts written. No read-api typed client found at
<api.client.output_dir>/<module>.ts — wire the types manually, or
run knowject-read-api first and then re-run this Skill to enable
the automatic rewrite.
Step 6 — Summarize
Output:
- Files written / skipped.
- Per-endpoint summary from the rewriter's stderr (
rewrote / not_found / no_response_type).
- The next-step hint: "Re-run TypeScript checks (
tsc --noEmit or your equivalent) to validate the new types compile against your code."
Failure modes
knowject/context.yaml missing or api block incomplete: name the missing fields, point at knowject-context-init, stop.
api.sources[*].format is not openapi: apply references/non-openapi-refusal.md, stop.
- OpenAPI source path does not exist on disk: print the expected path verbatim, ask the user whether the file moved.
- OpenAPI document fails to parse (not a mapping, or PyYAML chokes): show stderr verbatim, ask whether the file is OpenAPI 3.
- Extractor produces empty
operations_mapping (no operations in the OpenAPI doc): tell the user "the OpenAPI document contains no operations — nothing to type", stop.
- Rewriter refuses (no header marker): this is expected for user-authored files; the Skill body downgrades to Mode B silently and writes types-only.
- Rewriter reports
not_found for one or more endpoints: continue with partial wiring; surface the unmatched endpoints to the user with a one-line "wire these by hand" hint.
api.client.output_dir does not exist on disk: create it (after user confirmation) before writing.
What this Skill does NOT do
- Does not generate runtime validators (zod / io-ts / yup). Output is TypeScript declarations only (
interface for object schemas, type aliases for non-object schemas). Runtime validation is a separate v2 product candidate.
- Does not type request bodies, query params, or path params. Day-1 scope is response types only. Request types are emitted in
<module>.types.ts for manual wiring; future v2 will extend the rewriter to import and apply them.
- Does not parse non-OpenAPI sources. No Express AST, no Mongoose models, no Zod inference, no Pydantic, no Spring DTOs, no Nest decorators, no markdown. Refuse with
references/non-openapi-refusal.md.
- Does not merge into existing
import blocks. The new import type line is prepended when at least one response type was rewritten; if your project conventions require it elsewhere, move it after Skill output.
- Does not modify the read-api client's function signatures, parameters, or behavior. Only the
request<unknown> generic argument changes.
- Does not run TypeScript / lint / test against the output. That is the user's existing workflow.
See also