@comfanion/workflow 4.36.39 → 4.36.41

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@comfanion/workflow",
3
- "version": "4.36.39",
3
+ "version": "4.36.41",
4
4
  "description": "Initialize OpenCode Workflow system for AI-assisted development with semantic code search",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "4.36.39",
3
- "buildDate": "2026-01-24T21:24:09.542Z",
2
+ "version": "4.36.41",
3
+ "buildDate": "2026-01-24T22:03:27.547Z",
4
4
  "files": [
5
5
  "config.yaml",
6
6
  "FLOW.yaml",
@@ -148,7 +148,7 @@ permission:
148
148
  <rule>Prefer delegation to @coder for parallelizable tasks</rule>
149
149
  <rule>Keep complex logic and architecture decisions to yourself</rule>
150
150
  <rule>Delegate multiple tasks in parallel when independent</rule>
151
- <rule>Always verify @coder results before marking task complete</rule>
151
+ <rule>Always verify results before marking task complete</rule>
152
152
  </delegation-strategy>
153
153
  </subagents>
154
154
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: adr-writing
3
- description: How to write Architecture Decision Records (ADRs) documenting technical decisions and rationale
3
+ description: Use when documenting significant architectural decisions - database choice, framework selection, pattern adoption, or any decision with long-term consequences
4
4
  license: MIT
5
5
  compatibility: opencode
6
6
  metadata:
@@ -0,0 +1,527 @@
1
+ ---
2
+ name: api-design
3
+ description: Use when designing REST, GraphQL, or gRPC APIs, defining contracts, versioning strategy, or documenting endpoints
4
+ license: MIT
5
+ compatibility: opencode
6
+ metadata:
7
+ domain: software-architecture
8
+ patterns: rest, graphql, grpc, openapi
9
+ artifacts: docs/architecture/*/api/*.yaml
10
+ ---
11
+
12
+ # API Design Skill
13
+
14
+ ## When to Use
15
+
16
+ Use this skill when you need to:
17
+ - Design REST API endpoints for a module/service
18
+ - Define GraphQL schema and resolvers
19
+ - Design gRPC service definitions
20
+ - Plan API versioning strategy
21
+ - Document API contracts (OpenAPI/Swagger)
22
+ - Design error responses and status codes
23
+ - Plan authentication/authorization for APIs
24
+
25
+ ## Reference
26
+
27
+ Always check project standards: `@CLAUDE.md`
28
+
29
+ ## Templates
30
+
31
+ - OpenAPI: `@.opencode/skills/api-design/template-openapi.yaml`
32
+ - GraphQL: `@.opencode/skills/api-design/template-graphql.md`
33
+
34
+ ---
35
+
36
+ ## API Type Selection
37
+
38
+ | Type | Use When | Avoid When |
39
+ |------|----------|------------|
40
+ | **REST** | CRUD operations, public APIs, caching needed | Complex queries, real-time |
41
+ | **GraphQL** | Flexible queries, mobile clients, nested data | Simple CRUD, caching critical |
42
+ | **gRPC** | Service-to-service, high performance, streaming | Browser clients, public APIs |
43
+ | **WebSocket** | Real-time, bidirectional, live updates | Request-response patterns |
44
+
45
+ ---
46
+
47
+ ## REST API Design
48
+
49
+ ### URL Structure
50
+
51
+ ```
52
+ # Collection
53
+ GET /api/v1/tasks # List
54
+ POST /api/v1/tasks # Create
55
+
56
+ # Resource
57
+ GET /api/v1/tasks/{id} # Read
58
+ PUT /api/v1/tasks/{id} # Replace
59
+ PATCH /api/v1/tasks/{id} # Partial update
60
+ DELETE /api/v1/tasks/{id} # Delete
61
+
62
+ # Nested resources (when child belongs to parent)
63
+ GET /api/v1/projects/{id}/tasks
64
+ POST /api/v1/projects/{id}/tasks
65
+
66
+ # Actions (non-CRUD operations)
67
+ POST /api/v1/tasks/{id}/archive
68
+ POST /api/v1/tasks/{id}/assign
69
+ ```
70
+
71
+ ### Naming Conventions
72
+
73
+ | Rule | Good | Bad |
74
+ |------|------|-----|
75
+ | Plural nouns | `/tasks` | `/task`, `/getTask` |
76
+ | Lowercase, hyphens | `/user-profiles` | `/userProfiles`, `/user_profiles` |
77
+ | No verbs in URL | `POST /tasks` | `/createTask` |
78
+ | No trailing slash | `/tasks` | `/tasks/` |
79
+ | Consistent casing | `userId` | `user_id` in JSON |
80
+
81
+ ### Query Parameters
82
+
83
+ ```
84
+ # Filtering
85
+ GET /tasks?status=active&assignee_id=123
86
+
87
+ # Sorting
88
+ GET /tasks?sort=created_at:desc,title:asc
89
+
90
+ # Pagination (cursor-based preferred)
91
+ GET /tasks?cursor=eyJpZCI6MTIzfQ&limit=20
92
+
93
+ # Pagination (offset-based)
94
+ GET /tasks?page=2&per_page=20
95
+
96
+ # Field selection
97
+ GET /tasks?fields=id,title,status
98
+
99
+ # Expansion/embedding
100
+ GET /tasks?expand=assignee,project
101
+ ```
102
+
103
+ ### HTTP Methods & Status Codes
104
+
105
+ | Method | Success | Created | No Content | Client Error | Not Found |
106
+ |--------|---------|---------|------------|--------------|-----------|
107
+ | GET | 200 | - | - | 400 | 404 |
108
+ | POST | - | 201 | - | 400, 422 | - |
109
+ | PUT | 200 | 201 | 204 | 400, 422 | 404 |
110
+ | PATCH | 200 | - | 204 | 400, 422 | 404 |
111
+ | DELETE | - | - | 204 | 400 | 404 |
112
+
113
+ ### Response Format
114
+
115
+ ```json
116
+ // Success (single resource)
117
+ {
118
+ "data": {
119
+ "id": "123",
120
+ "type": "task",
121
+ "attributes": {
122
+ "title": "Fix bug",
123
+ "status": "active"
124
+ },
125
+ "relationships": {
126
+ "assignee": { "id": "456", "type": "user" }
127
+ }
128
+ }
129
+ }
130
+
131
+ // Success (collection)
132
+ {
133
+ "data": [...],
134
+ "meta": {
135
+ "total": 100,
136
+ "page": 1,
137
+ "per_page": 20
138
+ },
139
+ "links": {
140
+ "next": "/tasks?cursor=abc",
141
+ "prev": null
142
+ }
143
+ }
144
+
145
+ // Error
146
+ {
147
+ "error": {
148
+ "code": "VALIDATION_ERROR",
149
+ "message": "Validation failed",
150
+ "details": [
151
+ { "field": "title", "message": "is required" },
152
+ { "field": "due_date", "message": "must be in future" }
153
+ ]
154
+ }
155
+ }
156
+ ```
157
+
158
+ ### Error Codes
159
+
160
+ | HTTP | Code | When |
161
+ |------|------|------|
162
+ | 400 | `BAD_REQUEST` | Malformed JSON, missing required params |
163
+ | 401 | `UNAUTHORIZED` | Missing or invalid auth token |
164
+ | 403 | `FORBIDDEN` | Valid auth but no permission |
165
+ | 404 | `NOT_FOUND` | Resource doesn't exist |
166
+ | 409 | `CONFLICT` | Duplicate, version conflict |
167
+ | 422 | `VALIDATION_ERROR` | Business rule violation |
168
+ | 429 | `RATE_LIMITED` | Too many requests |
169
+ | 500 | `INTERNAL_ERROR` | Server error (log, don't expose details) |
170
+
171
+ ---
172
+
173
+ ## Versioning Strategy
174
+
175
+ ### URL Versioning (Recommended)
176
+
177
+ ```
178
+ /api/v1/tasks
179
+ /api/v2/tasks
180
+ ```
181
+
182
+ **Pros:** Clear, cacheable, easy routing
183
+ **Cons:** URL changes on version bump
184
+
185
+ ### Header Versioning
186
+
187
+ ```
188
+ GET /api/tasks
189
+ Accept: application/vnd.api+json; version=2
190
+ ```
191
+
192
+ **Pros:** Clean URLs
193
+ **Cons:** Harder to test, cache
194
+
195
+ ### Version Lifecycle
196
+
197
+ | Status | Meaning | Support |
198
+ |--------|---------|---------|
199
+ | `current` | Latest stable | Full support |
200
+ | `deprecated` | Being phased out | 6-12 months |
201
+ | `sunset` | Removal scheduled | Returns 410 Gone |
202
+
203
+ ### Breaking vs Non-Breaking Changes
204
+
205
+ | Non-Breaking (OK) | Breaking (New Version) |
206
+ |-------------------|------------------------|
207
+ | Add optional field | Remove field |
208
+ | Add new endpoint | Change field type |
209
+ | Add optional param | Rename field |
210
+ | Expand enum values | Change URL structure |
211
+
212
+ ---
213
+
214
+ ## Authentication & Authorization
215
+
216
+ ### Auth Methods
217
+
218
+ | Method | Use For | Header |
219
+ |--------|---------|--------|
220
+ | Bearer Token (JWT) | User sessions, mobile | `Authorization: Bearer <token>` |
221
+ | API Key | Service-to-service, public APIs | `X-API-Key: <key>` |
222
+ | OAuth 2.0 | Third-party integrations | OAuth flow |
223
+ | mTLS | High-security service mesh | Certificate |
224
+
225
+ ### Authorization Patterns
226
+
227
+ ```yaml
228
+ # Resource-based
229
+ GET /tasks/{id} # Check: user can read task
230
+
231
+ # Scope-based (OAuth)
232
+ Authorization: Bearer <token>
233
+ # Token has scopes: ["tasks:read", "tasks:write"]
234
+
235
+ # Role-based
236
+ # Admin: all operations
237
+ # User: own tasks only
238
+ # Viewer: read-only
239
+ ```
240
+
241
+ ---
242
+
243
+ ## GraphQL Design
244
+
245
+ ### Schema Structure
246
+
247
+ ```graphql
248
+ type Query {
249
+ task(id: ID!): Task
250
+ tasks(filter: TaskFilter, pagination: Pagination): TaskConnection!
251
+ }
252
+
253
+ type Mutation {
254
+ createTask(input: CreateTaskInput!): TaskPayload!
255
+ updateTask(id: ID!, input: UpdateTaskInput!): TaskPayload!
256
+ deleteTask(id: ID!): DeletePayload!
257
+ }
258
+
259
+ type Subscription {
260
+ taskUpdated(projectId: ID!): Task!
261
+ }
262
+
263
+ type Task {
264
+ id: ID!
265
+ title: String!
266
+ status: TaskStatus!
267
+ assignee: User
268
+ project: Project!
269
+ createdAt: DateTime!
270
+ }
271
+
272
+ input CreateTaskInput {
273
+ title: String!
274
+ projectId: ID!
275
+ assigneeId: ID
276
+ }
277
+
278
+ type TaskPayload {
279
+ task: Task
280
+ errors: [UserError!]
281
+ }
282
+
283
+ type UserError {
284
+ field: String
285
+ message: String!
286
+ }
287
+ ```
288
+
289
+ ### GraphQL Best Practices
290
+
291
+ | Practice | Example |
292
+ |----------|---------|
293
+ | Nullable by default | `assignee: User` (nullable) |
294
+ | Non-null when guaranteed | `id: ID!`, `createdAt: DateTime!` |
295
+ | Input types for mutations | `input CreateTaskInput` |
296
+ | Payload types with errors | `TaskPayload { task, errors }` |
297
+ | Connection pattern for lists | `TaskConnection { edges, pageInfo }` |
298
+ | Use enums | `enum TaskStatus { TODO, IN_PROGRESS, DONE }` |
299
+
300
+ ---
301
+
302
+ ## gRPC Design
303
+
304
+ ### Proto File Structure
305
+
306
+ ```protobuf
307
+ syntax = "proto3";
308
+
309
+ package tasks.v1;
310
+
311
+ option go_package = "github.com/org/project/gen/tasks/v1";
312
+
313
+ service TaskService {
314
+ rpc GetTask(GetTaskRequest) returns (Task);
315
+ rpc ListTasks(ListTasksRequest) returns (ListTasksResponse);
316
+ rpc CreateTask(CreateTaskRequest) returns (Task);
317
+ rpc UpdateTask(UpdateTaskRequest) returns (Task);
318
+ rpc DeleteTask(DeleteTaskRequest) returns (google.protobuf.Empty);
319
+
320
+ // Streaming
321
+ rpc WatchTasks(WatchTasksRequest) returns (stream Task);
322
+ }
323
+
324
+ message Task {
325
+ string id = 1;
326
+ string title = 2;
327
+ TaskStatus status = 3;
328
+ optional string assignee_id = 4;
329
+ google.protobuf.Timestamp created_at = 5;
330
+ }
331
+
332
+ enum TaskStatus {
333
+ TASK_STATUS_UNSPECIFIED = 0;
334
+ TASK_STATUS_TODO = 1;
335
+ TASK_STATUS_IN_PROGRESS = 2;
336
+ TASK_STATUS_DONE = 3;
337
+ }
338
+
339
+ message ListTasksRequest {
340
+ int32 page_size = 1;
341
+ string page_token = 2;
342
+ string filter = 3; // CEL expression
343
+ }
344
+
345
+ message ListTasksResponse {
346
+ repeated Task tasks = 1;
347
+ string next_page_token = 2;
348
+ }
349
+ ```
350
+
351
+ ### gRPC Best Practices
352
+
353
+ | Practice | Why |
354
+ |----------|-----|
355
+ | Prefix enums with type name | Avoid conflicts: `TASK_STATUS_TODO` |
356
+ | Use `UNSPECIFIED = 0` | Default value detection |
357
+ | Use `optional` for nullable | Distinguish null vs default |
358
+ | Package versioning | `package tasks.v1` |
359
+ | Pagination with tokens | Stateless, efficient |
360
+
361
+ ---
362
+
363
+ ## OpenAPI Specification
364
+
365
+ ### Minimal Example
366
+
367
+ ```yaml
368
+ openapi: 3.1.0
369
+ info:
370
+ title: Tasks API
371
+ version: 1.0.0
372
+
373
+ servers:
374
+ - url: https://api.example.com/v1
375
+
376
+ paths:
377
+ /tasks:
378
+ get:
379
+ summary: List tasks
380
+ operationId: listTasks
381
+ tags: [Tasks]
382
+ parameters:
383
+ - name: status
384
+ in: query
385
+ schema:
386
+ $ref: '#/components/schemas/TaskStatus'
387
+ - name: limit
388
+ in: query
389
+ schema:
390
+ type: integer
391
+ default: 20
392
+ maximum: 100
393
+ responses:
394
+ '200':
395
+ description: Success
396
+ content:
397
+ application/json:
398
+ schema:
399
+ $ref: '#/components/schemas/TaskList'
400
+ post:
401
+ summary: Create task
402
+ operationId: createTask
403
+ tags: [Tasks]
404
+ requestBody:
405
+ required: true
406
+ content:
407
+ application/json:
408
+ schema:
409
+ $ref: '#/components/schemas/CreateTaskRequest'
410
+ responses:
411
+ '201':
412
+ description: Created
413
+ content:
414
+ application/json:
415
+ schema:
416
+ $ref: '#/components/schemas/Task'
417
+ '422':
418
+ $ref: '#/components/responses/ValidationError'
419
+
420
+ components:
421
+ schemas:
422
+ Task:
423
+ type: object
424
+ required: [id, title, status, createdAt]
425
+ properties:
426
+ id:
427
+ type: string
428
+ format: uuid
429
+ title:
430
+ type: string
431
+ maxLength: 255
432
+ status:
433
+ $ref: '#/components/schemas/TaskStatus'
434
+ createdAt:
435
+ type: string
436
+ format: date-time
437
+
438
+ TaskStatus:
439
+ type: string
440
+ enum: [todo, in_progress, done]
441
+
442
+ CreateTaskRequest:
443
+ type: object
444
+ required: [title]
445
+ properties:
446
+ title:
447
+ type: string
448
+ minLength: 1
449
+ maxLength: 255
450
+ assigneeId:
451
+ type: string
452
+ format: uuid
453
+
454
+ responses:
455
+ ValidationError:
456
+ description: Validation failed
457
+ content:
458
+ application/json:
459
+ schema:
460
+ $ref: '#/components/schemas/Error'
461
+
462
+ securitySchemes:
463
+ bearerAuth:
464
+ type: http
465
+ scheme: bearer
466
+ bearerFormat: JWT
467
+
468
+ security:
469
+ - bearerAuth: []
470
+ ```
471
+
472
+ ---
473
+
474
+ ## Rate Limiting
475
+
476
+ ### Headers
477
+
478
+ ```
479
+ X-RateLimit-Limit: 1000
480
+ X-RateLimit-Remaining: 999
481
+ X-RateLimit-Reset: 1640000000
482
+ Retry-After: 60
483
+ ```
484
+
485
+ ### Response (429)
486
+
487
+ ```json
488
+ {
489
+ "error": {
490
+ "code": "RATE_LIMITED",
491
+ "message": "Too many requests",
492
+ "retry_after": 60
493
+ }
494
+ }
495
+ ```
496
+
497
+ ---
498
+
499
+ ## Validation Checklist
500
+
501
+ Before completing API design:
502
+
503
+ - [ ] URLs follow RESTful conventions
504
+ - [ ] HTTP methods used correctly
505
+ - [ ] Status codes are appropriate
506
+ - [ ] Error responses are consistent
507
+ - [ ] Pagination implemented (cursor preferred)
508
+ - [ ] Versioning strategy defined
509
+ - [ ] Authentication documented
510
+ - [ ] Rate limiting defined
511
+ - [ ] OpenAPI spec complete
512
+ - [ ] Examples for all endpoints
513
+ - [ ] Breaking changes identified
514
+
515
+ ---
516
+
517
+ ## Output
518
+
519
+ - OpenAPI: `docs/architecture/{module}/api/{resource}.yaml`
520
+ - GraphQL: `docs/architecture/{module}/api/schema.graphql`
521
+ - gRPC: `proto/{service}/v1/{service}.proto`
522
+
523
+ ## Related Skills
524
+
525
+ - `architecture-design` — API is part of architecture
526
+ - `unit-writing` — API specs in api/ folder
527
+ - `adr-writing` — Document API decisions