@sumrco/cli 0.1.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.
Files changed (51) hide show
  1. package/README.md +36 -0
  2. package/ai/modules/kontract/resources/configuration.rf.md +123 -0
  3. package/ai/modules/kontract/resources/generated-output.rf.md +179 -0
  4. package/ai/modules/kontract/resources/openapi-generator-lessons.rf.md +61 -0
  5. package/ai/modules/kontract/resources/overview.md +115 -0
  6. package/ai/modules/kontract/resources/performance.rf.md +90 -0
  7. package/ai/modules/kontract/resources/schema-reuse.rf.md +233 -0
  8. package/ai/modules/kontract/resources/scope-and-splitting.rf.md +147 -0
  9. package/ai/modules/kontract/resources/spec-layout.rf.md +69 -0
  10. package/ai/modules/kontract/resources/team-members/contract-author.tm.md +52 -0
  11. package/ai/modules/kontract/resources/workflows/contract-change.wf.md +60 -0
  12. package/ai/modules/kontract/sumr.module.yaml +42 -0
  13. package/ai/modules/mission/resources/flow-actions.rf.md +40 -0
  14. package/ai/modules/mission/resources/flow-config.rf.md +39 -0
  15. package/ai/modules/mission/resources/flow-safety-boundaries.rf.md +23 -0
  16. package/ai/modules/mission/resources/overview.md +69 -0
  17. package/ai/modules/mission/resources/stage-closeout.rf.md +21 -0
  18. package/ai/modules/mission/resources/stage-delivery.rf.md +36 -0
  19. package/ai/modules/mission/resources/stage-intake.rf.md +39 -0
  20. package/ai/modules/mission/resources/stage-planning.rf.md +21 -0
  21. package/ai/modules/mission/resources/stage-pull-request.rf.md +50 -0
  22. package/ai/modules/mission/resources/stage-quality.rf.md +22 -0
  23. package/ai/modules/mission/resources/team-members/delivery-lead.tm.md +39 -0
  24. package/ai/modules/mission/resources/team-members/implementer.tm.md +25 -0
  25. package/ai/modules/mission/resources/team-members/planner.tm.md +102 -0
  26. package/ai/modules/mission/resources/team-members/pr-writer.tm.md +57 -0
  27. package/ai/modules/mission/resources/team-members/product-owner.tm.md +37 -0
  28. package/ai/modules/mission/resources/team-members/quality-lead.tm.md +34 -0
  29. package/ai/modules/mission/resources/workflows/daily-triage.wf.md +117 -0
  30. package/ai/modules/mission/resources/workflows/full-delivery.wf.md +18 -0
  31. package/ai/modules/mission/resources/workflows/mission-cycle.wf.md +30 -0
  32. package/ai/modules/mission/resources/workflows/planning-only.wf.md +68 -0
  33. package/ai/modules/mission/resources/workflows/pr-assist.wf.md +21 -0
  34. package/ai/modules/mission/resources/workflows/standard-delivery.wf.md +18 -0
  35. package/ai/modules/mission/sumr.module.yaml +78 -0
  36. package/ai/modules/playbook/resources/authoring/content-structure.rf.md +148 -0
  37. package/ai/modules/playbook/resources/authoring/cross-referencing.rf.md +57 -0
  38. package/ai/modules/playbook/resources/authoring/descriptions.rf.md +71 -0
  39. package/ai/modules/playbook/resources/authoring/extraction.rf.md +81 -0
  40. package/ai/modules/playbook/resources/authoring/flows.rf.md +55 -0
  41. package/ai/modules/playbook/resources/authoring/folder-structure.rf.md +148 -0
  42. package/ai/modules/playbook/resources/authoring/frontmatter.rf.md +251 -0
  43. package/ai/modules/playbook/resources/authoring/markdown.rf.md +108 -0
  44. package/ai/modules/playbook/resources/authoring/overview.md +213 -0
  45. package/ai/modules/playbook/resources/team-members/playbook-technical-writer.tm.md +31 -0
  46. package/ai/modules/playbook/sumr.module.yaml +47 -0
  47. package/ai/registry.json +18 -0
  48. package/bin/_sumr +4 -0
  49. package/bin/sumr +7 -0
  50. package/index.js +410 -0
  51. package/package.json +52 -0
package/README.md ADDED
@@ -0,0 +1,36 @@
1
+ <h1 align="center">
2
+ <p align="center">
3
+ <img src="https://dev.sumr.co/sumr-docs.svg" alt="SUMR" width="250" />
4
+ </p>
5
+ </h1>
6
+
7
+ <p align="center">
8
+ <strong>The official SUMR CLI for project setup, account access, and AI workflow tooling.</strong>
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="https://www.npmjs.com/package/@sumrco/cli"><img src="https://img.shields.io/npm/v/@sumrco/cli?color=693776&label=npm" alt="npm version" /></a>
13
+ <img src="https://img.shields.io/badge/runtime-Bun-4d4d4d" alt="Bun runtime" />
14
+ </p>
15
+
16
+ <p align="center">
17
+ <a href="#-install">Install</a>
18
+ ·
19
+ <a href="#-quick-start">Quick start</a>
20
+ </p>
21
+
22
+ ---
23
+
24
+ ## 🚀 Install
25
+
26
+ ```bash
27
+ bun add -g @sumrco/cli
28
+ ```
29
+
30
+ ## ⚡ Quick start
31
+
32
+ ```bash
33
+ sumr --help
34
+ sumr login
35
+ sumr init
36
+ ```
@@ -0,0 +1,123 @@
1
+ ---
2
+ category: reference
3
+ name: configuration
4
+ title: Kontract Configuration
5
+ description: "How `sumr.yaml` configures Kontract sources, targets, generator types, and NestJS output options."
6
+ label: Configuration
7
+ when: Adding a Kontract target, debugging missing generated files, or comparing generated output across repos
8
+ order: 15
9
+ ---
10
+
11
+ # Kontract Configuration
12
+
13
+ Kontract reads repo-local configuration from `sumr.yaml`. A source points at a
14
+ schema directory; each target chooses an output directory and generator.
15
+
16
+ ```yaml
17
+ kontract:
18
+ sources:
19
+ - name: api
20
+ input: schema
21
+ targets:
22
+ - name: backend
23
+ output: backend/src/shared/models
24
+ generator:
25
+ type: typescript-nestjs
26
+ zod: true
27
+ dtos: true
28
+ - name: frontend
29
+ output: frontend/src/shared/api
30
+ generator:
31
+ type: typescript-fetch
32
+ modelPropertyNaming: original
33
+ paramNaming: original
34
+ stringEnums: true
35
+ ```
36
+
37
+ ## Sources
38
+
39
+ | Field | Meaning |
40
+ |---|---|
41
+ | `name` | Stable source name used by `--source`. |
42
+ | `input` | Directory scanned recursively for `*.openapi.yml`, `*.openapi.yaml`, `*.asyncapi.yml`, and `*.asyncapi.yaml`. |
43
+ | `targets` | One or more generated outputs. |
44
+
45
+ Use `--source <name>` to scope validation or generation to one source.
46
+
47
+ ## Targets
48
+
49
+ | Field | Meaning |
50
+ |---|---|
51
+ | `name` | Stable target name used by `--target`. |
52
+ | `output` | Root directory for generated output. Treat this folder as generated/read-only. |
53
+ | `generator.type` | Generator family. |
54
+
55
+ Use `--target <name>` to scope generation to one target.
56
+
57
+ ## Generator types
58
+
59
+ | Type | Purpose |
60
+ |---|---|
61
+ | `typescript-nestjs` | Backend HTTP contracts for NestJS services. |
62
+ | `asyncapi-nats` | NATS subjects, message schemas, server interfaces, and clients. |
63
+ | `typescript-fetch` | TypeScript fetch SDK. |
64
+ | `typescript-axios` | TypeScript axios SDK. |
65
+ | `typescript-angular` | Angular SDK. |
66
+ | `typescript-models` | Framework-neutral model-only output. |
67
+
68
+ ## `typescript-nestjs` options
69
+
70
+ | Option | Output |
71
+ |---|---|
72
+ | `zod: true` | Emits `http/zod/*.contract.ts` with Zod schemas and `createZodDto()` classes. |
73
+ | `dtos: true` | Emits `http/dto/*.dto.ts` plus `http/swagger.ts` operation metadata. |
74
+
75
+ `dtos` is the canonical spelling. `dto: true` is accepted as a compatibility
76
+ alias and is normalized internally to `dtos: true`.
77
+
78
+ Framework-neutral interfaces under `http/models/` and enums under `http/enums/`
79
+ are emitted for OpenAPI object schemas regardless of the Zod/DTO flavor.
80
+
81
+ ## Common debugging cases
82
+
83
+ ### `http/dto/` or `http/swagger.ts` is missing
84
+
85
+ Check both:
86
+
87
+ 1. The target config has `generator.type: typescript-nestjs` and `dtos: true`.
88
+ `dto: true` is also accepted, but prefer `dtos` in new config.
89
+ 2. The installed `SUMR Kontract module` version includes DTO/swagger support.
90
+
91
+ If two configs generate identical output and both miss `dto/` + `swagger.ts`,
92
+ the likely issue is the generator version being executed, not the consumer
93
+ repo's config.
94
+
95
+ ### `http/zod/` is missing
96
+
97
+ Check that the NestJS target has `zod: true` or that Zod generation has not been
98
+ explicitly disabled.
99
+
100
+ ### Generated files are stale
101
+
102
+ Run a scoped clean generation:
103
+
104
+ ```bash
105
+ sumr kontract generate --source api --target backend --clean
106
+ ```
107
+
108
+ Prefer scoping `--clean` in large repos so only the intended generated output
109
+ and selected Kontract cache are removed before regeneration.
110
+
111
+ ### Warm generation is still slow
112
+
113
+ Kontract stores incremental manifests under `.sumr-cache/kontract`. An unchanged
114
+ warm run should skip unchanged services before parse/emit and should not run a
115
+ formatter subprocess.
116
+
117
+ If warm runs regenerate everything, check for:
118
+
119
+ 1. generated files being manually edited or deleted;
120
+ 2. changing generator config in `sumr.yaml`;
121
+ 3. a changed installed `SUMR Kontract module` version;
122
+ 4. ambiguous or remote `$ref` usage that forces the safe path;
123
+ 5. `--clean`, which intentionally clears selected output and cache state.
@@ -0,0 +1,179 @@
1
+ ---
2
+ category: reference
3
+ name: generated-output
4
+ title: Generated Output Contract
5
+ description: "The exact shape of TypeScript files Kontract generates and how to consume them in NestJS."
6
+ label: Generated Output
7
+ when: Importing generated contracts, reviewing a generation diff, or wiring NATS/HTTP clients into a service
8
+ order: 20
9
+ ---
10
+
11
+ # Generated Output Contract
12
+
13
+ Generated files are deterministic outputs. Import them; never edit them.
14
+ Every generated TypeScript file starts with an `<auto-generated>` comment that
15
+ warns users not to edit the file directly.
16
+
17
+ ## HTTP output — one folder per OpenAPI service
18
+
19
+ For an OpenAPI service such as `recipes.openapi.yml`, the NestJS target
20
+ emits a service folder:
21
+
22
+ ```text
23
+ contracts/recipes/
24
+ index.ts
25
+ http/
26
+ index.ts
27
+ enums/
28
+ models/
29
+ zod/ # when zod generation is enabled
30
+ dto/ # when dtos generation is enabled
31
+ swagger.ts # when dtos generation is enabled
32
+ ```
33
+
34
+ Shared `$ref` components keep the source spec DRY and semantically consistent.
35
+ Today, supported `allOf` object composition is flattened in the generated
36
+ service output, so some concrete response DTOs may still repeat envelope fields.
37
+ Do not fix that by hand-editing generated files. If generated code repeats too
38
+ much, first improve the spec with shared components; then consider a Kontract
39
+ generator improvement such as preserved composition or shared external
40
+ component output.
41
+
42
+ `http/index.ts` intentionally uses namespace exports for folders that can share
43
+ symbol names:
44
+
45
+ ```typescript
46
+ export * as Dtos from './dto';
47
+ export * as Models from './models';
48
+ export * as ZodContracts from './zod';
49
+ export * from './enums';
50
+ export * from './swagger';
51
+ ```
52
+
53
+ Do not flatten-import everything blindly when DTO/model/Zod symbols collide.
54
+ Use the namespace exports or import from the leaf folder.
55
+
56
+ ## Zod contract — one file per OpenAPI `components/schemas` entry
57
+
58
+ ```typescript
59
+ // contracts/recipes/http/zod/recipe.contract.ts
60
+ import { z } from 'zod';
61
+ import { createZodDto } from 'nestjs-zod';
62
+
63
+ export const RecipeSchema = z.object({
64
+ id: z.string().uuid(),
65
+ name: z.string().min(1).max(255),
66
+ status: z.enum(['draft', 'published', 'archived']),
67
+ });
68
+
69
+ export class RecipeDto extends createZodDto(RecipeSchema) {}
70
+ export type Recipe = z.infer<typeof RecipeSchema>;
71
+ ```
72
+
73
+ Every generated Zod contract yields `${Name}Schema` + `${Name}Dto` +
74
+ `type ${Name}`.
75
+
76
+ ## Model interface — one file per object schema
77
+
78
+ ```typescript
79
+ // contracts/recipes/http/models/recipe.ts
80
+ export interface Recipe {
81
+ id: string;
82
+ name: string;
83
+ status: RecipeStatus;
84
+ }
85
+ ```
86
+
87
+ Model interfaces are framework-neutral and are safe for backend and frontend
88
+ type-only imports.
89
+
90
+ Map-shaped schemas follow OpenAPI `additionalProperties` semantics:
91
+
92
+ - map-only schemas generate index signatures such as `[key: string]: string`;
93
+ - named properties with `additionalProperties: true` preserve the named fields
94
+ and use `[key: string]: unknown`;
95
+ - named properties with typed `additionalProperties` preserve named fields and
96
+ widen the index signature with known property value types, matching the
97
+ practical TypeScript approach used by current OpenAPI TypeScript generators.
98
+
99
+ ## Class-validator DTO — when `dtos: true`
100
+
101
+ ```typescript
102
+ // contracts/recipes/http/dto/recipe.dto.ts
103
+ import { ApiProperty } from '@nestjs/swagger';
104
+ import { Expose } from 'class-transformer';
105
+ import { IsString, IsUUID } from 'class-validator';
106
+
107
+ export class RecipeDto {
108
+ @ApiProperty({ format: 'uuid' })
109
+ @IsUUID()
110
+ @Expose()
111
+ id!: string;
112
+
113
+ @ApiProperty()
114
+ @IsString()
115
+ @Expose()
116
+ name!: string;
117
+ }
118
+ ```
119
+
120
+ DTO files are generated for NestJS controllers and Swagger decorators. Generated
121
+ properties include `@Expose()` so they remain compatible with class-transformer
122
+ serializers that use `excludeExtraneousValues: true`. Do not hand-write parallel
123
+ DTOs for schemas Kontract owns.
124
+
125
+ ## Swagger operation metadata — when `dtos: true`
126
+
127
+ ```typescript
128
+ // contracts/recipes/http/swagger.ts
129
+ import type { RecipeDto } from './dto/recipe.dto';
130
+
131
+ export const SWG_LIST_RECIPES = {
132
+ method: 'GET',
133
+ path: '/recipes',
134
+ operationId: 'listRecipes',
135
+ responseDto: RecipeDto,
136
+ } as const;
137
+ ```
138
+
139
+ Controllers can consume `SWG_*` metadata to keep operation IDs, paths, params,
140
+ body DTOs, and response DTOs aligned with OpenAPI.
141
+
142
+ ## NATS contract — one `nats/index.ts` per AsyncAPI service
143
+
144
+ ```typescript
145
+ // contracts/recipes/nats/index.ts
146
+ export namespace Recipes {
147
+ export const CreateRecipeMessage = z.object({ name: z.string(), slug: z.string() });
148
+ export type CreateRecipeMessage = z.infer<typeof CreateRecipeMessage>;
149
+ export type CreateRecipeMessageInput = z.input<typeof CreateRecipeMessage>;
150
+
151
+ export const SUBJECTS = {
152
+ CREATE_RECIPE: 'example.recipes.command.createRecipe',
153
+ } as const;
154
+
155
+ export interface ICommandServer { /* ... */ }
156
+ export class CommandClient { /* validates with .parse() then proxy.send() */ }
157
+ export class QueryClient { /* ... */ }
158
+ export class EventClient { /* ... */ }
159
+ }
160
+ ```
161
+
162
+ - Namespace name comes from AsyncAPI `info.title`.
163
+ - Every message yields a Zod const + `z.infer<>` type + `z.input<>` input type.
164
+ - Subjects live in a single `SUBJECTS` const used directly by NestJS NATS.
165
+ - Clients validate input with `.parse()` before sending.
166
+
167
+ ## Consuming in NestJS
168
+
169
+ - Use `http/zod` `${Name}Dto` classes when you want `nestjs-zod` request/response
170
+ validation.
171
+ - Use `http/dto` classes and `http/swagger.ts` when a controller follows the
172
+ class-validator + Swagger metadata pattern.
173
+ - Use `http/models` interfaces for type-only internal code.
174
+ - Use the generated `*Client` classes and `SUBJECTS` for NATS — do not
175
+ hand-write subjects or message shapes.
176
+ - Each generated directory has a barrel `index.ts` for local aggregation only.
177
+ - Regenerate (`sumr kontract generate`) after any spec change; unchanged
178
+ work items are skipped with `.sumr-cache/kontract` manifests when source,
179
+ config, generator, and output hashes still match.
@@ -0,0 +1,61 @@
1
+ ---
2
+ category: reference
3
+ name: openapi-generator-lessons
4
+ title: OpenAPI Generator Bug Lessons
5
+ description: "Hardening lessons Kontract applies from public OpenAPI Generator NestJS/TypeScript bug reports. Use when reviewing generated output risks, query parameters, inline schemas, and strict TypeScript compatibility."
6
+ label: OpenAPI Generator Lessons
7
+ when: Reviewing Kontract specs or generator changes for known OpenAPI/NestJS codegen failure modes
8
+ order: 45
9
+ ---
10
+
11
+ # OpenAPI Generator Bug Lessons
12
+
13
+ Kontract learns from public OpenAPI/NestJS generator bugs without inheriting their
14
+ architecture. These lessons are guardrails for spec authors, reviewers, and AI agents
15
+ working on generated contracts.
16
+
17
+ ## Core lessons
18
+
19
+ - **Preserve query parameter semantics.** Optional query params stay optional, array query
20
+ params serialize as repeated keys, and enum query params use generated enum symbols instead
21
+ of raw literal imports.
22
+ - **Do not let wire names become unsafe local variables.** Parameter names such as `from`,
23
+ `class`, and `default` must remain valid wire keys while generated local identifiers are
24
+ safe TypeScript names.
25
+ - **Prefer component `$ref` schemas over anonymous inline operation models.** Kontract rejects
26
+ inline request/response schemas because anonymous model naming commonly causes duplicate
27
+ `InlineObject` outputs and unstable imports.
28
+ - **Generate maps deliberately.** `additionalProperties` map schemas must preserve named
29
+ properties and typed catch-all/index-signature values consistently across Zod, DTOs, models,
30
+ and SDK output. Unsupported `oneOf`, `anyOf`, `not`, and discriminators should produce clear
31
+ errors instead of partially generated code with missing symbols such as `AnyType` or
32
+ `InnerEnum`.
33
+ - **Keep NestJS ownership boundaries clean.** Kontract emits contracts, DTOs, models, swagger
34
+ metadata, and SDK clients. Application modules, controllers, providers, and DI wiring stay in
35
+ the consuming NestJS app.
36
+ - **Compile generated code under strict TypeScript assumptions.** Generated output should avoid
37
+ dangling imports, deprecated Nest HTTP client imports, stale `basePath` globals, `Map` headers
38
+ where records are expected, and framework symbols that were never emitted.
39
+ - **Stay Bun-native.** Kontract does not depend on Java, Docker images, downloaded generator
40
+ binaries, or template folders at generation time.
41
+
42
+ ## Spec authoring rules
43
+
44
+ - Put reusable request/response bodies, parameters, enums, and object fragments under
45
+ `components` and reference them with `$ref`.
46
+ - Encode validation constraints in the OpenAPI schema (`minLength`, `maxLength`, `minimum`,
47
+ `maximum`, `pattern`, `format`) so DTO/Zod output can enforce them.
48
+ - Use `additionalProperties` when the payload is intentionally map-shaped. Prefer typed map values
49
+ over `additionalProperties: true`; Kontract preserves named fields and emits a safe unknown
50
+ catch-all when the spec intentionally allows arbitrary values.
51
+ - For repeated query values, use `type: array` with scalar `items`; generated SDKs must not
52
+ collapse values into comma-separated strings.
53
+
54
+ ## Reviewer checklist
55
+
56
+ - Generated files include the auto-generated header and are not hand-edited.
57
+ - Query DTOs and SDK request types preserve optionality from the spec.
58
+ - No generated file contains `any`, `AnyType`, `InlineObject`, `InnerEnum`, `queryParameters`,
59
+ deprecated `HttpService`, stale `basePath`, or unsafe `apiKeys` access.
60
+ - Operation schemas reference named components instead of inline request/response objects.
61
+ - Unsupported schema features fail before any consumer repo is left with partial broken output.
@@ -0,0 +1,115 @@
1
+ ---
2
+ name: usage
3
+ title: Kontract Usage
4
+ description: "How to use the SUMR Kontract CLI to generate NestJS-ready TypeScript contracts from OpenAPI and AsyncAPI specs. Use when adding, changing, reviewing, validating, or generating API contracts."
5
+ tags: [kontract, contracts, openapi, asyncapi, nestjs, codegen]
6
+ ---
7
+
8
+ # Kontract Usage
9
+
10
+ Kontract turns YAML API specs into typed, validated TypeScript: NestJS HTTP
11
+ contracts, optional class-validator DTOs, Swagger operation metadata, frontend
12
+ SDKs, NATS subjects, server interfaces, and clients — all from a single source
13
+ of truth so implementations do not drift from the contract.
14
+
15
+ ## When to Use
16
+
17
+ - Adding or editing an OpenAPI (`*.openapi.yml`) or AsyncAPI (`*.asyncapi.yml`) spec.
18
+ - Reviewing newly written or updated `*.openapi.yml` / `*.asyncapi.yml` files
19
+ against Kontract best practices before validation or generation.
20
+ - Refactoring duplicated schema fields into shared `$ref` components.
21
+ - Regenerating contracts after a spec change.
22
+ - Validating specs before committing or in CI.
23
+ - Wiring generated contracts into a NestJS microservice.
24
+
25
+ ## Commands
26
+
27
+ ```bash
28
+ sumr kontract init # activate Kontract AI guidance for this repo
29
+ sumr kontract validate # validate configured OpenAPI/AsyncAPI sources
30
+ sumr kontract generate # generate TypeScript contracts and SDKs
31
+ ```
32
+
33
+ Useful flags:
34
+
35
+ - `--source <name>` — limit to one configured source
36
+ - `--target <name>` — limit to one configured target
37
+ - `-c, --concurrency <n>` — max parallel workers
38
+ - `--verbose` / `--quiet` — log level (`CI=true` implies quiet)
39
+ - `generate` also accepts `-s, --specific <name>` to generate one service spec
40
+ - `generate` also accepts `--clean` to remove selected generated outputs and the
41
+ selected Kontract bundle cache before regenerating
42
+
43
+ ## The Model
44
+
45
+ ```text
46
+ schema/
47
+ recipes.openapi.yml → contracts/recipes/http/
48
+ recipes.asyncapi.yml → contracts/recipes/nats/index.ts
49
+ ```
50
+
51
+ One source of truth (the YAML spec) → many generated, always-consistent
52
+ TypeScript artifacts. Generated files are outputs: never hand-edit them — change
53
+ the spec and regenerate.
54
+
55
+ ## Configuration
56
+
57
+ Kontract is configured from the repo's `sumr.yaml` under `kontract.sources`.
58
+ Each source points at an input directory and one or more targets:
59
+
60
+ ```yaml
61
+ kontract:
62
+ sources:
63
+ - name: api
64
+ input: schema
65
+ targets:
66
+ - name: backend
67
+ output: backend/src/shared/models
68
+ generator:
69
+ type: typescript-nestjs
70
+ zod: true
71
+ dtos: true
72
+ - name: frontend
73
+ output: frontend/src/shared/api
74
+ generator:
75
+ type: typescript-fetch
76
+ ```
77
+
78
+ For `typescript-nestjs`:
79
+
80
+ - `zod: true` emits NestJS-Zod contracts under `http/zod/`.
81
+ - `dtos: true` emits class-validator DTOs under `http/dto/` plus
82
+ `http/swagger.ts` operation metadata.
83
+ - `dto: true` is accepted as a compatibility alias for `dtos: true`; prefer
84
+ `dtos` in new config.
85
+ - Framework-neutral model interfaces are emitted under `http/models/`.
86
+
87
+ If a consuming repo is missing `http/dto/` or `http/swagger.ts`, first confirm
88
+ the target has `dtos: true` (or `dto: true`) and that the installed
89
+ `SUMR Kontract module` version contains DTO/swagger support.
90
+
91
+ ## Core Rules
92
+
93
+ - Validate before you generate: `sumr kontract validate` then `sumr kontract generate`.
94
+ - Treat everything under the generated `contracts/` output as read-only.
95
+ - Keep specs the single source of truth; do not hand-write Zod/DTOs that Kontract owns.
96
+ - After writing or updating any `*.openapi.yml` or `*.asyncapi.yml` file, review
97
+ the spec for duplicated concepts before generation.
98
+ - Design specs for reuse: shared parameters, scalar constraints, error responses,
99
+ response envelope fragments, pagination metadata, schedule/time-slot shapes,
100
+ and common config objects belong in shared components referenced with `$ref`.
101
+ - See the spec layout and generated output references for the exact file shapes.
102
+ - See the scope and splitting reference when a spec or Kontract source file
103
+ crosses the review thresholds, mixes domains, or needs domain/subdomain
104
+ structure.
105
+ - See the schema reuse reference before adding repeated fields or reviewing a
106
+ generated diff with many near-identical DTO/model files.
107
+ - See the OpenAPI generator lessons reference before changing query params,
108
+ inline schemas, SDK serialization, or strict TypeScript compatibility rules.
109
+ - Use scoped flags (`--source`, `--target`, `--specific`) before `--clean` in a
110
+ large consumer repo.
111
+ - Warm generation is manifest-driven. Kontract stores per-service manifests in
112
+ `.sumr-cache/kontract`, skips only when source/config/generator/output hashes
113
+ match, and regenerates if generated files were manually changed or deleted.
114
+ - For large repos, use normal generation first; use `--clean` only when you need
115
+ to intentionally clear selected generated outputs and Kontract cache state.
@@ -0,0 +1,90 @@
1
+ ---
2
+ category: reference
3
+ name: performance
4
+ title: Kontract Performance and Incremental Generation
5
+ description: "How Kontract uses manifests, bundle cache, workers, and batched formatting to keep large schema generations safe and fast."
6
+ label: Performance
7
+ when: Debugging slow `sumr kontract generate`, deciding whether to use `--clean`, or estimating large schema runs
8
+ order: 30
9
+ ---
10
+
11
+ # Kontract Performance and Incremental Generation
12
+
13
+ Kontract is optimized for safe warm runs in large repos. It prefers correctness over stale output: if a cache state is ambiguous, it regenerates.
14
+
15
+ ## Incremental manifests
16
+
17
+ For each configured source/target/service/channel, Kontract writes a manifest under the repo-local cache:
18
+
19
+ ```text
20
+ .sumr-cache/kontract/bundles/<source>/<target>/manifests/<channel>/<service>/manifest.json
21
+ ```
22
+
23
+ The manifest records the generator config hash, generator implementation hash, source dependency graph hash, output tree hash, generated files, Bun version, and package version.
24
+
25
+ Warm generation skips a service before parsing/emitting only when all hashes still match. Manual generated-file edits or deletions invalidate the output tree hash and force regeneration.
26
+
27
+ ## Clean generation
28
+
29
+ Use scoped clean when the cache or generated output may be stale:
30
+
31
+ ```bash
32
+ sumr kontract generate --source api --target backend --clean
33
+ ```
34
+
35
+ `--clean` removes the selected generated output roots and selected Kontract cache/manifests. It does not remove `.sumr-cache/activations.json`.
36
+
37
+ ## Formatting strategy
38
+
39
+ CLI generation does not spawn Biome once per generated file. It writes changed files first, then runs one Biome directory format per changed output root. Unchanged warm runs should have zero formatter subprocesses.
40
+
41
+ ## Bundling strategy
42
+
43
+ OpenAPI roots with no `$ref` or only internal `#/...` refs skip bundling. Roots with external
44
+ refs use Redocly's OpenAPI core in-process, and safe bundles are cached under:
45
+
46
+ ```text
47
+ .sumr-cache/kontract/bundles/<source>/source-cache/bundle-cache/
48
+ ```
49
+
50
+ The source-scoped bundle cache is shared across targets in the same source. A BCHQ-style source
51
+ that generates backend NestJS contracts and frontend models should bundle each unchanged external
52
+ OpenAPI root once, not once per target. Unsafe or ambiguous refs still fall back to target-scoped
53
+ temporary bundling.
54
+
55
+ Ambiguous multiline or remote refs take the safe path and regenerate/bundle rather than trusting a stale cache.
56
+
57
+ Emergency fallback:
58
+
59
+ ```bash
60
+ KONTRACT_DISABLE_REDOCLY_CORE=1 sumr kontract generate
61
+ ```
62
+
63
+ ## Worker strategy
64
+
65
+ When concurrency is greater than one, Kontract uses a Bun worker pool for parse/extract/emit/write tasks. The main process still owns discovery, manifest validation, final barrels, final formatting, and summaries.
66
+
67
+ Emergency/debug fallbacks:
68
+
69
+ ```bash
70
+ KONTRACT_DISABLE_WORKERS=1 sumr kontract generate
71
+ KONTRACT_FORCE_MAIN_THREAD=1 sumr kontract generate
72
+ ```
73
+
74
+ ## Benchmarking
75
+
76
+ Use the local synthetic benchmark before changing generation orchestration, formatting, file writing, bundling, or cache behavior:
77
+
78
+ ```bash
79
+ bun run tools perf generate --count=50 --concurrency=8 --mode=both
80
+ bun run tools perf generate --count=100 --concurrency=8 --mode=both --root=.tmp/kontract-performance-100
81
+ bun run tools perf generate --count=20 --concurrency=8 --mode=both --refs=external --targets=both
82
+ ```
83
+
84
+ Benchmark output stays under `.tmp/` and writes both `results.json` and `README.md` with phase timings, counters, and subprocess resource usage. Use `--refs=internal` to confirm bundling is skipped, and `--refs=external --targets=both` to confirm the shared bundle cache keeps cold-run in-process bundling at roughly one per schema root instead of one per target.
85
+
86
+ Local signal after in-process OpenAPI bundling:
87
+
88
+ - `--count=1000 --refs=external --targets=both --concurrency=8`: cold `8.72s`, warm `0.83s`.
89
+ - Warm manifests skipped all `2000` source/target work items and ran zero formatter/bundler subprocesses.
90
+ - Cold formatting stayed at 2 Biome subprocesses for 2 changed output roots.