@plazmodium/odin 0.3.3-beta → 0.3.4-beta

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 (73) hide show
  1. package/README.md +16 -10
  2. package/builtin/ODIN.md +1045 -0
  3. package/builtin/agent-definitions/README.md +170 -0
  4. package/builtin/agent-definitions/_shared-context.md +377 -0
  5. package/builtin/agent-definitions/architect.md +627 -0
  6. package/builtin/agent-definitions/builder.md +716 -0
  7. package/builtin/agent-definitions/discovery.md +293 -0
  8. package/builtin/agent-definitions/documenter.md +238 -0
  9. package/builtin/agent-definitions/guardian.md +1049 -0
  10. package/builtin/agent-definitions/integrator.md +363 -0
  11. package/builtin/agent-definitions/planning.md +236 -0
  12. package/builtin/agent-definitions/product.md +405 -0
  13. package/builtin/agent-definitions/release.md +430 -0
  14. package/builtin/agent-definitions/reviewer.md +447 -0
  15. package/builtin/agent-definitions/watcher.md +402 -0
  16. package/builtin/skills/api/graphql/SKILL.md +548 -0
  17. package/builtin/skills/api/grpc/SKILL.md +554 -0
  18. package/builtin/skills/api/rest-api/SKILL.md +469 -0
  19. package/builtin/skills/api/trpc/SKILL.md +503 -0
  20. package/builtin/skills/architecture/clean-architecture/SKILL.md +141 -0
  21. package/builtin/skills/architecture/domain-driven-design/SKILL.md +129 -0
  22. package/builtin/skills/architecture/event-driven/SKILL.md +145 -0
  23. package/builtin/skills/architecture/microservices/SKILL.md +143 -0
  24. package/builtin/skills/architecture/tla-precheck/SKILL.md +171 -0
  25. package/builtin/skills/backend/golang-gin/SKILL.md +141 -0
  26. package/builtin/skills/backend/nodejs-express/SKILL.md +277 -0
  27. package/builtin/skills/backend/nodejs-fastify/SKILL.md +152 -0
  28. package/builtin/skills/backend/python-django/SKILL.md +128 -0
  29. package/builtin/skills/backend/python-fastapi/SKILL.md +140 -0
  30. package/builtin/skills/database/mongodb/SKILL.md +132 -0
  31. package/builtin/skills/database/postgresql/SKILL.md +120 -0
  32. package/builtin/skills/database/prisma-orm/SKILL.md +366 -0
  33. package/builtin/skills/database/redis/SKILL.md +140 -0
  34. package/builtin/skills/database/supabase/SKILL.md +416 -0
  35. package/builtin/skills/devops/aws/SKILL.md +382 -0
  36. package/builtin/skills/devops/docker/SKILL.md +359 -0
  37. package/builtin/skills/devops/github-actions/SKILL.md +435 -0
  38. package/builtin/skills/devops/kubernetes/SKILL.md +459 -0
  39. package/builtin/skills/devops/terraform/SKILL.md +453 -0
  40. package/builtin/skills/frontend/alpine-dev/SKILL.md +27 -0
  41. package/builtin/skills/frontend/angular-dev/SKILL.md +28 -0
  42. package/builtin/skills/frontend/astro-dev/SKILL.md +28 -0
  43. package/builtin/skills/frontend/htmx-dev/SKILL.md +28 -0
  44. package/builtin/skills/frontend/nextjs-dev/SKILL.md +470 -0
  45. package/builtin/skills/frontend/react-patterns/SKILL.md +166 -0
  46. package/builtin/skills/frontend/svelte-dev/SKILL.md +28 -0
  47. package/builtin/skills/frontend/tailwindcss/SKILL.md +131 -0
  48. package/builtin/skills/frontend/vuejs-dev/SKILL.md +28 -0
  49. package/builtin/skills/generic-dev/SKILL.md +307 -0
  50. package/builtin/skills/testing/cypress/SKILL.md +372 -0
  51. package/builtin/skills/testing/jest/SKILL.md +176 -0
  52. package/builtin/skills/testing/playwright/SKILL.md +341 -0
  53. package/builtin/skills/testing/unit-tests-eval-sdd/SKILL.md +73 -0
  54. package/builtin/skills/testing/unit-tests-sdd/SKILL.md +83 -0
  55. package/builtin/skills/testing/vitest/SKILL.md +249 -0
  56. package/dist/adapters/skills/filesystem.d.ts.map +1 -1
  57. package/dist/adapters/skills/filesystem.js +2 -18
  58. package/dist/adapters/skills/filesystem.js.map +1 -1
  59. package/dist/builtin-assets.d.ts +8 -0
  60. package/dist/builtin-assets.d.ts.map +1 -0
  61. package/dist/builtin-assets.js +90 -0
  62. package/dist/builtin-assets.js.map +1 -0
  63. package/dist/init.js +69 -11
  64. package/dist/init.js.map +1 -1
  65. package/dist/schemas.d.ts +1 -1
  66. package/dist/server.js +1 -1
  67. package/dist/server.js.map +1 -1
  68. package/dist/tools/prepare-phase-context.d.ts.map +1 -1
  69. package/dist/tools/prepare-phase-context.js +5 -0
  70. package/dist/tools/prepare-phase-context.js.map +1 -1
  71. package/dist/types.d.ts +3 -0
  72. package/dist/types.d.ts.map +1 -1
  73. package/package.json +5 -3
@@ -0,0 +1,469 @@
1
+ ---
2
+ name: rest-api
3
+ description: REST API design and implementation expertise. Covers HTTP methods, status codes, resource naming, versioning, authentication, and OpenAPI documentation.
4
+ category: api
5
+ compatible_with:
6
+ - nodejs-express
7
+ - nodejs-fastify
8
+ - python-fastapi
9
+ - golang-gin
10
+ ---
11
+
12
+ # REST API Design
13
+
14
+ ## Instructions
15
+
16
+ 1. **Assess the API need**: CRUD operations, complex queries, or real-time data.
17
+ 2. **Follow REST conventions**:
18
+ - Use nouns for resources, not verbs
19
+ - Proper HTTP methods and status codes
20
+ - Consistent naming conventions
21
+ - HATEOAS where appropriate
22
+ 3. **Provide complete examples**: Include routes, handlers, and response schemas.
23
+ 4. **Guide on best practices**: Versioning, pagination, filtering, error handling.
24
+
25
+ ## HTTP Methods
26
+
27
+ | Method | Purpose | Idempotent | Safe |
28
+ |--------|---------|------------|------|
29
+ | GET | Retrieve resource(s) | Yes | Yes |
30
+ | POST | Create resource | No | No |
31
+ | PUT | Replace resource | Yes | No |
32
+ | PATCH | Partial update | No | No |
33
+ | DELETE | Remove resource | Yes | No |
34
+
35
+ ## Resource Naming
36
+
37
+ ```
38
+ # Good - Nouns, plural
39
+ GET /users
40
+ GET /users/:id
41
+ POST /users
42
+ PUT /users/:id
43
+ PATCH /users/:id
44
+ DELETE /users/:id
45
+
46
+ # Nested resources
47
+ GET /users/:userId/posts
48
+ GET /users/:userId/posts/:postId
49
+ POST /users/:userId/posts
50
+
51
+ # Bad - Verbs, actions in URL
52
+ GET /getUsers
53
+ POST /createUser
54
+ GET /getUserById/:id
55
+ ```
56
+
57
+ ## Status Codes
58
+
59
+ ### Success (2xx)
60
+
61
+ ```javascript
62
+ // 200 OK - Successful GET, PUT, PATCH
63
+ res.status(200).json({ data: user });
64
+
65
+ // 201 Created - Successful POST
66
+ res.status(201).json({ data: newUser });
67
+
68
+ // 204 No Content - Successful DELETE
69
+ res.status(204).send();
70
+ ```
71
+
72
+ ### Client Errors (4xx)
73
+
74
+ ```javascript
75
+ // 400 Bad Request - Invalid input
76
+ res.status(400).json({
77
+ error: {
78
+ code: 'VALIDATION_ERROR',
79
+ message: 'Invalid request body',
80
+ details: [
81
+ { field: 'email', message: 'Must be a valid email' }
82
+ ]
83
+ }
84
+ });
85
+
86
+ // 401 Unauthorized - Not authenticated
87
+ res.status(401).json({
88
+ error: {
89
+ code: 'UNAUTHORIZED',
90
+ message: 'Authentication required'
91
+ }
92
+ });
93
+
94
+ // 403 Forbidden - Authenticated but not authorized
95
+ res.status(403).json({
96
+ error: {
97
+ code: 'FORBIDDEN',
98
+ message: 'You do not have permission to access this resource'
99
+ }
100
+ });
101
+
102
+ // 404 Not Found
103
+ res.status(404).json({
104
+ error: {
105
+ code: 'NOT_FOUND',
106
+ message: 'User not found'
107
+ }
108
+ });
109
+
110
+ // 409 Conflict - Resource already exists
111
+ res.status(409).json({
112
+ error: {
113
+ code: 'CONFLICT',
114
+ message: 'Email already registered'
115
+ }
116
+ });
117
+
118
+ // 422 Unprocessable Entity - Semantic errors
119
+ res.status(422).json({
120
+ error: {
121
+ code: 'UNPROCESSABLE_ENTITY',
122
+ message: 'Cannot delete user with active subscriptions'
123
+ }
124
+ });
125
+
126
+ // 429 Too Many Requests - Rate limiting
127
+ res.status(429).json({
128
+ error: {
129
+ code: 'RATE_LIMITED',
130
+ message: 'Too many requests',
131
+ retryAfter: 60
132
+ }
133
+ });
134
+ ```
135
+
136
+ ### Server Errors (5xx)
137
+
138
+ ```javascript
139
+ // 500 Internal Server Error
140
+ res.status(500).json({
141
+ error: {
142
+ code: 'INTERNAL_ERROR',
143
+ message: 'An unexpected error occurred'
144
+ }
145
+ });
146
+
147
+ // 503 Service Unavailable
148
+ res.status(503).json({
149
+ error: {
150
+ code: 'SERVICE_UNAVAILABLE',
151
+ message: 'Service temporarily unavailable',
152
+ retryAfter: 300
153
+ }
154
+ });
155
+ ```
156
+
157
+ ## Response Structure
158
+
159
+ ### Single Resource
160
+
161
+ ```json
162
+ {
163
+ "data": {
164
+ "id": "123",
165
+ "type": "user",
166
+ "attributes": {
167
+ "email": "user@example.com",
168
+ "name": "John Doe",
169
+ "createdAt": "2024-01-15T10:30:00Z"
170
+ }
171
+ }
172
+ }
173
+ ```
174
+
175
+ ### Collection
176
+
177
+ ```json
178
+ {
179
+ "data": [
180
+ { "id": "1", "name": "Item 1" },
181
+ { "id": "2", "name": "Item 2" }
182
+ ],
183
+ "meta": {
184
+ "total": 100,
185
+ "page": 1,
186
+ "perPage": 20,
187
+ "totalPages": 5
188
+ },
189
+ "links": {
190
+ "self": "/items?page=1",
191
+ "first": "/items?page=1",
192
+ "prev": null,
193
+ "next": "/items?page=2",
194
+ "last": "/items?page=5"
195
+ }
196
+ }
197
+ ```
198
+
199
+ ## Pagination
200
+
201
+ ### Offset-based
202
+
203
+ ```
204
+ GET /users?page=2&limit=20
205
+ GET /users?offset=20&limit=20
206
+ ```
207
+
208
+ ### Cursor-based (recommended for large datasets)
209
+
210
+ ```
211
+ GET /users?cursor=eyJpZCI6MTAwfQ&limit=20
212
+
213
+ Response:
214
+ {
215
+ "data": [...],
216
+ "meta": {
217
+ "hasMore": true,
218
+ "nextCursor": "eyJpZCI6MTIwfQ"
219
+ }
220
+ }
221
+ ```
222
+
223
+ ## Filtering & Sorting
224
+
225
+ ```
226
+ # Filtering
227
+ GET /users?status=active
228
+ GET /users?role=admin&status=active
229
+ GET /users?createdAt[gte]=2024-01-01
230
+ GET /users?search=john
231
+
232
+ # Sorting
233
+ GET /users?sort=createdAt
234
+ GET /users?sort=-createdAt # Descending
235
+ GET /users?sort=lastName,firstName # Multiple fields
236
+
237
+ # Field selection
238
+ GET /users?fields=id,email,name
239
+ GET /users?include=posts,comments # Relations
240
+ ```
241
+
242
+ ## Versioning
243
+
244
+ ### URL Path (recommended)
245
+
246
+ ```
247
+ GET /api/v1/users
248
+ GET /api/v2/users
249
+ ```
250
+
251
+ ### Header-based
252
+
253
+ ```
254
+ GET /api/users
255
+ Accept: application/vnd.myapi.v2+json
256
+ ```
257
+
258
+ ### Query Parameter
259
+
260
+ ```
261
+ GET /api/users?version=2
262
+ ```
263
+
264
+ ## Authentication
265
+
266
+ ### Bearer Token (JWT)
267
+
268
+ ```javascript
269
+ // Request
270
+ GET /api/users
271
+ Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
272
+
273
+ // Middleware
274
+ const authenticate = (req, res, next) => {
275
+ const token = req.headers.authorization?.replace('Bearer ', '');
276
+ if (!token) {
277
+ return res.status(401).json({ error: { message: 'Token required' } });
278
+ }
279
+
280
+ try {
281
+ const decoded = jwt.verify(token, process.env.JWT_SECRET);
282
+ req.user = decoded;
283
+ next();
284
+ } catch (err) {
285
+ return res.status(401).json({ error: { message: 'Invalid token' } });
286
+ }
287
+ };
288
+ ```
289
+
290
+ ### API Key
291
+
292
+ ```javascript
293
+ // Request
294
+ GET /api/users
295
+ X-API-Key: sk_live_abc123
296
+
297
+ // Middleware
298
+ const apiKeyAuth = async (req, res, next) => {
299
+ const apiKey = req.headers['x-api-key'];
300
+ if (!apiKey) {
301
+ return res.status(401).json({ error: { message: 'API key required' } });
302
+ }
303
+
304
+ const client = await db.apiKeys.findOne({ key: apiKey, active: true });
305
+ if (!client) {
306
+ return res.status(401).json({ error: { message: 'Invalid API key' } });
307
+ }
308
+
309
+ req.client = client;
310
+ next();
311
+ };
312
+ ```
313
+
314
+ ## Rate Limiting
315
+
316
+ ```javascript
317
+ import rateLimit from 'express-rate-limit';
318
+
319
+ const limiter = rateLimit({
320
+ windowMs: 15 * 60 * 1000, // 15 minutes
321
+ max: 100,
322
+ standardHeaders: true,
323
+ legacyHeaders: false,
324
+ handler: (req, res) => {
325
+ res.status(429).json({
326
+ error: {
327
+ code: 'RATE_LIMITED',
328
+ message: 'Too many requests',
329
+ retryAfter: Math.ceil(req.rateLimit.resetTime / 1000)
330
+ }
331
+ });
332
+ }
333
+ });
334
+
335
+ app.use('/api/', limiter);
336
+ ```
337
+
338
+ ## OpenAPI/Swagger
339
+
340
+ ```yaml
341
+ openapi: 3.0.3
342
+ info:
343
+ title: My API
344
+ version: 1.0.0
345
+
346
+ paths:
347
+ /users:
348
+ get:
349
+ summary: List users
350
+ parameters:
351
+ - name: page
352
+ in: query
353
+ schema:
354
+ type: integer
355
+ default: 1
356
+ - name: limit
357
+ in: query
358
+ schema:
359
+ type: integer
360
+ default: 20
361
+ responses:
362
+ '200':
363
+ description: Successful response
364
+ content:
365
+ application/json:
366
+ schema:
367
+ type: object
368
+ properties:
369
+ data:
370
+ type: array
371
+ items:
372
+ $ref: '#/components/schemas/User'
373
+ post:
374
+ summary: Create user
375
+ requestBody:
376
+ required: true
377
+ content:
378
+ application/json:
379
+ schema:
380
+ $ref: '#/components/schemas/CreateUserInput'
381
+ responses:
382
+ '201':
383
+ description: User created
384
+
385
+ components:
386
+ schemas:
387
+ User:
388
+ type: object
389
+ properties:
390
+ id:
391
+ type: string
392
+ email:
393
+ type: string
394
+ format: email
395
+ name:
396
+ type: string
397
+ createdAt:
398
+ type: string
399
+ format: date-time
400
+ CreateUserInput:
401
+ type: object
402
+ required:
403
+ - email
404
+ - name
405
+ properties:
406
+ email:
407
+ type: string
408
+ format: email
409
+ name:
410
+ type: string
411
+ ```
412
+
413
+ ## Best Practices
414
+
415
+ - **Use HTTPS** - Always encrypt in transit
416
+ - **Validate input** - Never trust client data
417
+ - **Return consistent responses** - Same structure for success/error
418
+ - **Use proper status codes** - Don't use 200 for everything
419
+ - **Version your API** - Plan for breaking changes
420
+ - **Document thoroughly** - OpenAPI/Swagger
421
+ - **Implement rate limiting** - Protect against abuse
422
+ - **Log requests** - For debugging and auditing
423
+ - **Use ETags** - For caching and conditional requests
424
+ - **CORS** - Configure properly for web clients
425
+
426
+ ## Error Handling Pattern
427
+
428
+ ```javascript
429
+ class APIError extends Error {
430
+ constructor(code, message, status = 400, details = null) {
431
+ super(message);
432
+ this.code = code;
433
+ this.status = status;
434
+ this.details = details;
435
+ }
436
+ }
437
+
438
+ // Usage
439
+ throw new APIError('VALIDATION_ERROR', 'Invalid email', 400, [
440
+ { field: 'email', message: 'Must be valid email format' }
441
+ ]);
442
+
443
+ // Global error handler
444
+ app.use((err, req, res, next) => {
445
+ if (err instanceof APIError) {
446
+ return res.status(err.status).json({
447
+ error: {
448
+ code: err.code,
449
+ message: err.message,
450
+ details: err.details
451
+ }
452
+ });
453
+ }
454
+
455
+ console.error(err);
456
+ res.status(500).json({
457
+ error: {
458
+ code: 'INTERNAL_ERROR',
459
+ message: 'An unexpected error occurred'
460
+ }
461
+ });
462
+ });
463
+ ```
464
+
465
+ ## References
466
+
467
+ - REST API Design: https://restfulapi.net/
468
+ - HTTP Status Codes: https://httpstatuses.com/
469
+ - OpenAPI Specification: https://swagger.io/specification/