@torus-engineering/tas-kit 1.5.0 → 1.6.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 (111) hide show
  1. package/.claude/agents/README.md +83 -0
  2. package/.claude/agents/architect.md +53 -0
  3. package/.claude/agents/aws-reviewer.md +71 -0
  4. package/.claude/agents/build-resolver.md +59 -0
  5. package/.claude/agents/code-architect.md +62 -0
  6. package/.claude/agents/code-explorer.md +63 -0
  7. package/.claude/agents/code-simplifier.md +53 -0
  8. package/.claude/agents/comment-analyzer.md +59 -0
  9. package/.claude/agents/conversation-analyzer.md +57 -0
  10. package/.claude/agents/csharp-reviewer.md +62 -0
  11. package/.claude/agents/database-reviewer.md +73 -0
  12. package/.claude/agents/doc-updater.md +66 -0
  13. package/.claude/agents/docs-lookup.md +55 -0
  14. package/.claude/agents/e2e-runner.md +61 -0
  15. package/.claude/agents/harness-optimizer.md +62 -0
  16. package/.claude/agents/loop-operator.md +56 -0
  17. package/.claude/agents/performance-optimizer.md +78 -0
  18. package/.claude/agents/planner.md +82 -0
  19. package/.claude/agents/pr-test-analyzer.md +68 -0
  20. package/.claude/agents/python-reviewer.md +67 -0
  21. package/.claude/agents/pytorch-build-resolver.md +76 -0
  22. package/.claude/agents/refactor-cleaner.md +70 -0
  23. package/.claude/agents/security-reviewer.md +79 -0
  24. package/.claude/agents/seo-specialist.md +75 -0
  25. package/.claude/agents/silent-failure-hunter.md +69 -0
  26. package/.claude/agents/tdd-guide.md +84 -0
  27. package/.claude/agents/type-design-analyzer.md +75 -0
  28. package/.claude/agents/typescript-reviewer.md +65 -0
  29. package/.claude/commands/ado-create.md +2 -1
  30. package/.claude/commands/ado-delete.md +3 -2
  31. package/.claude/commands/ado-get.md +2 -1
  32. package/.claude/commands/ado-status.md +2 -1
  33. package/.claude/commands/ado-update.md +2 -1
  34. package/.claude/commands/tas-adr.md +13 -12
  35. package/.claude/commands/tas-bug.md +97 -50
  36. package/.claude/commands/tas-design.md +3 -1
  37. package/.claude/commands/tas-dev.md +115 -0
  38. package/.claude/commands/tas-epic.md +4 -2
  39. package/.claude/commands/tas-feature.md +5 -3
  40. package/.claude/commands/tas-fix.md +47 -0
  41. package/.claude/commands/tas-plan.md +184 -0
  42. package/.claude/commands/tas-prd.md +3 -1
  43. package/.claude/commands/tas-review.md +104 -0
  44. package/.claude/commands/tas-sad.md +3 -1
  45. package/.claude/commands/tas-security.md +80 -0
  46. package/.claude/commands/tas-spec.md +50 -0
  47. package/.claude/commands/tas-story.md +77 -40
  48. package/.claude/commands/tas-verify.md +8 -0
  49. package/.claude/hooks/code-quality.js +127 -0
  50. package/.claude/hooks/session-end.js +116 -0
  51. package/.claude/rules/.gitkeep +0 -0
  52. package/.claude/rules/common/agents.md +65 -0
  53. package/.claude/rules/common/code-review.md +124 -0
  54. package/.claude/rules/common/coding-style.md +90 -0
  55. package/.claude/rules/common/development-workflow.md +44 -0
  56. package/.claude/rules/common/git-workflow.md +24 -0
  57. package/.claude/rules/common/hooks.md +30 -0
  58. package/.claude/rules/common/patterns.md +31 -0
  59. package/.claude/rules/common/performance.md +55 -0
  60. package/.claude/rules/common/post-review-agent.md +39 -0
  61. package/.claude/rules/common/project-status.md +80 -0
  62. package/.claude/rules/common/security.md +29 -0
  63. package/.claude/rules/common/stack-detection.md +29 -0
  64. package/.claude/rules/common/testing.md +57 -0
  65. package/.claude/rules/csharp/coding-style.md +72 -0
  66. package/.claude/rules/csharp/hooks.md +25 -0
  67. package/.claude/rules/csharp/patterns.md +50 -0
  68. package/.claude/rules/csharp/security.md +58 -0
  69. package/.claude/rules/csharp/testing.md +46 -0
  70. package/.claude/rules/python/coding-style.md +42 -0
  71. package/.claude/rules/python/hooks.md +19 -0
  72. package/.claude/rules/python/patterns.md +39 -0
  73. package/.claude/rules/python/security.md +30 -0
  74. package/.claude/rules/python/testing.md +38 -0
  75. package/.claude/rules/typescript/coding-style.md +199 -0
  76. package/.claude/rules/typescript/hooks.md +22 -0
  77. package/.claude/rules/typescript/patterns.md +52 -0
  78. package/.claude/rules/typescript/security.md +28 -0
  79. package/.claude/rules/typescript/testing.md +18 -0
  80. package/.claude/rules/web/coding-style.md +96 -0
  81. package/.claude/rules/web/design-quality.md +63 -0
  82. package/.claude/rules/web/hooks.md +120 -0
  83. package/.claude/rules/web/patterns.md +79 -0
  84. package/.claude/rules/web/performance.md +64 -0
  85. package/.claude/rules/web/security.md +57 -0
  86. package/.claude/rules/web/testing.md +55 -0
  87. package/.claude/settings.json +37 -0
  88. package/.claude/settings.local.json +38 -0
  89. package/.claude/skills/ado-integration/SKILL.md +44 -1
  90. package/.claude/skills/agent-harness-construction/SKILL.md +77 -0
  91. package/.claude/skills/agent-introspection-debugging/SKILL.md +157 -0
  92. package/.claude/skills/ai-regression-testing/SKILL.md +364 -0
  93. package/.claude/skills/api-design/SKILL.md +528 -0
  94. package/.claude/skills/architecture-decision-records/SKILL.md +184 -0
  95. package/.claude/skills/backend-patterns/SKILL.md +602 -0
  96. package/.claude/skills/benchmark/SKILL.md +98 -0
  97. package/.claude/skills/browser-qa/SKILL.md +92 -0
  98. package/.claude/skills/canary-watch/SKILL.md +104 -0
  99. package/.claude/skills/tas-conventions/SKILL.md +51 -3
  100. package/.claude/skills/tas-implementation-complete/SKILL.md +97 -0
  101. package/.claude/skills/tas-tdd/SKILL.md +72 -16
  102. package/.tas/README.md +29 -24
  103. package/.tas/tas-example.yaml +2 -1
  104. package/.tas/templates/Story.md +18 -18
  105. package/CLAUDE-Example.md +1 -1
  106. package/README.md +23 -8
  107. package/bin/cli.js +4 -4
  108. package/package.json +1 -1
  109. package/.claude/commands/tas-dev-story.md +0 -61
  110. package/.claude/commands/tas-review-code.md +0 -42
  111. package/.claude/commands/tas-security-check.md +0 -30
@@ -0,0 +1,528 @@
1
+ ---
2
+ name: api-design
3
+ description: |
4
+ Auto-invoke when designing new REST API endpoints, reviewing existing API contracts,
5
+ planning pagination or filtering strategy, implementing error response formats,
6
+ adding API versioning, or building public/partner-facing APIs.
7
+ NOT for backend implementation layers (use backend-patterns instead).
8
+ origin: ECC
9
+ allowed-tools: Read, Grep, Glob
10
+ ---
11
+
12
+ # API Design Patterns
13
+
14
+ Conventions and best practices for designing consistent, developer-friendly REST APIs.
15
+
16
+ ## When to Activate
17
+
18
+ - Designing new API endpoints
19
+ - Reviewing existing API contracts
20
+ - Adding pagination, filtering, or sorting
21
+ - Implementing error handling for APIs
22
+ - Planning API versioning strategy
23
+ - Building public or partner-facing APIs
24
+
25
+ ## Resource Design
26
+
27
+ ### URL Structure
28
+
29
+ ```
30
+ # Resources are nouns, plural, lowercase, kebab-case
31
+ GET /api/v1/users
32
+ GET /api/v1/users/:id
33
+ POST /api/v1/users
34
+ PUT /api/v1/users/:id
35
+ PATCH /api/v1/users/:id
36
+ DELETE /api/v1/users/:id
37
+
38
+ # Sub-resources for relationships
39
+ GET /api/v1/users/:id/orders
40
+ POST /api/v1/users/:id/orders
41
+
42
+ # Actions that don't map to CRUD (use verbs sparingly)
43
+ POST /api/v1/orders/:id/cancel
44
+ POST /api/v1/auth/login
45
+ POST /api/v1/auth/refresh
46
+ ```
47
+
48
+ ### Naming Rules
49
+
50
+ ```
51
+ # GOOD
52
+ /api/v1/team-members # kebab-case for multi-word resources
53
+ /api/v1/orders?status=active # query params for filtering
54
+ /api/v1/users/123/orders # nested resources for ownership
55
+
56
+ # BAD
57
+ /api/v1/getUsers # verb in URL
58
+ /api/v1/user # singular (use plural)
59
+ /api/v1/team_members # snake_case in URLs
60
+ /api/v1/users/123/getOrders # verb in nested resource
61
+ ```
62
+
63
+ ## HTTP Methods and Status Codes
64
+
65
+ ### Method Semantics
66
+
67
+ | Method | Idempotent | Safe | Use For |
68
+ |--------|-----------|------|---------|
69
+ | GET | Yes | Yes | Retrieve resources |
70
+ | POST | No | No | Create resources, trigger actions |
71
+ | PUT | Yes | No | Full replacement of a resource |
72
+ | PATCH | No* | No | Partial update of a resource |
73
+ | DELETE | Yes | No | Remove a resource |
74
+
75
+ *PATCH can be made idempotent with proper implementation
76
+
77
+ ### Status Code Reference
78
+
79
+ ```
80
+ # Success
81
+ 200 OK — GET, PUT, PATCH (with response body)
82
+ 201 Created — POST (include Location header)
83
+ 204 No Content — DELETE, PUT (no response body)
84
+
85
+ # Client Errors
86
+ 400 Bad Request — Validation failure, malformed JSON
87
+ 401 Unauthorized — Missing or invalid authentication
88
+ 403 Forbidden — Authenticated but not authorized
89
+ 404 Not Found — Resource doesn't exist
90
+ 409 Conflict — Duplicate entry, state conflict
91
+ 422 Unprocessable Entity — Semantically invalid (valid JSON, bad data)
92
+ 429 Too Many Requests — Rate limit exceeded
93
+
94
+ # Server Errors
95
+ 500 Internal Server Error — Unexpected failure (never expose details)
96
+ 502 Bad Gateway — Upstream service failed
97
+ 503 Service Unavailable — Temporary overload, include Retry-After
98
+ ```
99
+
100
+ ### Common Mistakes
101
+
102
+ ```
103
+ # BAD: 200 for everything
104
+ { "status": 200, "success": false, "error": "Not found" }
105
+
106
+ # GOOD: Use HTTP status codes semantically
107
+ HTTP/1.1 404 Not Found
108
+ { "error": { "code": "not_found", "message": "User not found" } }
109
+
110
+ # BAD: 500 for validation errors
111
+ # GOOD: 400 or 422 with field-level details
112
+
113
+ # BAD: 200 for created resources
114
+ # GOOD: 201 with Location header
115
+ HTTP/1.1 201 Created
116
+ Location: /api/v1/users/abc-123
117
+ ```
118
+
119
+ ## Response Format
120
+
121
+ ### Success Response
122
+
123
+ ```json
124
+ {
125
+ "data": {
126
+ "id": "abc-123",
127
+ "email": "alice@example.com",
128
+ "name": "Alice",
129
+ "created_at": "2025-01-15T10:30:00Z"
130
+ }
131
+ }
132
+ ```
133
+
134
+ ### Collection Response (with Pagination)
135
+
136
+ ```json
137
+ {
138
+ "data": [
139
+ { "id": "abc-123", "name": "Alice" },
140
+ { "id": "def-456", "name": "Bob" }
141
+ ],
142
+ "meta": {
143
+ "total": 142,
144
+ "page": 1,
145
+ "per_page": 20,
146
+ "total_pages": 8
147
+ },
148
+ "links": {
149
+ "self": "/api/v1/users?page=1&per_page=20",
150
+ "next": "/api/v1/users?page=2&per_page=20",
151
+ "last": "/api/v1/users?page=8&per_page=20"
152
+ }
153
+ }
154
+ ```
155
+
156
+ ### Error Response
157
+
158
+ ```json
159
+ {
160
+ "error": {
161
+ "code": "validation_error",
162
+ "message": "Request validation failed",
163
+ "details": [
164
+ {
165
+ "field": "email",
166
+ "message": "Must be a valid email address",
167
+ "code": "invalid_format"
168
+ },
169
+ {
170
+ "field": "age",
171
+ "message": "Must be between 0 and 150",
172
+ "code": "out_of_range"
173
+ }
174
+ ]
175
+ }
176
+ }
177
+ ```
178
+
179
+ ### Response Envelope Variants
180
+
181
+ ```typescript
182
+ // Option A: Envelope with data wrapper (recommended for public APIs)
183
+ interface ApiResponse<T> {
184
+ data: T;
185
+ meta?: PaginationMeta;
186
+ links?: PaginationLinks;
187
+ }
188
+
189
+ interface ApiError {
190
+ error: {
191
+ code: string;
192
+ message: string;
193
+ details?: FieldError[];
194
+ };
195
+ }
196
+
197
+ // Option B: Flat response (simpler, common for internal APIs)
198
+ // Success: just return the resource directly
199
+ // Error: return error object
200
+ // Distinguish by HTTP status code
201
+ ```
202
+
203
+ ## Pagination
204
+
205
+ ### Offset-Based (Simple)
206
+
207
+ ```
208
+ GET /api/v1/users?page=2&per_page=20
209
+
210
+ # Implementation
211
+ SELECT * FROM users
212
+ ORDER BY created_at DESC
213
+ LIMIT 20 OFFSET 20;
214
+ ```
215
+
216
+ **Pros:** Easy to implement, supports "jump to page N"
217
+ **Cons:** Slow on large offsets (OFFSET 100000), inconsistent with concurrent inserts
218
+
219
+ ### Cursor-Based (Scalable)
220
+
221
+ ```
222
+ GET /api/v1/users?cursor=eyJpZCI6MTIzfQ&limit=20
223
+
224
+ # Implementation
225
+ SELECT * FROM users
226
+ WHERE id > :cursor_id
227
+ ORDER BY id ASC
228
+ LIMIT 21; -- fetch one extra to determine has_next
229
+ ```
230
+
231
+ ```json
232
+ {
233
+ "data": [...],
234
+ "meta": {
235
+ "has_next": true,
236
+ "next_cursor": "eyJpZCI6MTQzfQ"
237
+ }
238
+ }
239
+ ```
240
+
241
+ **Pros:** Consistent performance regardless of position, stable with concurrent inserts
242
+ **Cons:** Cannot jump to arbitrary page, cursor is opaque
243
+
244
+ ### When to Use Which
245
+
246
+ | Use Case | Pagination Type |
247
+ |----------|----------------|
248
+ | Admin dashboards, small datasets (<10K) | Offset |
249
+ | Infinite scroll, feeds, large datasets | Cursor |
250
+ | Public APIs | Cursor (default) with offset (optional) |
251
+ | Search results | Offset (users expect page numbers) |
252
+
253
+ ## Filtering, Sorting, and Search
254
+
255
+ ### Filtering
256
+
257
+ ```
258
+ # Simple equality
259
+ GET /api/v1/orders?status=active&customer_id=abc-123
260
+
261
+ # Comparison operators (use bracket notation)
262
+ GET /api/v1/products?price[gte]=10&price[lte]=100
263
+ GET /api/v1/orders?created_at[after]=2025-01-01
264
+
265
+ # Multiple values (comma-separated)
266
+ GET /api/v1/products?category=electronics,clothing
267
+
268
+ # Nested fields (dot notation)
269
+ GET /api/v1/orders?customer.country=US
270
+ ```
271
+
272
+ ### Sorting
273
+
274
+ ```
275
+ # Single field (prefix - for descending)
276
+ GET /api/v1/products?sort=-created_at
277
+
278
+ # Multiple fields (comma-separated)
279
+ GET /api/v1/products?sort=-featured,price,-created_at
280
+ ```
281
+
282
+ ### Full-Text Search
283
+
284
+ ```
285
+ # Search query parameter
286
+ GET /api/v1/products?q=wireless+headphones
287
+
288
+ # Field-specific search
289
+ GET /api/v1/users?email=alice
290
+ ```
291
+
292
+ ### Sparse Fieldsets
293
+
294
+ ```
295
+ # Return only specified fields (reduces payload)
296
+ GET /api/v1/users?fields=id,name,email
297
+ GET /api/v1/orders?fields=id,total,status&include=customer.name
298
+ ```
299
+
300
+ ## Authentication and Authorization
301
+
302
+ ### Token-Based Auth
303
+
304
+ ```
305
+ # Bearer token in Authorization header
306
+ GET /api/v1/users
307
+ Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
308
+
309
+ # API key (for server-to-server)
310
+ GET /api/v1/data
311
+ X-API-Key: sk_live_abc123
312
+ ```
313
+
314
+ ### Authorization Patterns
315
+
316
+ ```typescript
317
+ // Resource-level: check ownership
318
+ app.get("/api/v1/orders/:id", async (req, res) => {
319
+ const order = await Order.findById(req.params.id);
320
+ if (!order) return res.status(404).json({ error: { code: "not_found" } });
321
+ if (order.userId !== req.user.id) return res.status(403).json({ error: { code: "forbidden" } });
322
+ return res.json({ data: order });
323
+ });
324
+
325
+ // Role-based: check permissions
326
+ app.delete("/api/v1/users/:id", requireRole("admin"), async (req, res) => {
327
+ await User.delete(req.params.id);
328
+ return res.status(204).send();
329
+ });
330
+ ```
331
+
332
+ ## Rate Limiting
333
+
334
+ ### Headers
335
+
336
+ ```
337
+ HTTP/1.1 200 OK
338
+ X-RateLimit-Limit: 100
339
+ X-RateLimit-Remaining: 95
340
+ X-RateLimit-Reset: 1640000000
341
+
342
+ # When exceeded
343
+ HTTP/1.1 429 Too Many Requests
344
+ Retry-After: 60
345
+ {
346
+ "error": {
347
+ "code": "rate_limit_exceeded",
348
+ "message": "Rate limit exceeded. Try again in 60 seconds."
349
+ }
350
+ }
351
+ ```
352
+
353
+ ### Rate Limit Tiers
354
+
355
+ | Tier | Limit | Window | Use Case |
356
+ |------|-------|--------|----------|
357
+ | Anonymous | 30/min | Per IP | Public endpoints |
358
+ | Authenticated | 100/min | Per user | Standard API access |
359
+ | Premium | 1000/min | Per API key | Paid API plans |
360
+ | Internal | 10000/min | Per service | Service-to-service |
361
+
362
+ ## Versioning
363
+
364
+ ### URL Path Versioning (Recommended)
365
+
366
+ ```
367
+ /api/v1/users
368
+ /api/v2/users
369
+ ```
370
+
371
+ **Pros:** Explicit, easy to route, cacheable
372
+ **Cons:** URL changes between versions
373
+
374
+ ### Header Versioning
375
+
376
+ ```
377
+ GET /api/users
378
+ Accept: application/vnd.myapp.v2+json
379
+ ```
380
+
381
+ **Pros:** Clean URLs
382
+ **Cons:** Harder to test, easy to forget
383
+
384
+ ### Versioning Strategy
385
+
386
+ ```
387
+ 1. Start with /api/v1/ — don't version until you need to
388
+ 2. Maintain at most 2 active versions (current + previous)
389
+ 3. Deprecation timeline:
390
+ - Announce deprecation (6 months notice for public APIs)
391
+ - Add Sunset header: Sunset: Sat, 01 Jan 2026 00:00:00 GMT
392
+ - Return 410 Gone after sunset date
393
+ 4. Non-breaking changes don't need a new version:
394
+ - Adding new fields to responses
395
+ - Adding new optional query parameters
396
+ - Adding new endpoints
397
+ 5. Breaking changes require a new version:
398
+ - Removing or renaming fields
399
+ - Changing field types
400
+ - Changing URL structure
401
+ - Changing authentication method
402
+ ```
403
+
404
+ ## Implementation Patterns
405
+
406
+ ### TypeScript (Next.js API Route)
407
+
408
+ ```typescript
409
+ import { z } from "zod";
410
+ import { NextRequest, NextResponse } from "next/server";
411
+
412
+ const createUserSchema = z.object({
413
+ email: z.string().email(),
414
+ name: z.string().min(1).max(100),
415
+ });
416
+
417
+ export async function POST(req: NextRequest) {
418
+ const body = await req.json();
419
+ const parsed = createUserSchema.safeParse(body);
420
+
421
+ if (!parsed.success) {
422
+ return NextResponse.json({
423
+ error: {
424
+ code: "validation_error",
425
+ message: "Request validation failed",
426
+ details: parsed.error.issues.map(i => ({
427
+ field: i.path.join("."),
428
+ message: i.message,
429
+ code: i.code,
430
+ })),
431
+ },
432
+ }, { status: 422 });
433
+ }
434
+
435
+ const user = await createUser(parsed.data);
436
+
437
+ return NextResponse.json(
438
+ { data: user },
439
+ {
440
+ status: 201,
441
+ headers: { Location: `/api/v1/users/${user.id}` },
442
+ },
443
+ );
444
+ }
445
+ ```
446
+
447
+ ### Python (Django REST Framework)
448
+
449
+ ```python
450
+ from rest_framework import serializers, viewsets, status
451
+ from rest_framework.response import Response
452
+
453
+ class CreateUserSerializer(serializers.Serializer):
454
+ email = serializers.EmailField()
455
+ name = serializers.CharField(max_length=100)
456
+
457
+ class UserSerializer(serializers.ModelSerializer):
458
+ class Meta:
459
+ model = User
460
+ fields = ["id", "email", "name", "created_at"]
461
+
462
+ class UserViewSet(viewsets.ModelViewSet):
463
+ serializer_class = UserSerializer
464
+ permission_classes = [IsAuthenticated]
465
+
466
+ def get_serializer_class(self):
467
+ if self.action == "create":
468
+ return CreateUserSerializer
469
+ return UserSerializer
470
+
471
+ def create(self, request):
472
+ serializer = CreateUserSerializer(data=request.data)
473
+ serializer.is_valid(raise_exception=True)
474
+ user = UserService.create(**serializer.validated_data)
475
+ return Response(
476
+ {"data": UserSerializer(user).data},
477
+ status=status.HTTP_201_CREATED,
478
+ headers={"Location": f"/api/v1/users/{user.id}"},
479
+ )
480
+ ```
481
+
482
+ ### Go (net/http)
483
+
484
+ ```go
485
+ func (h *UserHandler) CreateUser(w http.ResponseWriter, r *http.Request) {
486
+ var req CreateUserRequest
487
+ if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
488
+ writeError(w, http.StatusBadRequest, "invalid_json", "Invalid request body")
489
+ return
490
+ }
491
+
492
+ if err := req.Validate(); err != nil {
493
+ writeError(w, http.StatusUnprocessableEntity, "validation_error", err.Error())
494
+ return
495
+ }
496
+
497
+ user, err := h.service.Create(r.Context(), req)
498
+ if err != nil {
499
+ switch {
500
+ case errors.Is(err, domain.ErrEmailTaken):
501
+ writeError(w, http.StatusConflict, "email_taken", "Email already registered")
502
+ default:
503
+ writeError(w, http.StatusInternalServerError, "internal_error", "Internal error")
504
+ }
505
+ return
506
+ }
507
+
508
+ w.Header().Set("Location", fmt.Sprintf("/api/v1/users/%s", user.ID))
509
+ writeJSON(w, http.StatusCreated, map[string]any{"data": user})
510
+ }
511
+ ```
512
+
513
+ ## API Design Checklist
514
+
515
+ Before shipping a new endpoint:
516
+
517
+ - [ ] Resource URL follows naming conventions (plural, kebab-case, no verbs)
518
+ - [ ] Correct HTTP method used (GET for reads, POST for creates, etc.)
519
+ - [ ] Appropriate status codes returned (not 200 for everything)
520
+ - [ ] Input validated with schema (Zod, Pydantic, Bean Validation)
521
+ - [ ] Error responses follow standard format with codes and messages
522
+ - [ ] Pagination implemented for list endpoints (cursor or offset)
523
+ - [ ] Authentication required (or explicitly marked as public)
524
+ - [ ] Authorization checked (user can only access their own resources)
525
+ - [ ] Rate limiting configured
526
+ - [ ] Response does not leak internal details (stack traces, SQL errors)
527
+ - [ ] Consistent naming with existing endpoints (camelCase vs snake_case)
528
+ - [ ] Documented (OpenAPI/Swagger spec updated)
@@ -0,0 +1,184 @@
1
+ ---
2
+ name: architecture-decision-records
3
+ description: |
4
+ Auto-invoke when user says "ADR this", "record this decision", "we decided to use X over Y",
5
+ or "the reason we're doing X instead of Y is...". Also when choosing between significant
6
+ alternatives (framework, database, pattern, API design) and reaching a conclusion.
7
+ When user asks "why did we choose X?" — read existing ADRs in docs/adr/.
8
+ origin: ECC
9
+ allowed-tools: Read, Write, Bash, Glob
10
+ ---
11
+
12
+ # Architecture Decision Records
13
+
14
+ Capture architectural decisions as they happen during coding sessions. Instead of decisions living only in Slack threads, PR comments, or someone's memory, this skill produces structured ADR documents that live alongside the code.
15
+
16
+ ## When to Activate
17
+
18
+ - User explicitly says "let's record this decision" or "ADR this"
19
+ - User chooses between significant alternatives (framework, library, pattern, database, API design)
20
+ - User says "we decided to..." or "the reason we're doing X instead of Y is..."
21
+ - User asks "why did we choose X?" (read existing ADRs)
22
+ - During planning phases when architectural trade-offs are discussed
23
+
24
+ ## ADR Format
25
+
26
+ Use the lightweight ADR format proposed by Michael Nygard, adapted for AI-assisted development:
27
+
28
+ ```markdown
29
+ # ADR-NNNN: [Decision Title]
30
+
31
+ **Date**: YYYY-MM-DD
32
+ **Status**: proposed | accepted | deprecated | superseded by ADR-NNNN
33
+ **Deciders**: [who was involved]
34
+
35
+ ## Context
36
+
37
+ What is the issue that we're seeing that is motivating this decision or change?
38
+
39
+ [2-5 sentences describing the situation, constraints, and forces at play]
40
+
41
+ ## Decision
42
+
43
+ What is the change that we're proposing and/or doing?
44
+
45
+ [1-3 sentences stating the decision clearly]
46
+
47
+ ## Alternatives Considered
48
+
49
+ ### Alternative 1: [Name]
50
+ - **Pros**: [benefits]
51
+ - **Cons**: [drawbacks]
52
+ - **Why not**: [specific reason this was rejected]
53
+
54
+ ### Alternative 2: [Name]
55
+ - **Pros**: [benefits]
56
+ - **Cons**: [drawbacks]
57
+ - **Why not**: [specific reason this was rejected]
58
+
59
+ ## Consequences
60
+
61
+ What becomes easier or more difficult to do because of this change?
62
+
63
+ ### Positive
64
+ - [benefit 1]
65
+ - [benefit 2]
66
+
67
+ ### Negative
68
+ - [trade-off 1]
69
+ - [trade-off 2]
70
+
71
+ ### Risks
72
+ - [risk and mitigation]
73
+ ```
74
+
75
+ ## Workflow
76
+
77
+ ### Capturing a New ADR
78
+
79
+ When a decision moment is detected:
80
+
81
+ 1. **Initialize (first time only)** — if `docs/adr/` does not exist, ask the user for confirmation before creating the directory, a `README.md` seeded with the index table header (see ADR Index Format below), and a blank `template.md` for manual use. Do not create files without explicit consent.
82
+ 2. **Identify the decision** — extract the core architectural choice being made
83
+ 3. **Gather context** — what problem prompted this? What constraints exist?
84
+ 4. **Document alternatives** — what other options were considered? Why were they rejected?
85
+ 5. **State consequences** — what are the trade-offs? What becomes easier/harder?
86
+ 6. **Assign a number** — scan existing ADRs in `docs/adr/` and increment
87
+ 7. **Confirm and write** — present the draft ADR to the user for review. Only write to `docs/adr/NNNN-decision-title.md` after explicit approval. If the user declines, discard the draft without writing any files.
88
+ 8. **Update the index** — append to `docs/adr/README.md`
89
+
90
+ ### Reading Existing ADRs
91
+
92
+ When a user asks "why did we choose X?":
93
+
94
+ 1. Check if `docs/adr/` exists — if not, respond: "No ADRs found in this project. Would you like to start recording architectural decisions?"
95
+ 2. If it exists, scan `docs/adr/README.md` index for relevant entries
96
+ 3. Read matching ADR files and present the Context and Decision sections
97
+ 4. If no match is found, respond: "No ADR found for that decision. Would you like to record one now?"
98
+
99
+ ### ADR Directory Structure
100
+
101
+ ```
102
+ docs/
103
+ └── adr/
104
+ ├── README.md ← index of all ADRs
105
+ ├── 0001-use-nextjs.md
106
+ ├── 0002-postgres-over-mongo.md
107
+ ├── 0003-rest-over-graphql.md
108
+ └── template.md ← blank template for manual use
109
+ ```
110
+
111
+ ### ADR Index Format
112
+
113
+ ```markdown
114
+ # Architecture Decision Records
115
+
116
+ | ADR | Title | Status | Date |
117
+ |-----|-------|--------|------|
118
+ | [0001](0001-use-nextjs.md) | Use Next.js as frontend framework | accepted | 2026-01-15 |
119
+ | [0002](0002-postgres-over-mongo.md) | PostgreSQL over MongoDB for primary datastore | accepted | 2026-01-20 |
120
+ | [0003](0003-rest-over-graphql.md) | REST API over GraphQL | accepted | 2026-02-01 |
121
+ ```
122
+
123
+ ## Decision Detection Signals
124
+
125
+ Watch for these patterns in conversation that indicate an architectural decision:
126
+
127
+ **Explicit signals**
128
+ - "Let's go with X"
129
+ - "We should use X instead of Y"
130
+ - "The trade-off is worth it because..."
131
+ - "Record this as an ADR"
132
+
133
+ **Implicit signals** (suggest recording an ADR — do not auto-create without user confirmation)
134
+ - Comparing two frameworks or libraries and reaching a conclusion
135
+ - Making a database schema design choice with stated rationale
136
+ - Choosing between architectural patterns (monolith vs microservices, REST vs GraphQL)
137
+ - Deciding on authentication/authorization strategy
138
+ - Selecting deployment infrastructure after evaluating alternatives
139
+
140
+ ## What Makes a Good ADR
141
+
142
+ ### Do
143
+ - **Be specific** — "Use Prisma ORM" not "use an ORM"
144
+ - **Record the why** — the rationale matters more than the what
145
+ - **Include rejected alternatives** — future developers need to know what was considered
146
+ - **State consequences honestly** — every decision has trade-offs
147
+ - **Keep it short** — an ADR should be readable in 2 minutes
148
+ - **Use present tense** — "We use X" not "We will use X"
149
+
150
+ ### Don't
151
+ - Record trivial decisions — variable naming or formatting choices don't need ADRs
152
+ - Write essays — if the context section exceeds 10 lines, it's too long
153
+ - Omit alternatives — "we just picked it" is not a valid rationale
154
+ - Backfill without marking it — if recording a past decision, note the original date
155
+ - Let ADRs go stale — superseded decisions should reference their replacement
156
+
157
+ ## ADR Lifecycle
158
+
159
+ ```
160
+ proposed → accepted → [deprecated | superseded by ADR-NNNN]
161
+ ```
162
+
163
+ - **proposed**: decision is under discussion, not yet committed
164
+ - **accepted**: decision is in effect and being followed
165
+ - **deprecated**: decision is no longer relevant (e.g., feature removed)
166
+ - **superseded**: a newer ADR replaces this one (always link the replacement)
167
+
168
+ ## Categories of Decisions Worth Recording
169
+
170
+ | Category | Examples |
171
+ |----------|---------|
172
+ | **Technology choices** | Framework, language, database, cloud provider |
173
+ | **Architecture patterns** | Monolith vs microservices, event-driven, CQRS |
174
+ | **API design** | REST vs GraphQL, versioning strategy, auth mechanism |
175
+ | **Data modeling** | Schema design, normalization decisions, caching strategy |
176
+ | **Infrastructure** | Deployment model, CI/CD pipeline, monitoring stack |
177
+ | **Security** | Auth strategy, encryption approach, secret management |
178
+ | **Testing** | Test framework, coverage targets, E2E vs integration balance |
179
+ | **Process** | Branching strategy, review process, release cadence |
180
+
181
+ ## Integration with Other Skills
182
+
183
+ - **Planner agent**: when the planner proposes architecture changes, suggest creating an ADR
184
+ - **Code reviewer agent**: flag PRs that introduce architectural changes without a corresponding ADR