@khanhspring/forge-spec 1.0.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.
@@ -0,0 +1,282 @@
1
+ # Main contract skeleton — copy and fill in for {feature-slug}.
2
+ # Placeholders in {curly braces} are substituted per feature/resource.
3
+ # Schemas and the shared/ error + pagination objects live in separate files (see best-practices.md);
4
+ # this main file holds only info + paths + $refs.
5
+
6
+ openapi: "3.0.0"
7
+
8
+ info:
9
+ title: "{Module Name} — {Feature Name}"
10
+ version: "1.0.0"
11
+ description: "Contract for {feature-slug}. Spec: ../../features/{slug}/spec.md"
12
+
13
+ servers:
14
+ - url: http://localhost:{port}
15
+ description: Local development
16
+
17
+ security:
18
+ - bearerAuth: []
19
+
20
+ paths:
21
+ /api/v1/{resources}:
22
+ post:
23
+ summary: "Create a new {resource}"
24
+ operationId: "create{Resource}"
25
+ tags: ["{feature-slug}"]
26
+ requestBody:
27
+ required: true
28
+ content:
29
+ application/json:
30
+ schema:
31
+ $ref: "./schemas/create-{resource}-request.yaml"
32
+ examples:
33
+ valid:
34
+ value:
35
+ {field}: "{example}"
36
+ responses:
37
+ "201":
38
+ description: "{Resource} created successfully"
39
+ headers:
40
+ Location:
41
+ description: "URL of the created resource"
42
+ schema:
43
+ type: string
44
+ example: "/api/v1/{resources}/123e4567-e89b-12d3-a456-426614174000"
45
+ content:
46
+ application/json:
47
+ schema:
48
+ $ref: "./schemas/{resource}-reference.yaml"
49
+ examples:
50
+ success:
51
+ value:
52
+ id: "123e4567-e89b-12d3-a456-426614174000"
53
+ "400":
54
+ $ref: "#/components/responses/BadRequest"
55
+ "401":
56
+ $ref: "#/components/responses/Unauthorized"
57
+ "409":
58
+ $ref: "#/components/responses/Conflict"
59
+ "500":
60
+ $ref: "#/components/responses/InternalError"
61
+
62
+ get:
63
+ summary: "List {resources}"
64
+ operationId: "list{Resources}"
65
+ tags: ["{feature-slug}"]
66
+ parameters:
67
+ - name: page
68
+ in: query
69
+ schema:
70
+ type: integer
71
+ default: 1
72
+ minimum: 1
73
+ - name: size
74
+ in: query
75
+ schema:
76
+ type: integer
77
+ default: 20
78
+ minimum: 1
79
+ maximum: 100
80
+ - name: sort
81
+ in: query
82
+ schema:
83
+ type: string
84
+ example: "createdAt"
85
+ - name: order
86
+ in: query
87
+ schema:
88
+ type: string
89
+ enum: [asc, desc]
90
+ default: desc
91
+ responses:
92
+ "200":
93
+ description: "Paginated list of {resources}"
94
+ content:
95
+ application/json:
96
+ schema:
97
+ type: object
98
+ required: [data, pagination]
99
+ properties:
100
+ data:
101
+ type: array
102
+ items:
103
+ $ref: "./schemas/{resource}-summary.yaml"
104
+ pagination:
105
+ $ref: "./shared/pagination-meta.yaml"
106
+ examples:
107
+ success:
108
+ value:
109
+ data:
110
+ - id: "123e4567-e89b-12d3-a456-426614174000"
111
+ {field}: "{value}"
112
+ pagination:
113
+ page: 1
114
+ size: 20
115
+ total: 1
116
+ totalPages: 1
117
+ "401":
118
+ $ref: "#/components/responses/Unauthorized"
119
+ "500":
120
+ $ref: "#/components/responses/InternalError"
121
+
122
+ /api/v1/{resources}/{id}:
123
+ parameters:
124
+ - name: id
125
+ in: path
126
+ required: true
127
+ schema:
128
+ type: string
129
+ format: uuid
130
+
131
+ get:
132
+ summary: "Get {resource} by ID"
133
+ operationId: "get{Resource}ById"
134
+ tags: ["{feature-slug}"]
135
+ responses:
136
+ "200":
137
+ description: "{Resource} found"
138
+ content:
139
+ application/json:
140
+ schema:
141
+ $ref: "./schemas/{resource}-response.yaml"
142
+ examples:
143
+ success:
144
+ value:
145
+ id: "123e4567-e89b-12d3-a456-426614174000"
146
+ {field}: "{value}"
147
+ createdAt: "2024-01-15T10:30:00Z"
148
+ "401":
149
+ $ref: "#/components/responses/Unauthorized"
150
+ "404":
151
+ $ref: "#/components/responses/NotFound"
152
+ "500":
153
+ $ref: "#/components/responses/InternalError"
154
+
155
+ patch:
156
+ summary: "Update {resource}"
157
+ operationId: "update{Resource}"
158
+ tags: ["{feature-slug}"]
159
+ requestBody:
160
+ required: true
161
+ content:
162
+ application/json:
163
+ schema:
164
+ $ref: "./schemas/update-{resource}-request.yaml"
165
+ examples:
166
+ valid:
167
+ value:
168
+ {field}: "{example}"
169
+ responses:
170
+ "204":
171
+ description: "Updated successfully"
172
+ "400":
173
+ $ref: "#/components/responses/BadRequest"
174
+ "401":
175
+ $ref: "#/components/responses/Unauthorized"
176
+ "403":
177
+ $ref: "#/components/responses/Forbidden"
178
+ "404":
179
+ $ref: "#/components/responses/NotFound"
180
+ "500":
181
+ $ref: "#/components/responses/InternalError"
182
+
183
+ delete:
184
+ summary: "Delete {resource}"
185
+ operationId: "delete{Resource}"
186
+ tags: ["{feature-slug}"]
187
+ responses:
188
+ "204":
189
+ description: "Deleted successfully"
190
+ "401":
191
+ $ref: "#/components/responses/Unauthorized"
192
+ "403":
193
+ $ref: "#/components/responses/Forbidden"
194
+ "404":
195
+ $ref: "#/components/responses/NotFound"
196
+ "500":
197
+ $ref: "#/components/responses/InternalError"
198
+
199
+ components:
200
+ responses:
201
+ BadRequest:
202
+ description: "Validation failed"
203
+ content:
204
+ application/json:
205
+ schema:
206
+ $ref: "./shared/api-error.yaml"
207
+ examples:
208
+ validationError:
209
+ value:
210
+ code: "VALIDATION_ERROR"
211
+ message: "Validation failed for 1 field(s)"
212
+ traceId: "123e4567-e89b-12d3-a456-426614174000"
213
+ details:
214
+ - field: "email"
215
+ code: "INVALID_FORMAT"
216
+ message: "Must be a valid email address"
217
+ Unauthorized:
218
+ description: "Not authenticated"
219
+ content:
220
+ application/json:
221
+ schema:
222
+ $ref: "./shared/api-error.yaml"
223
+ examples:
224
+ unauthenticated:
225
+ value:
226
+ code: "UNAUTHENTICATED"
227
+ message: "Missing or invalid authentication token"
228
+ traceId: "123e4567-e89b-12d3-a456-426614174000"
229
+ Forbidden:
230
+ description: "Not authorized"
231
+ content:
232
+ application/json:
233
+ schema:
234
+ $ref: "./shared/api-error.yaml"
235
+ examples:
236
+ forbidden:
237
+ value:
238
+ code: "FORBIDDEN"
239
+ message: "You do not have permission to perform this action"
240
+ traceId: "123e4567-e89b-12d3-a456-426614174000"
241
+ NotFound:
242
+ description: "Resource not found"
243
+ content:
244
+ application/json:
245
+ schema:
246
+ $ref: "./shared/api-error.yaml"
247
+ examples:
248
+ notFound:
249
+ value:
250
+ code: "NOT_FOUND"
251
+ message: "{Resource} not found"
252
+ traceId: "123e4567-e89b-12d3-a456-426614174000"
253
+ Conflict:
254
+ description: "Resource already exists or state conflict"
255
+ content:
256
+ application/json:
257
+ schema:
258
+ $ref: "./shared/api-error.yaml"
259
+ examples:
260
+ conflict:
261
+ value:
262
+ code: "ALREADY_EXISTS"
263
+ message: "{Resource} already exists"
264
+ traceId: "123e4567-e89b-12d3-a456-426614174000"
265
+ InternalError:
266
+ description: "Unexpected server error"
267
+ content:
268
+ application/json:
269
+ schema:
270
+ $ref: "./shared/api-error.yaml"
271
+ examples:
272
+ internalError:
273
+ value:
274
+ code: "INTERNAL_ERROR"
275
+ message: "An unexpected error occurred"
276
+ traceId: "123e4567-e89b-12d3-a456-426614174000"
277
+
278
+ securitySchemes:
279
+ bearerAuth:
280
+ type: http
281
+ scheme: bearer
282
+ bearerFormat: JWT
@@ -0,0 +1,205 @@
1
+ ---
2
+ name: "forge-init"
3
+ description: "One-time initialization for a Forge spec repo. Walks through setup conversationally one question at a time, then writes .forge/project.json, CLAUDE.md, and directory scaffolding on confirmation."
4
+ argument-hint: "Optional: project name to skip the first prompt"
5
+ compatibility: "Run once in a spec repo before any other forge skills. Safe to re-run — never overwrites existing files."
6
+ when_to_use: >
7
+ ALWAYS activate when any of the following occur:
8
+ - User says init, initialize, setup, set up, bootstrap, configure + repo/forge/project
9
+ - User says "set this up", "get this started", "prepare this repo"
10
+ - No .forge/project.json exists AND user wants to start planning features or writing specs
11
+ - User says "this is a new spec repo" or "add forge to this project"
12
+ Do NOT activate if .forge/project.json already exists — repo is already initialized.
13
+ metadata:
14
+ author: "forge-workflow"
15
+ source: "spec-skills/forge-init/SKILL.md"
16
+ user-invocable: true
17
+ disable-model-invocation: false
18
+ ---
19
+
20
+ # Forge Init — Spec Repo
21
+
22
+ Initialize this repo as a Forge spec repo. Ask questions one at a time, build up the
23
+ config through conversation, then write everything in one go after confirmation.
24
+
25
+ ## Pre-check
26
+ If `.forge/project.json` already exists → say "Spec repo already initialized." and stop.
27
+
28
+ ---
29
+
30
+ ## Phase 1 — Project identity
31
+
32
+ Ask one question at a time. Wait for each answer before asking the next.
33
+
34
+ **Q1.** "What's the project name? (kebab-case slug, e.g. `my-platform`)"
35
+
36
+ **Q2.** "What does this project do? (1–2 sentences)"
37
+
38
+ **Q3.** "What's the spec repo remote URL?
39
+ _(Skip with 'none' if it's not set up yet — you can add it later with `/forge-config`)_"
40
+
41
+ ---
42
+
43
+ ## Phase 2 — Modules
44
+
45
+ Collect modules one at a time. Each module is gathered field by field.
46
+
47
+ Start with:
48
+ > "Now let's add the services and apps that make up this project. First module — what's its name? (kebab-case, e.g. `user-service`)"
49
+
50
+ For each module, ask these in order (one question per message):
51
+
52
+ 1. **Name** — already asked above
53
+ 2. **Type** — "Is `{name}` a backend service, frontend app, or something else?
54
+ _(backend / frontend / worker / gateway)_"
55
+ 3. **Stack** — "What's the tech stack for `{name}`? (e.g. `Spring Boot 3, Java 21` or `React, TypeScript`)"
56
+ 4. **Port** — "What port does `{name}` run on locally?"
57
+ 5. **Repo URL** — "What's the git repo URL for `{name}`?
58
+ _(Skip with 'none' if not set up yet)_"
59
+ 6. **Description** — "One sentence: what does `{name}` do?
60
+ _(Skip with 'none')_"
61
+
62
+ After collecting all fields for a module, confirm it back:
63
+
64
+ > "Got it:
65
+ > `{name}` — {type} — {stack} — :{port} — {repo or 'no repo yet'}
66
+ > {description}
67
+ > Is that right?"
68
+
69
+ Then ask:
70
+ > "Any more modules to add? (yes / no)"
71
+
72
+ If yes, repeat from step 1 of this phase for the next module.
73
+ If no, move to Phase 3.
74
+
75
+ ---
76
+
77
+ ## Phase 3 — Principles & conventions
78
+
79
+ Ask one at a time. "None" or "not yet" are valid answers — these sections can be filled
80
+ in later with `/forge-config`.
81
+
82
+ **Q1.** "What are the core principles or rules for this project?
83
+ _(e.g. 'API contract before implementation', 'no breaking changes without versioning')
84
+ Say 'none yet' to skip._"
85
+
86
+ **Q2.** "Any coding or API conventions the whole team should follow?
87
+ _(e.g. 'all endpoints versioned under /api/v1', 'use kebab-case for URL paths')
88
+ Say 'none yet' to skip._"
89
+
90
+ **Q3.** "Anything explicitly out of scope or forbidden across services?
91
+ _(e.g. 'no direct DB access across service boundaries', 'no sync inter-service calls')
92
+ Say 'none yet' to skip._"
93
+
94
+ ---
95
+
96
+ ## Phase 4 — Preview & gate
97
+
98
+ Show a full preview of what will be written:
99
+
100
+ ```
101
+ Ready to initialize. Here's what I'll create:
102
+
103
+ .forge/project.json
104
+ project: {name}
105
+ modules: {n} module(s): {comma-separated names}
106
+ spec_repo: {url or "not set"}
107
+
108
+ CLAUDE.md
109
+ Description: {description}
110
+ Modules: {n} listed
111
+ Principles: {list or "none yet"}
112
+ Conventions: {list or "none yet"}
113
+ Out of scope: {list or "none yet"}
114
+
115
+ features/.gitkeep
116
+ contracts/.gitkeep
117
+ .gitignore ← append Forge entries
118
+ ```
119
+
120
+ > "Does this look right? Say **yes** to initialize, or tell me what to change."
121
+
122
+ Wait for confirmation. Do not write anything before the user says yes.
123
+
124
+ ---
125
+
126
+ ## Phase 5 — Write files
127
+
128
+ Write `.forge/project.json`:
129
+ ```json
130
+ {
131
+ "project": "{project-name}",
132
+ "version": "1.0",
133
+ "modules": [
134
+ {
135
+ "name": "{module-name}",
136
+ "repo": "{repo-url}",
137
+ "type": "backend|frontend|worker|gateway",
138
+ "stack": ["{stack}"],
139
+ "port": {port},
140
+ "description": "{description}"
141
+ }
142
+ ],
143
+ "spec_repo": "{spec-repo-url}",
144
+ "contract_format": "openapi3",
145
+ "contract_tool": "specmatic"
146
+ }
147
+ ```
148
+
149
+ Write `CLAUDE.md`:
150
+ ```markdown
151
+ # {project-name}
152
+
153
+ {description}
154
+
155
+ ## Modules
156
+ | Name | Type | Stack | Port |
157
+ |------|------|-------|------|
158
+ | {name} | {type} | {stack} | {port} |
159
+
160
+ ## Forge Workflow
161
+ 1. `/forge-brainstorm` — explore and define a feature
162
+ 2. `/forge-spec` — write the spec
163
+ 3. `/forge-tasks` — break into per-module tasks
164
+ 4. `/forge-contract` — generate Specmatic OpenAPI contracts
165
+ 5. `/forge-close {slug} {module}` — mark a module's tasks done (after module repo ships)
166
+
167
+ Utilities: `/forge-status` (feature dashboard) · `/forge-config` (edit modules/ports)
168
+
169
+ ## Principles
170
+ {list each as a bullet — or "None defined yet."}
171
+
172
+ ## Conventions
173
+ {list each as a bullet — or "None defined yet."}
174
+
175
+ ## Out of Scope / Forbidden
176
+ {list each as a bullet — or "None defined yet."}
177
+
178
+ ## Structure
179
+ - `features/{slug}/brainstorm.md` — approved brainstorm summary
180
+ - `features/{slug}/spec.md` — requirements, flows, API list
181
+ - `features/{slug}/tasks.md` — per-module task breakdown with checkboxes
182
+ - `contracts/{module}/{slug}.yaml` + `schemas/` + `shared/` — Specmatic OpenAPI 3.0 contracts
183
+ ```
184
+
185
+ Create:
186
+ - `features/.gitkeep`
187
+ - `contracts/.gitkeep`
188
+
189
+ Append to `.gitignore` if not present:
190
+ ```
191
+ # Forge
192
+ .forge/secrets
193
+ ```
194
+
195
+ Run `git status` and confirm:
196
+ > "Spec repo initialized. Run `/forge-brainstorm` to plan your first feature."
197
+
198
+ ---
199
+
200
+ ## Rules
201
+ - One question per message — never ask multiple questions at once
202
+ - Never write files before the user says yes in Phase 4
203
+ - Never overwrite existing files
204
+ - All written files must be complete — no unfilled placeholders
205
+ - If the user provides multiple answers in one message, accept them gracefully and move forward