create-agent-room 1.2.1
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/README.md +229 -0
- package/bin/cli.js +186 -0
- package/examples/python-project/.agent-room.json +14 -0
- package/examples/python-project/AGENTS.md +32 -0
- package/examples/rust-project/.agent-room.json +12 -0
- package/examples/rust-project/AGENTS.md +32 -0
- package/lib/color.js +31 -0
- package/lib/fsutil.js +218 -0
- package/lib/init.js +660 -0
- package/lib/lint-sessions.js +278 -0
- package/lib/metrics.js +190 -0
- package/lib/pr.js +176 -0
- package/lib/prompt.js +20 -0
- package/lib/session-utils.js +213 -0
- package/lib/sync.js +138 -0
- package/lib/validate.js +179 -0
- package/package.json +48 -0
- package/templates/.agent-room/anti-patterns.md +22 -0
- package/templates/.agent-room/coordination/handoff-protocol.md +60 -0
- package/templates/.agent-room/coordination/scope-boundaries.md +57 -0
- package/templates/.agent-room/coordination/session-log-format.md +62 -0
- package/templates/.agent-room/decisions.md +17 -0
- package/templates/.agent-room/guardrails.json +23 -0
- package/templates/.agent-room/guardrails.md +56 -0
- package/templates/.agent-room/principles.md +306 -0
- package/templates/.agent-room/sessions/.gitkeep +4 -0
- package/templates/.agent-room/skills/brainstorming.md +64 -0
- package/templates/.agent-room/skills/closing-the-loop.md +67 -0
- package/templates/.agent-room/skills/systematic-debugging.md +85 -0
- package/templates/.agent-room/skills/test-driven-development.md +100 -0
- package/templates/.agent-room/skills/verification-before-completion.md +56 -0
- package/templates/.agent-room/skills/writing-plans.md +87 -0
- package/templates/.agent-room/workflow-classifier.md +127 -0
- package/templates/AGENTS.md.tmpl +85 -0
- package/templates/adapters/CLAUDE.md.tmpl +38 -0
- package/templates/adapters/claude-hooks/close-the-loop-check.js +96 -0
- package/templates/adapters/clinerules.tmpl +14 -0
- package/templates/adapters/codexrules.tmpl +45 -0
- package/templates/adapters/cursorrules.tmpl +14 -0
- package/templates/adapters/git-hooks/guardrails-check.js +140 -0
- package/templates/adapters/git-hooks/pre-commit.tmpl +43 -0
- package/templates/adapters/windsurfrules.tmpl +14 -0
- package/templates/docs/plans/.gitkeep +0 -0
- package/templates/skill-packs/api-design/api-design.md +152 -0
- package/templates/skill-packs/code-review/code-review.md +113 -0
- package/templates/skill-packs/database/database-migrations.md +123 -0
- package/templates/skill-packs/documentation/documentation.md +155 -0
- package/templates/skill-packs/observability/observability.md +128 -0
- package/templates/skill-packs/performance/performance-optimization.md +150 -0
- package/templates/skill-packs/release/release-management.md +145 -0
- package/templates/skill-packs/security/security-principles.md +127 -0
- package/templates/skill-packs/testing/integration-testing.md +127 -0
- package/templates/stacks/python/.agent-room/skills/python-testing.md +59 -0
- package/templates/stacks/python/AGENTS.md.tmpl +35 -0
- package/templates/stacks/react/.agent-room/skills/react-component-testing.md +76 -0
- package/templates/stacks/react/AGENTS.md.tmpl +37 -0
- package/templates/stacks/typescript/.agent-room/skills/typescript-testing.md +63 -0
- package/templates/stacks/typescript/AGENTS.md.tmpl +36 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Cline rules — {{PROJECT_NAME}}
|
|
2
|
+
|
|
3
|
+
Read [`AGENTS.md`](AGENTS.md) and everything under
|
|
4
|
+
[`.agent-room/`](.agent-room/) before making non-trivial changes:
|
|
5
|
+
|
|
6
|
+
- `.agent-room/principles.md` — how to get reliable output from the model.
|
|
7
|
+
- `.agent-room/workflow-classifier.md` — size the process to the work
|
|
8
|
+
(Bug / Enhancement / Feature / Product).
|
|
9
|
+
- `.agent-room/skills/` — brainstorming, writing-plans, TDD, systematic
|
|
10
|
+
debugging, verification-before-completion. Follow these as procedures,
|
|
11
|
+
not suggestions.
|
|
12
|
+
- `.agent-room/anti-patterns.md` and `.agent-room/decisions.md` — check
|
|
13
|
+
before repeating a past mistake; append after a new one or a notable
|
|
14
|
+
decision.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Codex rules — {{PROJECT_NAME}}
|
|
2
|
+
|
|
3
|
+
Read [`AGENTS.md`](AGENTS.md) and everything under
|
|
4
|
+
[`.agent-room/`](.agent-room/) before making non-trivial changes:
|
|
5
|
+
|
|
6
|
+
- `.agent-room/principles.md` — how to get reliable output from the model.
|
|
7
|
+
- `.agent-room/workflow-classifier.md` — size the process to the work
|
|
8
|
+
(Bug / Enhancement / Feature / Product).
|
|
9
|
+
- `.agent-room/skills/` — brainstorming, writing-plans, TDD, systematic
|
|
10
|
+
debugging, verification-before-completion. Follow these as procedures,
|
|
11
|
+
not suggestions.
|
|
12
|
+
- `.agent-room/anti-patterns.md` and `.agent-room/decisions.md` — check
|
|
13
|
+
before repeating a past mistake; append after a new one or a notable
|
|
14
|
+
decision.
|
|
15
|
+
|
|
16
|
+
## Core rules
|
|
17
|
+
|
|
18
|
+
1. **Always read AGENTS.md first.** It's the entry point for any coder.
|
|
19
|
+
|
|
20
|
+
2. **Classify the work:** Use `.agent-room/workflow-classifier.md` to size
|
|
21
|
+
the process (bug fix ≠ feature ≠ enhancement). Don't over-engineer.
|
|
22
|
+
|
|
23
|
+
3. **Brainstorm before coding:** For any non-trivial change, brainstorm
|
|
24
|
+
2-3 approaches with tradeoffs before writing code.
|
|
25
|
+
|
|
26
|
+
4. **Write tests first (TDD):** Failing test → implementation → passing test.
|
|
27
|
+
Then refactor. This catches bugs early.
|
|
28
|
+
|
|
29
|
+
5. **Verify before handing off:** Run the full test suite and checks before
|
|
30
|
+
marking work complete. Leave the codebase in a shippable state.
|
|
31
|
+
|
|
32
|
+
6. **Close the loop:** Before ending a session, append decisions and
|
|
33
|
+
anti-patterns to `.agent-room/decisions.md` and `.agent-room/anti-patterns.md`.
|
|
34
|
+
Document what you learned.
|
|
35
|
+
|
|
36
|
+
## Guardrails
|
|
37
|
+
|
|
38
|
+
Review `.agent-room/guardrails.md` for protected paths, approval requirements,
|
|
39
|
+
and forbidden actions. Some changes require human review.
|
|
40
|
+
|
|
41
|
+
## Session logs
|
|
42
|
+
|
|
43
|
+
Save a session log to `.agent-room/sessions/` following the format in
|
|
44
|
+
`.agent-room/coordination/session-log-format.md`. Include goal, actions,
|
|
45
|
+
decisions, and outcome.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Cursor rules — {{PROJECT_NAME}}
|
|
2
|
+
|
|
3
|
+
Read [`AGENTS.md`](../AGENTS.md) and everything under
|
|
4
|
+
[`.agent-room/`](../.agent-room/) before making non-trivial changes:
|
|
5
|
+
|
|
6
|
+
- `.agent-room/principles.md` — how to get reliable output from the model.
|
|
7
|
+
- `.agent-room/workflow-classifier.md` — size the process to the work
|
|
8
|
+
(Bug / Enhancement / Feature / Product).
|
|
9
|
+
- `.agent-room/skills/` — brainstorming, writing-plans, TDD, systematic
|
|
10
|
+
debugging, verification-before-completion. Follow these as procedures,
|
|
11
|
+
not suggestions.
|
|
12
|
+
- `.agent-room/anti-patterns.md` and `.agent-room/decisions.md` — check
|
|
13
|
+
before repeating a past mistake; append after a new one or a notable
|
|
14
|
+
decision.
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Pre-commit hook for guardrails enforcement
|
|
6
|
+
* Prevents commits that violate project guardrails
|
|
7
|
+
*
|
|
8
|
+
* Checks:
|
|
9
|
+
* - Protected paths: blocks commits to paths requiring approval
|
|
10
|
+
* - Forbidden actions: blocks commits containing dangerous patterns (e.g., hard-coded credentials)
|
|
11
|
+
* - Minimum checks before merge
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
const path = require('path');
|
|
16
|
+
const { execSync } = require('child_process');
|
|
17
|
+
|
|
18
|
+
const projectRoot = process.cwd();
|
|
19
|
+
const guardrailsPath = path.join(projectRoot, '.agent-room', 'guardrails.json');
|
|
20
|
+
|
|
21
|
+
// Allow override via env variable
|
|
22
|
+
const ALLOW_GUARDRAILS_BYPASS = process.env.GUARDRAILS_BYPASS || process.env.SKIP_GUARDRAILS_CHECK;
|
|
23
|
+
|
|
24
|
+
if (!fs.existsSync(guardrailsPath)) {
|
|
25
|
+
// No guardrails file, allow commit
|
|
26
|
+
process.exit(0);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let guardrails = {};
|
|
30
|
+
try {
|
|
31
|
+
guardrails = JSON.parse(fs.readFileSync(guardrailsPath, 'utf8'));
|
|
32
|
+
} catch (err) {
|
|
33
|
+
console.error(`⚠️ Failed to parse guardrails.json: ${err.message}`);
|
|
34
|
+
process.exit(0);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Get staged files
|
|
38
|
+
let stagedFiles = [];
|
|
39
|
+
try {
|
|
40
|
+
const output = execSync('git diff --cached --name-only', { encoding: 'utf8' });
|
|
41
|
+
stagedFiles = output.trim().split('\n').filter(Boolean);
|
|
42
|
+
} catch (err) {
|
|
43
|
+
// Not a git repo or no staged files
|
|
44
|
+
process.exit(0);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const protectedPaths = guardrails.protectedPaths || [];
|
|
48
|
+
const forbiddenPatterns = guardrails.forbiddenActions || [];
|
|
49
|
+
|
|
50
|
+
let violations = [];
|
|
51
|
+
|
|
52
|
+
// Check protected paths
|
|
53
|
+
for (const file of stagedFiles) {
|
|
54
|
+
for (const protectedPath of protectedPaths) {
|
|
55
|
+
if (isPathProtected(file, protectedPath)) {
|
|
56
|
+
violations.push(`Protected path violation: ${file}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Check for forbidden patterns in staged content
|
|
62
|
+
for (const file of stagedFiles) {
|
|
63
|
+
if (!fs.existsSync(file)) continue;
|
|
64
|
+
|
|
65
|
+
// Skip binary files and very large files
|
|
66
|
+
if (isBinaryFile(file) || fs.statSync(file).size > 1_000_000) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
// Get staged content (not working tree)
|
|
72
|
+
const stagedContent = execSync(`git show :${file}`, { encoding: 'utf8' });
|
|
73
|
+
|
|
74
|
+
for (const pattern of forbiddenPatterns) {
|
|
75
|
+
if (pattern.match(/^\/.*\/[gimuy]*$/) || pattern.startsWith('(?:') || pattern.includes('(?:')) {
|
|
76
|
+
// It's a regex
|
|
77
|
+
try {
|
|
78
|
+
const regex = new RegExp(pattern);
|
|
79
|
+
if (regex.test(stagedContent)) {
|
|
80
|
+
violations.push(`Forbidden pattern found in ${file}: ${pattern}`);
|
|
81
|
+
}
|
|
82
|
+
} catch (regexErr) {
|
|
83
|
+
// Invalid regex, skip
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
// Literal string
|
|
87
|
+
if (stagedContent.includes(pattern)) {
|
|
88
|
+
violations.push(`Forbidden pattern found in ${file}: ${pattern}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
} catch (err) {
|
|
93
|
+
// File might not exist in index yet
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (violations.length > 0) {
|
|
98
|
+
console.error('');
|
|
99
|
+
console.error('❌ Guardrails Check Failed: Commit violates project guardrails');
|
|
100
|
+
console.error('');
|
|
101
|
+
for (const violation of violations) {
|
|
102
|
+
console.error(` - ${violation}`);
|
|
103
|
+
}
|
|
104
|
+
console.error('');
|
|
105
|
+
console.error('To bypass guardrails (requires approval), use:');
|
|
106
|
+
console.error(' GUARDRAILS_BYPASS=1 git commit');
|
|
107
|
+
console.error('');
|
|
108
|
+
|
|
109
|
+
if (!ALLOW_GUARDRAILS_BYPASS) {
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
console.warn('⚠️ Guardrails bypass enabled - proceeding with commit');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
process.exit(0);
|
|
117
|
+
|
|
118
|
+
function isPathProtected(filePath, protectedPattern) {
|
|
119
|
+
// Normalize paths for comparison
|
|
120
|
+
const normalized = filePath.replace(/\\/g, '/');
|
|
121
|
+
const pattern = protectedPattern.replace(/\\/g, '/');
|
|
122
|
+
|
|
123
|
+
// Handle glob patterns
|
|
124
|
+
if (pattern.includes('*')) {
|
|
125
|
+
const regexPattern = pattern
|
|
126
|
+
.split('*')
|
|
127
|
+
.map((part) => part.replace(/[.+?^${}()|[\]\\]/g, '\\$&'))
|
|
128
|
+
.join('.*');
|
|
129
|
+
return new RegExp(`^${regexPattern}$`).test(normalized);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Direct match or prefix match
|
|
133
|
+
return normalized === pattern || normalized.startsWith(pattern + '/');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function isBinaryFile(filePath) {
|
|
137
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
138
|
+
const binaryExts = ['.png', '.jpg', '.jpeg', '.gif', '.pdf', '.zip', '.tar', '.exe', '.dll', '.so', '.bin'];
|
|
139
|
+
return binaryExts.includes(ext);
|
|
140
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Git pre-commit hook generated by create-agent-room
|
|
3
|
+
# Enforces the closing-the-loop discipline and guardrails checks for all commits.
|
|
4
|
+
|
|
5
|
+
if ! [ -d ".agent-room" ]; then
|
|
6
|
+
exit 0
|
|
7
|
+
fi
|
|
8
|
+
|
|
9
|
+
# First, run guardrails check
|
|
10
|
+
if [ -f ".agent-room/hooks/guardrails-check.js" ]; then
|
|
11
|
+
node ".agent-room/hooks/guardrails-check.js"
|
|
12
|
+
if [ $? -ne 0 ]; then
|
|
13
|
+
exit 1
|
|
14
|
+
fi
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
# List of changed files staged for commit
|
|
18
|
+
STAGED_FILES=$(git diff --cached --name-only)
|
|
19
|
+
|
|
20
|
+
# Check if there are non-scaffold files changed
|
|
21
|
+
HAS_SOURCE_CHANGES=false
|
|
22
|
+
HAS_LOG_TOUCHED=false
|
|
23
|
+
|
|
24
|
+
for file in $STAGED_FILES; do
|
|
25
|
+
case "$file" in
|
|
26
|
+
.agent-room/anti-patterns.md|.agent-room/decisions.md)
|
|
27
|
+
HAS_LOG_TOUCHED=true
|
|
28
|
+
;;
|
|
29
|
+
AGENTS.md|CLAUDE.md|.claude/*|.cursor/*|.windsurfrules|.clinerules|docs/plans/*)
|
|
30
|
+
# Skip scaffold/plan updates
|
|
31
|
+
;;
|
|
32
|
+
*)
|
|
33
|
+
HAS_SOURCE_CHANGES=true
|
|
34
|
+
;;
|
|
35
|
+
esac
|
|
36
|
+
done
|
|
37
|
+
|
|
38
|
+
if [ "$HAS_SOURCE_CHANGES" = true ] && [ "$HAS_LOG_TOUCHED" = false ]; then
|
|
39
|
+
echo "ERROR: Close-the-loop check failed." >&2
|
|
40
|
+
echo "You changed source files but did not update .agent-room/anti-patterns.md or .agent-room/decisions.md." >&2
|
|
41
|
+
echo "To bypass, append a waiver to decisions.md, or commit with 'git commit --no-verify' (use with caution)." >&2
|
|
42
|
+
exit 1
|
|
43
|
+
fi
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Windsurf rules — {{PROJECT_NAME}}
|
|
2
|
+
|
|
3
|
+
Read [`AGENTS.md`](AGENTS.md) and everything under
|
|
4
|
+
[`.agent-room/`](.agent-room/) before making non-trivial changes:
|
|
5
|
+
|
|
6
|
+
- `.agent-room/principles.md` — how to get reliable output from the model.
|
|
7
|
+
- `.agent-room/workflow-classifier.md` — size the process to the work
|
|
8
|
+
(Bug / Enhancement / Feature / Product).
|
|
9
|
+
- `.agent-room/skills/` — brainstorming, writing-plans, TDD, systematic
|
|
10
|
+
debugging, verification-before-completion. Follow these as procedures,
|
|
11
|
+
not suggestions.
|
|
12
|
+
- `.agent-room/anti-patterns.md` and `.agent-room/decisions.md` — check
|
|
13
|
+
before repeating a past mistake; append after a new one or a notable
|
|
14
|
+
decision.
|
|
File without changes
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: api-design
|
|
3
|
+
description: "Use when designing, implementing, or modifying REST APIs, GraphQL schemas, or any service interface that other systems or clients consume."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# API Design
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
An API is a contract. Unlike internal code, changing an API breaks other
|
|
11
|
+
people's code. Design for clarity, consistency, and evolution from the
|
|
12
|
+
start — retrofitting these qualities is expensive and disruptive.
|
|
13
|
+
|
|
14
|
+
## The iron law
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
BREAKING CHANGES REQUIRE A VERSIONED MIGRATION PATH
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Never remove, rename, or change the type of an existing field, endpoint,
|
|
21
|
+
or response shape without a deprecation period and a documented migration
|
|
22
|
+
path. "Nobody uses this endpoint" is not evidence — check access logs.
|
|
23
|
+
|
|
24
|
+
## Resource naming
|
|
25
|
+
|
|
26
|
+
- Use nouns, not verbs: `/users`, not `/getUsers`.
|
|
27
|
+
- Use plural nouns: `/orders`, not `/order`.
|
|
28
|
+
- Use kebab-case for multi-word resources: `/order-items`, not
|
|
29
|
+
`/orderItems` or `/order_items`.
|
|
30
|
+
- Nest for relationships: `/users/{id}/orders`, not `/getUserOrders`.
|
|
31
|
+
- Keep nesting shallow (max 2 levels). Deep nesting creates rigid
|
|
32
|
+
coupling: `/users/{id}/orders/{oid}/items/{iid}/comments` is a sign
|
|
33
|
+
the resource model needs rethinking.
|
|
34
|
+
|
|
35
|
+
## HTTP verb semantics
|
|
36
|
+
|
|
37
|
+
| Verb | Meaning | Idempotent | Safe |
|
|
38
|
+
| --- | --- | --- | --- |
|
|
39
|
+
| GET | Retrieve a resource | Yes | Yes |
|
|
40
|
+
| POST | Create a new resource | No | No |
|
|
41
|
+
| PUT | Replace a resource entirely | Yes | No |
|
|
42
|
+
| PATCH | Partially update a resource | No* | No |
|
|
43
|
+
| DELETE | Remove a resource | Yes | No |
|
|
44
|
+
|
|
45
|
+
*PATCH is not inherently idempotent but can be designed to be.
|
|
46
|
+
|
|
47
|
+
**Common agent mistakes:**
|
|
48
|
+
- Using POST for everything (including fetches and updates).
|
|
49
|
+
- Using GET with a request body (not universally supported).
|
|
50
|
+
- Using DELETE to "soft delete" without documenting the behavior.
|
|
51
|
+
|
|
52
|
+
## Error response contract
|
|
53
|
+
|
|
54
|
+
Every API should return errors in a **consistent shape**. Don't invent a
|
|
55
|
+
new error format per endpoint.
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"error": {
|
|
60
|
+
"code": "VALIDATION_FAILED",
|
|
61
|
+
"message": "Email address is not valid.",
|
|
62
|
+
"details": [
|
|
63
|
+
{
|
|
64
|
+
"field": "email",
|
|
65
|
+
"reason": "Must be a valid email address.",
|
|
66
|
+
"value": "not-an-email"
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Rules:
|
|
74
|
+
- `code` is machine-readable (constant string, not a sentence).
|
|
75
|
+
- `message` is human-readable (for debugging, not for end users).
|
|
76
|
+
- `details` is optional, for validation errors with multiple fields.
|
|
77
|
+
- HTTP status code matches the error type (see table below).
|
|
78
|
+
|
|
79
|
+
| Status | When to use |
|
|
80
|
+
| --- | --- |
|
|
81
|
+
| 400 | Client sent invalid data (validation, malformed JSON) |
|
|
82
|
+
| 401 | No valid authentication credentials |
|
|
83
|
+
| 403 | Authenticated but not authorized for this resource |
|
|
84
|
+
| 404 | Resource does not exist |
|
|
85
|
+
| 409 | Conflict (duplicate email, version mismatch) |
|
|
86
|
+
| 422 | Request is syntactically valid but semantically wrong |
|
|
87
|
+
| 429 | Rate limit exceeded |
|
|
88
|
+
| 500 | Server error (never expose internal details to the client) |
|
|
89
|
+
|
|
90
|
+
## Pagination
|
|
91
|
+
|
|
92
|
+
Never return unbounded lists. Every list endpoint must support pagination.
|
|
93
|
+
|
|
94
|
+
**Cursor-based (recommended for large datasets):**
|
|
95
|
+
```
|
|
96
|
+
GET /orders?cursor=eyJpZCI6MTIzfQ&limit=20
|
|
97
|
+
```
|
|
98
|
+
Returns a `nextCursor` in the response. Stable under insertions/deletions.
|
|
99
|
+
|
|
100
|
+
**Offset-based (simpler, less stable):**
|
|
101
|
+
```
|
|
102
|
+
GET /orders?offset=40&limit=20
|
|
103
|
+
```
|
|
104
|
+
Breaks when items are inserted or deleted during pagination. Acceptable
|
|
105
|
+
for small, slowly-changing datasets.
|
|
106
|
+
|
|
107
|
+
**Always include pagination metadata in the response:**
|
|
108
|
+
```json
|
|
109
|
+
{
|
|
110
|
+
"data": [...],
|
|
111
|
+
"pagination": {
|
|
112
|
+
"nextCursor": "eyJpZCI6MTQzfQ",
|
|
113
|
+
"hasMore": true
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Versioning
|
|
119
|
+
|
|
120
|
+
When a breaking change is unavoidable:
|
|
121
|
+
|
|
122
|
+
1. **URL versioning** (`/api/v2/users`) — simple, explicit, easy to route.
|
|
123
|
+
2. **Header versioning** (`Accept: application/vnd.api.v2+json`) — cleaner
|
|
124
|
+
URLs but harder to test in a browser.
|
|
125
|
+
|
|
126
|
+
**Deprecation protocol:**
|
|
127
|
+
1. Add a `Sunset` header to the old endpoint with the removal date.
|
|
128
|
+
2. Log usage of deprecated endpoints (so you can notify consumers).
|
|
129
|
+
3. Maintain the old version for at least one release cycle (minimum 30
|
|
130
|
+
days for internal APIs, 90 days for public APIs).
|
|
131
|
+
4. Document migration steps in the changelog.
|
|
132
|
+
|
|
133
|
+
## Breaking change detection
|
|
134
|
+
|
|
135
|
+
Before modifying an existing endpoint, check:
|
|
136
|
+
|
|
137
|
+
- [ ] Am I removing or renaming a field in the response? → Breaking.
|
|
138
|
+
- [ ] Am I changing a field's type (string → number)? → Breaking.
|
|
139
|
+
- [ ] Am I adding a new required field to the request? → Breaking.
|
|
140
|
+
- [ ] Am I changing the HTTP status code for an existing error? → Breaking.
|
|
141
|
+
- [ ] Am I changing the URL path or query parameter names? → Breaking.
|
|
142
|
+
|
|
143
|
+
If any answer is "yes," use the versioning and deprecation protocol above.
|
|
144
|
+
Adding new optional fields to responses or requests is generally safe.
|
|
145
|
+
|
|
146
|
+
## Red flags — stop and redesign
|
|
147
|
+
|
|
148
|
+
Endpoints that accept 20+ query parameters · response shapes that change
|
|
149
|
+
based on the caller's role (use separate endpoints instead) · error
|
|
150
|
+
responses that return HTML instead of JSON · list endpoints without
|
|
151
|
+
pagination · APIs that expose internal database IDs without obfuscation ·
|
|
152
|
+
PUT endpoints that silently ignore unknown fields.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: code-review
|
|
3
|
+
description: "Use when reviewing pull requests, diffs, or code changes — whether as the reviewer or when preparing code for review."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Code Review
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Code review is not proofreading — it's a systematic evaluation of whether
|
|
11
|
+
a change is correct, safe, maintainable, and appropriately scoped. An
|
|
12
|
+
agent reviewing code must follow a consistent priority order, not scan
|
|
13
|
+
for whatever catches its eye first.
|
|
14
|
+
|
|
15
|
+
## The iron law
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
REVIEW IN PRIORITY ORDER: SECURITY → CORRECTNESS → PERFORMANCE → STYLE
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Security bugs that slip through review cause incidents. Correctness bugs
|
|
22
|
+
cause regressions. Performance issues cause gradual degradation. Style
|
|
23
|
+
issues cause friction. Review in order of impact.
|
|
24
|
+
|
|
25
|
+
## The review process
|
|
26
|
+
|
|
27
|
+
### 1. Understand the intent first
|
|
28
|
+
|
|
29
|
+
Before reading a single line of code:
|
|
30
|
+
- Read the PR description, linked issue, or design doc.
|
|
31
|
+
- Understand what the change is *supposed* to do.
|
|
32
|
+
- If the intent is unclear, ask before reviewing the implementation.
|
|
33
|
+
|
|
34
|
+
### 2. Review in priority order
|
|
35
|
+
|
|
36
|
+
**Security (blocking):**
|
|
37
|
+
- Does user input flow into queries, commands, or markup unsanitized?
|
|
38
|
+
- Are secrets hardcoded or logged?
|
|
39
|
+
- Are authorization checks present at the data layer, not just the route?
|
|
40
|
+
- Does the change introduce new attack surface (new endpoints, new file
|
|
41
|
+
uploads, new auth flows)?
|
|
42
|
+
|
|
43
|
+
**Correctness (blocking):**
|
|
44
|
+
- Does the code actually implement the stated intent?
|
|
45
|
+
- Are edge cases handled (empty input, null, boundary values, concurrency)?
|
|
46
|
+
- Are error paths handled (what happens when the network call fails, the
|
|
47
|
+
file doesn't exist, the database is down)?
|
|
48
|
+
- Does it have tests? Do the tests cover the meaningful behaviors?
|
|
49
|
+
|
|
50
|
+
**Performance (blocking if severe, otherwise non-blocking):**
|
|
51
|
+
- N+1 queries in loops?
|
|
52
|
+
- Unbounded data fetches (no pagination, no LIMIT)?
|
|
53
|
+
- Large allocations in hot paths?
|
|
54
|
+
- Missing indexes for new query patterns?
|
|
55
|
+
|
|
56
|
+
**Style and maintainability (non-blocking):**
|
|
57
|
+
- Naming clarity (would a new team member understand the intent?).
|
|
58
|
+
- Duplication that could be extracted.
|
|
59
|
+
- Comments that explain "why" not "what."
|
|
60
|
+
|
|
61
|
+
### 3. Check scope
|
|
62
|
+
|
|
63
|
+
A PR should do one thing. Red flags for scope creep:
|
|
64
|
+
- The PR title says "fix login bug" but also refactors the auth module.
|
|
65
|
+
- More than 500 lines changed for what should be a small fix.
|
|
66
|
+
- Unrelated formatting changes mixed with functional changes.
|
|
67
|
+
|
|
68
|
+
If scope is too broad, ask the author to split the PR. Don't review a
|
|
69
|
+
kitchen-sink PR — it's impossible to verify correctness when 5 concerns
|
|
70
|
+
are interleaved.
|
|
71
|
+
|
|
72
|
+
## Writing review comments
|
|
73
|
+
|
|
74
|
+
### Good comments are actionable
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
BAD: "This could be better."
|
|
78
|
+
GOOD: "This query fetches all users without pagination. With 100K users
|
|
79
|
+
this will OOM the server. Add LIMIT/OFFSET or cursor pagination."
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Distinguish blocking from non-blocking
|
|
83
|
+
|
|
84
|
+
- **Blocking:** Must be fixed before merge. Security issues, correctness
|
|
85
|
+
bugs, missing tests for new behavior.
|
|
86
|
+
- **Non-blocking (nit):** Prefix with "nit:" — style suggestions, minor
|
|
87
|
+
naming improvements, optional refactors. These should not block merge.
|
|
88
|
+
|
|
89
|
+
### Explain the "why," not just the "what"
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
BAD: "Use a Map instead of an Object."
|
|
93
|
+
GOOD: "nit: Consider a Map here — the keys are user-provided strings,
|
|
94
|
+
and Object prototype pollution is a risk if keys like '__proto__'
|
|
95
|
+
are possible. Not blocking if input is validated upstream."
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Self-review before requesting review
|
|
99
|
+
|
|
100
|
+
Before submitting code for review, run your own checklist:
|
|
101
|
+
|
|
102
|
+
- [ ] Does every new function/endpoint have tests?
|
|
103
|
+
- [ ] Did I remove all debugging artifacts (`console.log`, `debugger`)?
|
|
104
|
+
- [ ] Are there any TODOs that should be resolved before merge?
|
|
105
|
+
- [ ] Is the diff minimal? (No unrelated formatting, no leftover experiments.)
|
|
106
|
+
- [ ] Does the PR description explain what changed and why?
|
|
107
|
+
|
|
108
|
+
## Red flags — request changes immediately
|
|
109
|
+
|
|
110
|
+
Hardcoded credentials · missing auth checks on new endpoints · raw SQL
|
|
111
|
+
with string interpolation · `eval()` or `Function()` with external input ·
|
|
112
|
+
tests that assert the implementation rather than the behavior ·
|
|
113
|
+
catch-and-swallow error handling · PRs with no tests for new behavior.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: database-migrations
|
|
3
|
+
description: "Use when writing database schema changes, data migrations, creating indexes, or modifying existing tables in production-facing systems."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Database Migrations
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Database migrations are the riskiest part of most releases. Unlike code,
|
|
11
|
+
a bad migration can't be reverted by redeploying the previous version —
|
|
12
|
+
the data has already changed. Every migration must be backward-compatible,
|
|
13
|
+
tested, and paired with a rollback plan.
|
|
14
|
+
|
|
15
|
+
## The iron law
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
EVERY MIGRATION MUST BE BACKWARD-COMPATIBLE WITH THE CURRENTLY DEPLOYED CODE
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Deploy the migration first, then deploy the new code. If the migration
|
|
22
|
+
breaks the old code, you can't roll back the code deployment without also
|
|
23
|
+
rolling back the migration — and data migrations often can't be rolled back.
|
|
24
|
+
|
|
25
|
+
## Safe vs. unsafe operations
|
|
26
|
+
|
|
27
|
+
| Operation | Safe? | Notes |
|
|
28
|
+
| --- | --- | --- |
|
|
29
|
+
| Add a new table | ✅ Yes | No existing code references it |
|
|
30
|
+
| Add a nullable column | ✅ Yes | Old code ignores it |
|
|
31
|
+
| Add a column with a default | ✅ Yes* | *Check if your DB locks the table during ALTER |
|
|
32
|
+
| Add an index | ⚠️ Careful | Use CONCURRENTLY (Postgres) or equivalent |
|
|
33
|
+
| Rename a column | ❌ No | Old code uses the old name |
|
|
34
|
+
| Remove a column | ❌ No | Old code reads the old column |
|
|
35
|
+
| Change a column type | ❌ No | Old code expects the old type |
|
|
36
|
+
| Add a NOT NULL constraint | ❌ No | Existing rows may violate it |
|
|
37
|
+
|
|
38
|
+
## The multi-step pattern for unsafe changes
|
|
39
|
+
|
|
40
|
+
Unsafe operations must be split across multiple releases:
|
|
41
|
+
|
|
42
|
+
### Renaming a column (3 releases)
|
|
43
|
+
|
|
44
|
+
1. **Release 1:** Add the new column. Write to both old and new. Read
|
|
45
|
+
from old.
|
|
46
|
+
2. **Release 2:** Backfill the new column from the old. Switch reads to
|
|
47
|
+
the new column. Stop writing to old.
|
|
48
|
+
3. **Release 3:** Drop the old column.
|
|
49
|
+
|
|
50
|
+
### Removing a column (2 releases)
|
|
51
|
+
|
|
52
|
+
1. **Release 1:** Stop reading from the column in code. Stop writing to
|
|
53
|
+
it. (The column still exists in the database.)
|
|
54
|
+
2. **Release 2:** Drop the column via migration.
|
|
55
|
+
|
|
56
|
+
### Adding a NOT NULL constraint (2 releases)
|
|
57
|
+
|
|
58
|
+
1. **Release 1:** Backfill all NULL values. Add application-level
|
|
59
|
+
validation to prevent new NULLs.
|
|
60
|
+
2. **Release 2:** Add the database-level NOT NULL constraint.
|
|
61
|
+
|
|
62
|
+
## Index creation
|
|
63
|
+
|
|
64
|
+
Large indexes on production tables can lock writes for minutes or hours.
|
|
65
|
+
|
|
66
|
+
- **PostgreSQL:** Always use `CREATE INDEX CONCURRENTLY`. It takes longer
|
|
67
|
+
but doesn't lock the table.
|
|
68
|
+
- **MySQL:** Use `ALTER TABLE ... ADD INDEX` with `ALGORITHM=INPLACE,
|
|
69
|
+
LOCK=NONE` where supported.
|
|
70
|
+
- **Measure impact:** On large tables (>1M rows), test the index creation
|
|
71
|
+
on a staging copy first. Note the time and lock behavior.
|
|
72
|
+
- **Don't create indexes speculatively.** Add an index when you have a
|
|
73
|
+
slow query that needs it, not "in case someone queries this column
|
|
74
|
+
later."
|
|
75
|
+
|
|
76
|
+
## Data backfill strategies
|
|
77
|
+
|
|
78
|
+
When migrating data between columns or formats:
|
|
79
|
+
|
|
80
|
+
1. **Batch, don't bulk.** Process 1,000-10,000 rows at a time, not the
|
|
81
|
+
entire table in one statement. Bulk updates lock rows and can cause
|
|
82
|
+
replication lag.
|
|
83
|
+
2. **Idempotent backfills.** The backfill script should be safe to run
|
|
84
|
+
multiple times. Use `WHERE new_column IS NULL` to skip already-migrated
|
|
85
|
+
rows.
|
|
86
|
+
3. **Monitor progress.** Log how many rows are processed, how many remain,
|
|
87
|
+
and the estimated time to completion.
|
|
88
|
+
4. **Run during low-traffic windows** if the table is large and heavily
|
|
89
|
+
written to.
|
|
90
|
+
|
|
91
|
+
## Migration testing
|
|
92
|
+
|
|
93
|
+
Before deploying a migration to production:
|
|
94
|
+
|
|
95
|
+
- [ ] Run the migration against a copy of production data (or a
|
|
96
|
+
representative staging dataset).
|
|
97
|
+
- [ ] Verify the old code still works after the migration runs.
|
|
98
|
+
- [ ] Verify the new code works after the migration runs.
|
|
99
|
+
- [ ] Measure execution time. If it takes more than 30 seconds, consider
|
|
100
|
+
breaking it into smaller steps.
|
|
101
|
+
- [ ] Write and test the reverse migration. If the migration is
|
|
102
|
+
irreversible, document the manual recovery procedure.
|
|
103
|
+
|
|
104
|
+
## Rollback plan
|
|
105
|
+
|
|
106
|
+
Every migration must document its rollback before deployment:
|
|
107
|
+
|
|
108
|
+
- **Reversible migrations:** Include a `down` migration that undoes the
|
|
109
|
+
change. Test it.
|
|
110
|
+
- **Irreversible migrations** (dropped columns, data transformations):
|
|
111
|
+
Document what data is lost and the manual recovery procedure. Consider
|
|
112
|
+
whether a backup should be taken before running.
|
|
113
|
+
- **If in doubt, take a table snapshot** before running destructive
|
|
114
|
+
migrations. Storage is cheap; data loss is not.
|
|
115
|
+
|
|
116
|
+
## Red flags — stop and reassess
|
|
117
|
+
|
|
118
|
+
Migrations that take more than 5 minutes on staging · ALTER TABLE on a
|
|
119
|
+
table with active write traffic without testing lock behavior · backfills
|
|
120
|
+
that process the entire table in one transaction · migrations without a
|
|
121
|
+
tested reverse migration · dropping a column that's still referenced in
|
|
122
|
+
deployed code · adding a foreign key constraint to a large table without
|
|
123
|
+
validating existing data first.
|