mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-03-30 13:43:26 +08:00
feat: add Cursor, Codex, and OpenCode harnesses — maximize every AI coding tool
- AGENTS.md: universal cross-tool file read by Claude Code, Cursor, Codex, and OpenCode - .cursor/: 15 hook events via hooks.json, 16 hook scripts with DRY adapter pattern, 29 rules (9 common + 20 language-specific) with Cursor YAML frontmatter - .codex/: reference config.toml, Codex-specific AGENTS.md supplement, 10 skills ported to .agents/skills/ with openai.yaml metadata - .opencode/: 3 new tools (format-code, lint-check, git-summary), 3 new hooks (shell.env, experimental.session.compacting, permission.ask), expanded instructions, version bumped to 1.6.0 - README: fixed Cursor section, added Codex section, added cross-tool parity table - install.sh: now copies hooks.json + hooks/ for --target cursor
This commit is contained in:
109
.cursor/hooks.json
Normal file
109
.cursor/hooks.json
Normal file
@@ -0,0 +1,109 @@
|
||||
{
|
||||
"hooks": {
|
||||
"sessionStart": [
|
||||
{
|
||||
"command": "node .cursor/hooks/session-start.js",
|
||||
"event": "sessionStart",
|
||||
"description": "Load previous context and detect environment"
|
||||
}
|
||||
],
|
||||
"sessionEnd": [
|
||||
{
|
||||
"command": "node .cursor/hooks/session-end.js",
|
||||
"event": "sessionEnd",
|
||||
"description": "Persist session state and evaluate patterns"
|
||||
}
|
||||
],
|
||||
"beforeShellExecution": [
|
||||
{
|
||||
"command": "node .cursor/hooks/before-shell-execution.js",
|
||||
"event": "beforeShellExecution",
|
||||
"description": "Tmux dev server blocker, tmux reminder, git push review"
|
||||
}
|
||||
],
|
||||
"afterShellExecution": [
|
||||
{
|
||||
"command": "node .cursor/hooks/after-shell-execution.js",
|
||||
"event": "afterShellExecution",
|
||||
"description": "PR URL logging, build analysis"
|
||||
}
|
||||
],
|
||||
"afterFileEdit": [
|
||||
{
|
||||
"command": "node .cursor/hooks/after-file-edit.js",
|
||||
"event": "afterFileEdit",
|
||||
"description": "Auto-format, TypeScript check, console.log warning"
|
||||
}
|
||||
],
|
||||
"beforeMCPExecution": [
|
||||
{
|
||||
"command": "node .cursor/hooks/before-mcp-execution.js",
|
||||
"event": "beforeMCPExecution",
|
||||
"description": "MCP audit logging and untrusted server warning"
|
||||
}
|
||||
],
|
||||
"afterMCPExecution": [
|
||||
{
|
||||
"command": "node .cursor/hooks/after-mcp-execution.js",
|
||||
"event": "afterMCPExecution",
|
||||
"description": "MCP result logging"
|
||||
}
|
||||
],
|
||||
"beforeReadFile": [
|
||||
{
|
||||
"command": "node .cursor/hooks/before-read-file.js",
|
||||
"event": "beforeReadFile",
|
||||
"description": "Warn when reading sensitive files (.env, .key, .pem)"
|
||||
}
|
||||
],
|
||||
"beforeSubmitPrompt": [
|
||||
{
|
||||
"command": "node .cursor/hooks/before-submit-prompt.js",
|
||||
"event": "beforeSubmitPrompt",
|
||||
"description": "Detect secrets in prompts (sk-, ghp_, AKIA patterns)"
|
||||
}
|
||||
],
|
||||
"subagentStart": [
|
||||
{
|
||||
"command": "node .cursor/hooks/subagent-start.js",
|
||||
"event": "subagentStart",
|
||||
"description": "Log agent spawning for observability"
|
||||
}
|
||||
],
|
||||
"subagentStop": [
|
||||
{
|
||||
"command": "node .cursor/hooks/subagent-stop.js",
|
||||
"event": "subagentStop",
|
||||
"description": "Log agent completion"
|
||||
}
|
||||
],
|
||||
"beforeTabFileRead": [
|
||||
{
|
||||
"command": "node .cursor/hooks/before-tab-file-read.js",
|
||||
"event": "beforeTabFileRead",
|
||||
"description": "Block Tab from reading secrets (.env, .key, .pem, credentials)"
|
||||
}
|
||||
],
|
||||
"afterTabFileEdit": [
|
||||
{
|
||||
"command": "node .cursor/hooks/after-tab-file-edit.js",
|
||||
"event": "afterTabFileEdit",
|
||||
"description": "Auto-format Tab edits"
|
||||
}
|
||||
],
|
||||
"preCompact": [
|
||||
{
|
||||
"command": "node .cursor/hooks/pre-compact.js",
|
||||
"event": "preCompact",
|
||||
"description": "Save state before context compaction"
|
||||
}
|
||||
],
|
||||
"stop": [
|
||||
{
|
||||
"command": "node .cursor/hooks/stop.js",
|
||||
"event": "stop",
|
||||
"description": "Console.log audit on all modified files"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
62
.cursor/hooks/adapter.js
Normal file
62
.cursor/hooks/adapter.js
Normal file
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Cursor-to-Claude Code Hook Adapter
|
||||
* Transforms Cursor stdin JSON to Claude Code hook format,
|
||||
* then delegates to existing scripts/hooks/*.js
|
||||
*/
|
||||
|
||||
const { execFileSync } = require('child_process');
|
||||
const path = require('path');
|
||||
|
||||
const MAX_STDIN = 1024 * 1024;
|
||||
|
||||
function readStdin() {
|
||||
return new Promise((resolve) => {
|
||||
let data = '';
|
||||
process.stdin.setEncoding('utf8');
|
||||
process.stdin.on('data', chunk => {
|
||||
if (data.length < MAX_STDIN) data += chunk.substring(0, MAX_STDIN - data.length);
|
||||
});
|
||||
process.stdin.on('end', () => resolve(data));
|
||||
});
|
||||
}
|
||||
|
||||
function getPluginRoot() {
|
||||
return path.resolve(__dirname, '..', '..');
|
||||
}
|
||||
|
||||
function transformToClaude(cursorInput, overrides = {}) {
|
||||
return {
|
||||
tool_input: {
|
||||
command: cursorInput.command || cursorInput.args?.command || '',
|
||||
file_path: cursorInput.path || cursorInput.file || '',
|
||||
...overrides.tool_input,
|
||||
},
|
||||
tool_output: {
|
||||
output: cursorInput.output || cursorInput.result || '',
|
||||
...overrides.tool_output,
|
||||
},
|
||||
_cursor: {
|
||||
conversation_id: cursorInput.conversation_id,
|
||||
hook_event_name: cursorInput.hook_event_name,
|
||||
workspace_roots: cursorInput.workspace_roots,
|
||||
model: cursorInput.model,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function runExistingHook(scriptName, stdinData) {
|
||||
const scriptPath = path.join(getPluginRoot(), 'scripts', 'hooks', scriptName);
|
||||
try {
|
||||
execFileSync('node', [scriptPath], {
|
||||
input: typeof stdinData === 'string' ? stdinData : JSON.stringify(stdinData),
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
timeout: 15000,
|
||||
cwd: process.cwd(),
|
||||
});
|
||||
} catch (e) {
|
||||
if (e.status === 2) process.exit(2); // Forward blocking exit code
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { readStdin, getPluginRoot, transformToClaude, runExistingHook };
|
||||
17
.cursor/hooks/after-file-edit.js
Normal file
17
.cursor/hooks/after-file-edit.js
Normal file
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env node
|
||||
const { readStdin, runExistingHook, transformToClaude } = require('./adapter');
|
||||
readStdin().then(raw => {
|
||||
try {
|
||||
const input = JSON.parse(raw);
|
||||
const claudeInput = transformToClaude(input, {
|
||||
tool_input: { file_path: input.path || input.file || '' }
|
||||
});
|
||||
const claudeStr = JSON.stringify(claudeInput);
|
||||
|
||||
// Run format, typecheck, and console.log warning sequentially
|
||||
runExistingHook('post-edit-format.js', claudeStr);
|
||||
runExistingHook('post-edit-typecheck.js', claudeStr);
|
||||
runExistingHook('post-edit-console-warn.js', claudeStr);
|
||||
} catch {}
|
||||
process.stdout.write(raw);
|
||||
}).catch(() => process.exit(0));
|
||||
12
.cursor/hooks/after-mcp-execution.js
Normal file
12
.cursor/hooks/after-mcp-execution.js
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env node
|
||||
const { readStdin } = require('./adapter');
|
||||
readStdin().then(raw => {
|
||||
try {
|
||||
const input = JSON.parse(raw);
|
||||
const server = input.server || input.mcp_server || 'unknown';
|
||||
const tool = input.tool || input.mcp_tool || 'unknown';
|
||||
const success = input.error ? 'FAILED' : 'OK';
|
||||
console.error(`[ECC] MCP result: ${server}/${tool} - ${success}`);
|
||||
} catch {}
|
||||
process.stdout.write(raw);
|
||||
}).catch(() => process.exit(0));
|
||||
26
.cursor/hooks/after-shell-execution.js
Normal file
26
.cursor/hooks/after-shell-execution.js
Normal file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env node
|
||||
const { readStdin } = require('./adapter');
|
||||
readStdin().then(raw => {
|
||||
try {
|
||||
const input = JSON.parse(raw);
|
||||
const cmd = input.command || '';
|
||||
const output = input.output || input.result || '';
|
||||
|
||||
// PR creation logging
|
||||
if (/gh pr create/.test(cmd)) {
|
||||
const m = output.match(/https:\/\/github\.com\/[^/]+\/[^/]+\/pull\/\d+/);
|
||||
if (m) {
|
||||
console.error('[ECC] PR created: ' + m[0]);
|
||||
const repo = m[0].replace(/https:\/\/github\.com\/([^/]+\/[^/]+)\/pull\/\d+/, '$1');
|
||||
const pr = m[0].replace(/.+\/pull\/(\d+)/, '$1');
|
||||
console.error('[ECC] To review: gh pr review ' + pr + ' --repo ' + repo);
|
||||
}
|
||||
}
|
||||
|
||||
// Build completion notice
|
||||
if (/(npm run build|pnpm build|yarn build)/.test(cmd)) {
|
||||
console.error('[ECC] Build completed');
|
||||
}
|
||||
} catch {}
|
||||
process.stdout.write(raw);
|
||||
}).catch(() => process.exit(0));
|
||||
12
.cursor/hooks/after-tab-file-edit.js
Normal file
12
.cursor/hooks/after-tab-file-edit.js
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env node
|
||||
const { readStdin, runExistingHook, transformToClaude } = require('./adapter');
|
||||
readStdin().then(raw => {
|
||||
try {
|
||||
const input = JSON.parse(raw);
|
||||
const claudeInput = transformToClaude(input, {
|
||||
tool_input: { file_path: input.path || input.file || '' }
|
||||
});
|
||||
runExistingHook('post-edit-format.js', JSON.stringify(claudeInput));
|
||||
} catch {}
|
||||
process.stdout.write(raw);
|
||||
}).catch(() => process.exit(0));
|
||||
11
.cursor/hooks/before-mcp-execution.js
Normal file
11
.cursor/hooks/before-mcp-execution.js
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env node
|
||||
const { readStdin } = require('./adapter');
|
||||
readStdin().then(raw => {
|
||||
try {
|
||||
const input = JSON.parse(raw);
|
||||
const server = input.server || input.mcp_server || 'unknown';
|
||||
const tool = input.tool || input.mcp_tool || 'unknown';
|
||||
console.error(`[ECC] MCP invocation: ${server}/${tool}`);
|
||||
} catch {}
|
||||
process.stdout.write(raw);
|
||||
}).catch(() => process.exit(0));
|
||||
13
.cursor/hooks/before-read-file.js
Normal file
13
.cursor/hooks/before-read-file.js
Normal file
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env node
|
||||
const { readStdin } = require('./adapter');
|
||||
readStdin().then(raw => {
|
||||
try {
|
||||
const input = JSON.parse(raw);
|
||||
const filePath = input.path || input.file || '';
|
||||
if (/\.(env|key|pem)$|\.env\.|credentials|secret/i.test(filePath)) {
|
||||
console.error('[ECC] WARNING: Reading sensitive file: ' + filePath);
|
||||
console.error('[ECC] Ensure this data is not exposed in outputs');
|
||||
}
|
||||
} catch {}
|
||||
process.stdout.write(raw);
|
||||
}).catch(() => process.exit(0));
|
||||
27
.cursor/hooks/before-shell-execution.js
Normal file
27
.cursor/hooks/before-shell-execution.js
Normal file
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env node
|
||||
const { readStdin } = require('./adapter');
|
||||
readStdin().then(raw => {
|
||||
try {
|
||||
const input = JSON.parse(raw);
|
||||
const cmd = input.command || '';
|
||||
|
||||
// 1. Block dev server outside tmux
|
||||
if (process.platform !== 'win32' && /(npm run dev\b|pnpm( run)? dev\b|yarn dev\b|bun run dev\b)/.test(cmd)) {
|
||||
console.error('[ECC] BLOCKED: Dev server must run in tmux for log access');
|
||||
console.error('[ECC] Use: tmux new-session -d -s dev "npm run dev"');
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
// 2. Tmux reminder for long-running commands
|
||||
if (process.platform !== 'win32' && !process.env.TMUX &&
|
||||
/(npm (install|test)|pnpm (install|test)|yarn (install|test)?|bun (install|test)|cargo build|make\b|docker\b|pytest|vitest|playwright)/.test(cmd)) {
|
||||
console.error('[ECC] Consider running in tmux for session persistence');
|
||||
}
|
||||
|
||||
// 3. Git push review reminder
|
||||
if (/git push/.test(cmd)) {
|
||||
console.error('[ECC] Review changes before push: git diff origin/main...HEAD');
|
||||
}
|
||||
} catch {}
|
||||
process.stdout.write(raw);
|
||||
}).catch(() => process.exit(0));
|
||||
23
.cursor/hooks/before-submit-prompt.js
Normal file
23
.cursor/hooks/before-submit-prompt.js
Normal file
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env node
|
||||
const { readStdin } = require('./adapter');
|
||||
readStdin().then(raw => {
|
||||
try {
|
||||
const input = JSON.parse(raw);
|
||||
const prompt = input.prompt || input.content || input.message || '';
|
||||
const secretPatterns = [
|
||||
/sk-[a-zA-Z0-9]{20,}/, // OpenAI API keys
|
||||
/ghp_[a-zA-Z0-9]{36,}/, // GitHub personal access tokens
|
||||
/AKIA[A-Z0-9]{16}/, // AWS access keys
|
||||
/xox[bpsa]-[a-zA-Z0-9-]+/, // Slack tokens
|
||||
/-----BEGIN (RSA |EC )?PRIVATE KEY-----/, // Private keys
|
||||
];
|
||||
for (const pattern of secretPatterns) {
|
||||
if (pattern.test(prompt)) {
|
||||
console.error('[ECC] WARNING: Potential secret detected in prompt!');
|
||||
console.error('[ECC] Remove secrets before submitting. Use environment variables instead.');
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
process.stdout.write(raw);
|
||||
}).catch(() => process.exit(0));
|
||||
13
.cursor/hooks/before-tab-file-read.js
Normal file
13
.cursor/hooks/before-tab-file-read.js
Normal file
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env node
|
||||
const { readStdin } = require('./adapter');
|
||||
readStdin().then(raw => {
|
||||
try {
|
||||
const input = JSON.parse(raw);
|
||||
const filePath = input.path || input.file || '';
|
||||
if (/\.(env|key|pem)$|\.env\.|credentials|secret/i.test(filePath)) {
|
||||
console.error('[ECC] BLOCKED: Tab cannot read sensitive file: ' + filePath);
|
||||
process.exit(2);
|
||||
}
|
||||
} catch {}
|
||||
process.stdout.write(raw);
|
||||
}).catch(() => process.exit(0));
|
||||
7
.cursor/hooks/pre-compact.js
Normal file
7
.cursor/hooks/pre-compact.js
Normal file
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env node
|
||||
const { readStdin, runExistingHook, transformToClaude } = require('./adapter');
|
||||
readStdin().then(raw => {
|
||||
const claudeInput = JSON.parse(raw || '{}');
|
||||
runExistingHook('pre-compact.js', transformToClaude(claudeInput));
|
||||
process.stdout.write(raw);
|
||||
}).catch(() => process.exit(0));
|
||||
9
.cursor/hooks/session-end.js
Normal file
9
.cursor/hooks/session-end.js
Normal file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env node
|
||||
const { readStdin, runExistingHook, transformToClaude } = require('./adapter');
|
||||
readStdin().then(raw => {
|
||||
const input = JSON.parse(raw);
|
||||
const claudeInput = transformToClaude(input);
|
||||
runExistingHook('session-end.js', claudeInput);
|
||||
runExistingHook('evaluate-session.js', claudeInput);
|
||||
process.stdout.write(raw);
|
||||
}).catch(() => process.exit(0));
|
||||
8
.cursor/hooks/session-start.js
Normal file
8
.cursor/hooks/session-start.js
Normal file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env node
|
||||
const { readStdin, runExistingHook, transformToClaude } = require('./adapter');
|
||||
readStdin().then(raw => {
|
||||
const input = JSON.parse(raw);
|
||||
const claudeInput = transformToClaude(input);
|
||||
runExistingHook('session-start.js', claudeInput);
|
||||
process.stdout.write(raw);
|
||||
}).catch(() => process.exit(0));
|
||||
7
.cursor/hooks/stop.js
Normal file
7
.cursor/hooks/stop.js
Normal file
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env node
|
||||
const { readStdin, runExistingHook, transformToClaude } = require('./adapter');
|
||||
readStdin().then(raw => {
|
||||
const claudeInput = JSON.parse(raw || '{}');
|
||||
runExistingHook('check-console-log.js', transformToClaude(claudeInput));
|
||||
process.stdout.write(raw);
|
||||
}).catch(() => process.exit(0));
|
||||
10
.cursor/hooks/subagent-start.js
Normal file
10
.cursor/hooks/subagent-start.js
Normal file
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env node
|
||||
const { readStdin } = require('./adapter');
|
||||
readStdin().then(raw => {
|
||||
try {
|
||||
const input = JSON.parse(raw);
|
||||
const agent = input.agent_name || input.agent || 'unknown';
|
||||
console.error(`[ECC] Agent spawned: ${agent}`);
|
||||
} catch {}
|
||||
process.stdout.write(raw);
|
||||
}).catch(() => process.exit(0));
|
||||
10
.cursor/hooks/subagent-stop.js
Normal file
10
.cursor/hooks/subagent-stop.js
Normal file
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env node
|
||||
const { readStdin } = require('./adapter');
|
||||
readStdin().then(raw => {
|
||||
try {
|
||||
const input = JSON.parse(raw);
|
||||
const agent = input.agent_name || input.agent || 'unknown';
|
||||
console.error(`[ECC] Agent completed: ${agent}`);
|
||||
} catch {}
|
||||
process.stdout.write(raw);
|
||||
}).catch(() => process.exit(0));
|
||||
53
.cursor/rules/common-agents.md
Normal file
53
.cursor/rules/common-agents.md
Normal file
@@ -0,0 +1,53 @@
|
||||
---
|
||||
description: "Agent orchestration: available agents, parallel execution, multi-perspective analysis"
|
||||
alwaysApply: true
|
||||
---
|
||||
# Agent Orchestration
|
||||
|
||||
## Available Agents
|
||||
|
||||
Located in `~/.claude/agents/`:
|
||||
|
||||
| Agent | Purpose | When to Use |
|
||||
|-------|---------|-------------|
|
||||
| planner | Implementation planning | Complex features, refactoring |
|
||||
| architect | System design | Architectural decisions |
|
||||
| tdd-guide | Test-driven development | New features, bug fixes |
|
||||
| code-reviewer | Code review | After writing code |
|
||||
| security-reviewer | Security analysis | Before commits |
|
||||
| build-error-resolver | Fix build errors | When build fails |
|
||||
| e2e-runner | E2E testing | Critical user flows |
|
||||
| refactor-cleaner | Dead code cleanup | Code maintenance |
|
||||
| doc-updater | Documentation | Updating docs |
|
||||
|
||||
## Immediate Agent Usage
|
||||
|
||||
No user prompt needed:
|
||||
1. Complex feature requests - Use **planner** agent
|
||||
2. Code just written/modified - Use **code-reviewer** agent
|
||||
3. Bug fix or new feature - Use **tdd-guide** agent
|
||||
4. Architectural decision - Use **architect** agent
|
||||
|
||||
## Parallel Task Execution
|
||||
|
||||
ALWAYS use parallel Task execution for independent operations:
|
||||
|
||||
```markdown
|
||||
# GOOD: Parallel execution
|
||||
Launch 3 agents in parallel:
|
||||
1. Agent 1: Security analysis of auth module
|
||||
2. Agent 2: Performance review of cache system
|
||||
3. Agent 3: Type checking of utilities
|
||||
|
||||
# BAD: Sequential when unnecessary
|
||||
First agent 1, then agent 2, then agent 3
|
||||
```
|
||||
|
||||
## Multi-Perspective Analysis
|
||||
|
||||
For complex problems, use split role sub-agents:
|
||||
- Factual reviewer
|
||||
- Senior engineer
|
||||
- Security expert
|
||||
- Consistency reviewer
|
||||
- Redundancy checker
|
||||
52
.cursor/rules/common-coding-style.md
Normal file
52
.cursor/rules/common-coding-style.md
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
description: "ECC coding style: immutability, file organization, error handling, validation"
|
||||
alwaysApply: true
|
||||
---
|
||||
# Coding Style
|
||||
|
||||
## Immutability (CRITICAL)
|
||||
|
||||
ALWAYS create new objects, NEVER mutate existing ones:
|
||||
|
||||
```
|
||||
// Pseudocode
|
||||
WRONG: modify(original, field, value) → changes original in-place
|
||||
CORRECT: update(original, field, value) → returns new copy with change
|
||||
```
|
||||
|
||||
Rationale: Immutable data prevents hidden side effects, makes debugging easier, and enables safe concurrency.
|
||||
|
||||
## File Organization
|
||||
|
||||
MANY SMALL FILES > FEW LARGE FILES:
|
||||
- High cohesion, low coupling
|
||||
- 200-400 lines typical, 800 max
|
||||
- Extract utilities from large modules
|
||||
- Organize by feature/domain, not by type
|
||||
|
||||
## Error Handling
|
||||
|
||||
ALWAYS handle errors comprehensively:
|
||||
- Handle errors explicitly at every level
|
||||
- Provide user-friendly error messages in UI-facing code
|
||||
- Log detailed error context on the server side
|
||||
- Never silently swallow errors
|
||||
|
||||
## Input Validation
|
||||
|
||||
ALWAYS validate at system boundaries:
|
||||
- Validate all user input before processing
|
||||
- Use schema-based validation where available
|
||||
- Fail fast with clear error messages
|
||||
- Never trust external data (API responses, user input, file content)
|
||||
|
||||
## Code Quality Checklist
|
||||
|
||||
Before marking work complete:
|
||||
- [ ] Code is readable and well-named
|
||||
- [ ] Functions are small (<50 lines)
|
||||
- [ ] Files are focused (<800 lines)
|
||||
- [ ] No deep nesting (>4 levels)
|
||||
- [ ] Proper error handling
|
||||
- [ ] No hardcoded values (use constants or config)
|
||||
- [ ] No mutation (immutable patterns used)
|
||||
33
.cursor/rules/common-development-workflow.md
Normal file
33
.cursor/rules/common-development-workflow.md
Normal file
@@ -0,0 +1,33 @@
|
||||
---
|
||||
description: "Development workflow: plan, TDD, review, commit pipeline"
|
||||
alwaysApply: true
|
||||
---
|
||||
# Development Workflow
|
||||
|
||||
> This rule extends the git workflow rule with the full feature development process that happens before git operations.
|
||||
|
||||
The Feature Implementation Workflow describes the development pipeline: planning, TDD, code review, and then committing to git.
|
||||
|
||||
## Feature Implementation Workflow
|
||||
|
||||
1. **Plan First**
|
||||
- Use **planner** agent to create implementation plan
|
||||
- Identify dependencies and risks
|
||||
- Break down into phases
|
||||
|
||||
2. **TDD Approach**
|
||||
- Use **tdd-guide** agent
|
||||
- Write tests first (RED)
|
||||
- Implement to pass tests (GREEN)
|
||||
- Refactor (IMPROVE)
|
||||
- Verify 80%+ coverage
|
||||
|
||||
3. **Code Review**
|
||||
- Use **code-reviewer** agent immediately after writing code
|
||||
- Address CRITICAL and HIGH issues
|
||||
- Fix MEDIUM issues when possible
|
||||
|
||||
4. **Commit & Push**
|
||||
- Detailed commit messages
|
||||
- Follow conventional commits format
|
||||
- See the git workflow rule for commit message format and PR process
|
||||
28
.cursor/rules/common-git-workflow.md
Normal file
28
.cursor/rules/common-git-workflow.md
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
description: "Git workflow: conventional commits, PR process"
|
||||
alwaysApply: true
|
||||
---
|
||||
# Git Workflow
|
||||
|
||||
## Commit Message Format
|
||||
```
|
||||
<type>: <description>
|
||||
|
||||
<optional body>
|
||||
```
|
||||
|
||||
Types: feat, fix, refactor, docs, test, chore, perf, ci
|
||||
|
||||
Note: Attribution disabled globally via ~/.claude/settings.json.
|
||||
|
||||
## Pull Request Workflow
|
||||
|
||||
When creating PRs:
|
||||
1. Analyze full commit history (not just latest commit)
|
||||
2. Use `git diff [base-branch]...HEAD` to see all changes
|
||||
3. Draft comprehensive PR summary
|
||||
4. Include test plan with TODOs
|
||||
5. Push with `-u` flag if new branch
|
||||
|
||||
> For the full development process (planning, TDD, code review) before git operations,
|
||||
> see the development workflow rule.
|
||||
34
.cursor/rules/common-hooks.md
Normal file
34
.cursor/rules/common-hooks.md
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
description: "Hooks system: types, auto-accept permissions, TodoWrite best practices"
|
||||
alwaysApply: true
|
||||
---
|
||||
# Hooks System
|
||||
|
||||
## Hook Types
|
||||
|
||||
- **PreToolUse**: Before tool execution (validation, parameter modification)
|
||||
- **PostToolUse**: After tool execution (auto-format, checks)
|
||||
- **Stop**: When session ends (final verification)
|
||||
|
||||
## Auto-Accept Permissions
|
||||
|
||||
Use with caution:
|
||||
- Enable for trusted, well-defined plans
|
||||
- Disable for exploratory work
|
||||
- Never use dangerously-skip-permissions flag
|
||||
- Configure `allowedTools` in `~/.claude.json` instead
|
||||
|
||||
## TodoWrite Best Practices
|
||||
|
||||
Use TodoWrite tool to:
|
||||
- Track progress on multi-step tasks
|
||||
- Verify understanding of instructions
|
||||
- Enable real-time steering
|
||||
- Show granular implementation steps
|
||||
|
||||
Todo list reveals:
|
||||
- Out of order steps
|
||||
- Missing items
|
||||
- Extra unnecessary items
|
||||
- Wrong granularity
|
||||
- Misinterpreted requirements
|
||||
35
.cursor/rules/common-patterns.md
Normal file
35
.cursor/rules/common-patterns.md
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
description: "Common patterns: repository, API response, skeleton projects"
|
||||
alwaysApply: true
|
||||
---
|
||||
# Common Patterns
|
||||
|
||||
## Skeleton Projects
|
||||
|
||||
When implementing new functionality:
|
||||
1. Search for battle-tested skeleton projects
|
||||
2. Use parallel agents to evaluate options:
|
||||
- Security assessment
|
||||
- Extensibility analysis
|
||||
- Relevance scoring
|
||||
- Implementation planning
|
||||
3. Clone best match as foundation
|
||||
4. Iterate within proven structure
|
||||
|
||||
## Design Patterns
|
||||
|
||||
### Repository Pattern
|
||||
|
||||
Encapsulate data access behind a consistent interface:
|
||||
- Define standard operations: findAll, findById, create, update, delete
|
||||
- Concrete implementations handle storage details (database, API, file, etc.)
|
||||
- Business logic depends on the abstract interface, not the storage mechanism
|
||||
- Enables easy swapping of data sources and simplifies testing with mocks
|
||||
|
||||
### API Response Format
|
||||
|
||||
Use a consistent envelope for all API responses:
|
||||
- Include a success/status indicator
|
||||
- Include the data payload (nullable on error)
|
||||
- Include an error message field (nullable on success)
|
||||
- Include metadata for paginated responses (total, page, limit)
|
||||
59
.cursor/rules/common-performance.md
Normal file
59
.cursor/rules/common-performance.md
Normal file
@@ -0,0 +1,59 @@
|
||||
---
|
||||
description: "Performance: model selection, context management, build troubleshooting"
|
||||
alwaysApply: true
|
||||
---
|
||||
# Performance Optimization
|
||||
|
||||
## Model Selection Strategy
|
||||
|
||||
**Haiku 4.5** (90% of Sonnet capability, 3x cost savings):
|
||||
- Lightweight agents with frequent invocation
|
||||
- Pair programming and code generation
|
||||
- Worker agents in multi-agent systems
|
||||
|
||||
**Sonnet 4.6** (Best coding model):
|
||||
- Main development work
|
||||
- Orchestrating multi-agent workflows
|
||||
- Complex coding tasks
|
||||
|
||||
**Opus 4.5** (Deepest reasoning):
|
||||
- Complex architectural decisions
|
||||
- Maximum reasoning requirements
|
||||
- Research and analysis tasks
|
||||
|
||||
## Context Window Management
|
||||
|
||||
Avoid last 20% of context window for:
|
||||
- Large-scale refactoring
|
||||
- Feature implementation spanning multiple files
|
||||
- Debugging complex interactions
|
||||
|
||||
Lower context sensitivity tasks:
|
||||
- Single-file edits
|
||||
- Independent utility creation
|
||||
- Documentation updates
|
||||
- Simple bug fixes
|
||||
|
||||
## Extended Thinking + Plan Mode
|
||||
|
||||
Extended thinking is enabled by default, reserving up to 31,999 tokens for internal reasoning.
|
||||
|
||||
Control extended thinking via:
|
||||
- **Toggle**: Option+T (macOS) / Alt+T (Windows/Linux)
|
||||
- **Config**: Set `alwaysThinkingEnabled` in `~/.claude/settings.json`
|
||||
- **Budget cap**: `export MAX_THINKING_TOKENS=10000`
|
||||
- **Verbose mode**: Ctrl+O to see thinking output
|
||||
|
||||
For complex tasks requiring deep reasoning:
|
||||
1. Ensure extended thinking is enabled (on by default)
|
||||
2. Enable **Plan Mode** for structured approach
|
||||
3. Use multiple critique rounds for thorough analysis
|
||||
4. Use split role sub-agents for diverse perspectives
|
||||
|
||||
## Build Troubleshooting
|
||||
|
||||
If build fails:
|
||||
1. Use **build-error-resolver** agent
|
||||
2. Analyze error messages
|
||||
3. Fix incrementally
|
||||
4. Verify after each fix
|
||||
33
.cursor/rules/common-security.md
Normal file
33
.cursor/rules/common-security.md
Normal file
@@ -0,0 +1,33 @@
|
||||
---
|
||||
description: "Security: mandatory checks, secret management, response protocol"
|
||||
alwaysApply: true
|
||||
---
|
||||
# Security Guidelines
|
||||
|
||||
## Mandatory Security Checks
|
||||
|
||||
Before ANY commit:
|
||||
- [ ] No hardcoded secrets (API keys, passwords, tokens)
|
||||
- [ ] All user inputs validated
|
||||
- [ ] SQL injection prevention (parameterized queries)
|
||||
- [ ] XSS prevention (sanitized HTML)
|
||||
- [ ] CSRF protection enabled
|
||||
- [ ] Authentication/authorization verified
|
||||
- [ ] Rate limiting on all endpoints
|
||||
- [ ] Error messages don't leak sensitive data
|
||||
|
||||
## Secret Management
|
||||
|
||||
- NEVER hardcode secrets in source code
|
||||
- ALWAYS use environment variables or a secret manager
|
||||
- Validate that required secrets are present at startup
|
||||
- Rotate any secrets that may have been exposed
|
||||
|
||||
## Security Response Protocol
|
||||
|
||||
If security issue found:
|
||||
1. STOP immediately
|
||||
2. Use **security-reviewer** agent
|
||||
3. Fix CRITICAL issues before continuing
|
||||
4. Rotate any exposed secrets
|
||||
5. Review entire codebase for similar issues
|
||||
33
.cursor/rules/common-testing.md
Normal file
33
.cursor/rules/common-testing.md
Normal file
@@ -0,0 +1,33 @@
|
||||
---
|
||||
description: "Testing requirements: 80% coverage, TDD workflow, test types"
|
||||
alwaysApply: true
|
||||
---
|
||||
# Testing Requirements
|
||||
|
||||
## Minimum Test Coverage: 80%
|
||||
|
||||
Test Types (ALL required):
|
||||
1. **Unit Tests** - Individual functions, utilities, components
|
||||
2. **Integration Tests** - API endpoints, database operations
|
||||
3. **E2E Tests** - Critical user flows (framework chosen per language)
|
||||
|
||||
## Test-Driven Development
|
||||
|
||||
MANDATORY workflow:
|
||||
1. Write test first (RED)
|
||||
2. Run test - it should FAIL
|
||||
3. Write minimal implementation (GREEN)
|
||||
4. Run test - it should PASS
|
||||
5. Refactor (IMPROVE)
|
||||
6. Verify coverage (80%+)
|
||||
|
||||
## Troubleshooting Test Failures
|
||||
|
||||
1. Use **tdd-guide** agent
|
||||
2. Check test isolation
|
||||
3. Verify mocks are correct
|
||||
4. Fix implementation, not tests (unless tests are wrong)
|
||||
|
||||
## Agent Support
|
||||
|
||||
- **tdd-guide** - Use PROACTIVELY for new features, enforces write-tests-first
|
||||
31
.cursor/rules/golang-coding-style.md
Normal file
31
.cursor/rules/golang-coding-style.md
Normal file
@@ -0,0 +1,31 @@
|
||||
---
|
||||
description: "Go coding style extending common rules"
|
||||
globs: ["**/*.go", "**/go.mod", "**/go.sum"]
|
||||
alwaysApply: false
|
||||
---
|
||||
# Go Coding Style
|
||||
|
||||
> This file extends the common coding style rule with Go specific content.
|
||||
|
||||
## Formatting
|
||||
|
||||
- **gofmt** and **goimports** are mandatory -- no style debates
|
||||
|
||||
## Design Principles
|
||||
|
||||
- Accept interfaces, return structs
|
||||
- Keep interfaces small (1-3 methods)
|
||||
|
||||
## Error Handling
|
||||
|
||||
Always wrap errors with context:
|
||||
|
||||
```go
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create user: %w", err)
|
||||
}
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
See skill: `golang-patterns` for comprehensive Go idioms and patterns.
|
||||
16
.cursor/rules/golang-hooks.md
Normal file
16
.cursor/rules/golang-hooks.md
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
description: "Go hooks extending common rules"
|
||||
globs: ["**/*.go", "**/go.mod", "**/go.sum"]
|
||||
alwaysApply: false
|
||||
---
|
||||
# Go Hooks
|
||||
|
||||
> This file extends the common hooks rule with Go specific content.
|
||||
|
||||
## PostToolUse Hooks
|
||||
|
||||
Configure in `~/.claude/settings.json`:
|
||||
|
||||
- **gofmt/goimports**: Auto-format `.go` files after edit
|
||||
- **go vet**: Run static analysis after editing `.go` files
|
||||
- **staticcheck**: Run extended static checks on modified packages
|
||||
44
.cursor/rules/golang-patterns.md
Normal file
44
.cursor/rules/golang-patterns.md
Normal file
@@ -0,0 +1,44 @@
|
||||
---
|
||||
description: "Go patterns extending common rules"
|
||||
globs: ["**/*.go", "**/go.mod", "**/go.sum"]
|
||||
alwaysApply: false
|
||||
---
|
||||
# Go Patterns
|
||||
|
||||
> This file extends the common patterns rule with Go specific content.
|
||||
|
||||
## Functional Options
|
||||
|
||||
```go
|
||||
type Option func(*Server)
|
||||
|
||||
func WithPort(port int) Option {
|
||||
return func(s *Server) { s.port = port }
|
||||
}
|
||||
|
||||
func NewServer(opts ...Option) *Server {
|
||||
s := &Server{port: 8080}
|
||||
for _, opt := range opts {
|
||||
opt(s)
|
||||
}
|
||||
return s
|
||||
}
|
||||
```
|
||||
|
||||
## Small Interfaces
|
||||
|
||||
Define interfaces where they are used, not where they are implemented.
|
||||
|
||||
## Dependency Injection
|
||||
|
||||
Use constructor functions to inject dependencies:
|
||||
|
||||
```go
|
||||
func NewUserService(repo UserRepository, logger Logger) *UserService {
|
||||
return &UserService{repo: repo, logger: logger}
|
||||
}
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
See skill: `golang-patterns` for comprehensive Go patterns including concurrency, error handling, and package organization.
|
||||
33
.cursor/rules/golang-security.md
Normal file
33
.cursor/rules/golang-security.md
Normal file
@@ -0,0 +1,33 @@
|
||||
---
|
||||
description: "Go security extending common rules"
|
||||
globs: ["**/*.go", "**/go.mod", "**/go.sum"]
|
||||
alwaysApply: false
|
||||
---
|
||||
# Go Security
|
||||
|
||||
> This file extends the common security rule with Go specific content.
|
||||
|
||||
## Secret Management
|
||||
|
||||
```go
|
||||
apiKey := os.Getenv("OPENAI_API_KEY")
|
||||
if apiKey == "" {
|
||||
log.Fatal("OPENAI_API_KEY not configured")
|
||||
}
|
||||
```
|
||||
|
||||
## Security Scanning
|
||||
|
||||
- Use **gosec** for static security analysis:
|
||||
```bash
|
||||
gosec ./...
|
||||
```
|
||||
|
||||
## Context & Timeouts
|
||||
|
||||
Always use `context.Context` for timeout control:
|
||||
|
||||
```go
|
||||
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
```
|
||||
30
.cursor/rules/golang-testing.md
Normal file
30
.cursor/rules/golang-testing.md
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
description: "Go testing extending common rules"
|
||||
globs: ["**/*.go", "**/go.mod", "**/go.sum"]
|
||||
alwaysApply: false
|
||||
---
|
||||
# Go Testing
|
||||
|
||||
> This file extends the common testing rule with Go specific content.
|
||||
|
||||
## Framework
|
||||
|
||||
Use the standard `go test` with **table-driven tests**.
|
||||
|
||||
## Race Detection
|
||||
|
||||
Always run with the `-race` flag:
|
||||
|
||||
```bash
|
||||
go test -race ./...
|
||||
```
|
||||
|
||||
## Coverage
|
||||
|
||||
```bash
|
||||
go test -cover ./...
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
See skill: `golang-testing` for detailed Go testing patterns and helpers.
|
||||
42
.cursor/rules/python-coding-style.md
Normal file
42
.cursor/rules/python-coding-style.md
Normal file
@@ -0,0 +1,42 @@
|
||||
---
|
||||
description: "Python coding style extending common rules"
|
||||
globs: ["**/*.py", "**/*.pyi"]
|
||||
alwaysApply: false
|
||||
---
|
||||
# Python Coding Style
|
||||
|
||||
> This file extends the common coding style rule with Python specific content.
|
||||
|
||||
## Standards
|
||||
|
||||
- Follow **PEP 8** conventions
|
||||
- Use **type annotations** on all function signatures
|
||||
|
||||
## Immutability
|
||||
|
||||
Prefer immutable data structures:
|
||||
|
||||
```python
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class User:
|
||||
name: str
|
||||
email: str
|
||||
|
||||
from typing import NamedTuple
|
||||
|
||||
class Point(NamedTuple):
|
||||
x: float
|
||||
y: float
|
||||
```
|
||||
|
||||
## Formatting
|
||||
|
||||
- **black** for code formatting
|
||||
- **isort** for import sorting
|
||||
- **ruff** for linting
|
||||
|
||||
## Reference
|
||||
|
||||
See skill: `python-patterns` for comprehensive Python idioms and patterns.
|
||||
19
.cursor/rules/python-hooks.md
Normal file
19
.cursor/rules/python-hooks.md
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
description: "Python hooks extending common rules"
|
||||
globs: ["**/*.py", "**/*.pyi"]
|
||||
alwaysApply: false
|
||||
---
|
||||
# Python Hooks
|
||||
|
||||
> This file extends the common hooks rule with Python specific content.
|
||||
|
||||
## PostToolUse Hooks
|
||||
|
||||
Configure in `~/.claude/settings.json`:
|
||||
|
||||
- **black/ruff**: Auto-format `.py` files after edit
|
||||
- **mypy/pyright**: Run type checking after editing `.py` files
|
||||
|
||||
## Warnings
|
||||
|
||||
- Warn about `print()` statements in edited files (use `logging` module instead)
|
||||
39
.cursor/rules/python-patterns.md
Normal file
39
.cursor/rules/python-patterns.md
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
description: "Python patterns extending common rules"
|
||||
globs: ["**/*.py", "**/*.pyi"]
|
||||
alwaysApply: false
|
||||
---
|
||||
# Python Patterns
|
||||
|
||||
> This file extends the common patterns rule with Python specific content.
|
||||
|
||||
## Protocol (Duck Typing)
|
||||
|
||||
```python
|
||||
from typing import Protocol
|
||||
|
||||
class Repository(Protocol):
|
||||
def find_by_id(self, id: str) -> dict | None: ...
|
||||
def save(self, entity: dict) -> dict: ...
|
||||
```
|
||||
|
||||
## Dataclasses as DTOs
|
||||
|
||||
```python
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass
|
||||
class CreateUserRequest:
|
||||
name: str
|
||||
email: str
|
||||
age: int | None = None
|
||||
```
|
||||
|
||||
## Context Managers & Generators
|
||||
|
||||
- Use context managers (`with` statement) for resource management
|
||||
- Use generators for lazy evaluation and memory-efficient iteration
|
||||
|
||||
## Reference
|
||||
|
||||
See skill: `python-patterns` for comprehensive patterns including decorators, concurrency, and package organization.
|
||||
30
.cursor/rules/python-security.md
Normal file
30
.cursor/rules/python-security.md
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
description: "Python security extending common rules"
|
||||
globs: ["**/*.py", "**/*.pyi"]
|
||||
alwaysApply: false
|
||||
---
|
||||
# Python Security
|
||||
|
||||
> This file extends the common security rule with Python specific content.
|
||||
|
||||
## Secret Management
|
||||
|
||||
```python
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
api_key = os.environ["OPENAI_API_KEY"] # Raises KeyError if missing
|
||||
```
|
||||
|
||||
## Security Scanning
|
||||
|
||||
- Use **bandit** for static security analysis:
|
||||
```bash
|
||||
bandit -r src/
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
See skill: `django-security` for Django-specific security guidelines (if applicable).
|
||||
38
.cursor/rules/python-testing.md
Normal file
38
.cursor/rules/python-testing.md
Normal file
@@ -0,0 +1,38 @@
|
||||
---
|
||||
description: "Python testing extending common rules"
|
||||
globs: ["**/*.py", "**/*.pyi"]
|
||||
alwaysApply: false
|
||||
---
|
||||
# Python Testing
|
||||
|
||||
> This file extends the common testing rule with Python specific content.
|
||||
|
||||
## Framework
|
||||
|
||||
Use **pytest** as the testing framework.
|
||||
|
||||
## Coverage
|
||||
|
||||
```bash
|
||||
pytest --cov=src --cov-report=term-missing
|
||||
```
|
||||
|
||||
## Test Organization
|
||||
|
||||
Use `pytest.mark` for test categorization:
|
||||
|
||||
```python
|
||||
import pytest
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_calculate_total():
|
||||
...
|
||||
|
||||
@pytest.mark.integration
|
||||
def test_database_connection():
|
||||
...
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
See skill: `python-testing` for detailed pytest patterns and fixtures.
|
||||
47
.cursor/rules/swift-coding-style.md
Normal file
47
.cursor/rules/swift-coding-style.md
Normal file
@@ -0,0 +1,47 @@
|
||||
---
|
||||
description: "Swift coding style extending common rules"
|
||||
globs: ["**/*.swift", "**/Package.swift"]
|
||||
alwaysApply: false
|
||||
---
|
||||
# Swift Coding Style
|
||||
|
||||
> This file extends the common coding style rule with Swift specific content.
|
||||
|
||||
## Formatting
|
||||
|
||||
- **SwiftFormat** for auto-formatting, **SwiftLint** for style enforcement
|
||||
- `swift-format` is bundled with Xcode 16+ as an alternative
|
||||
|
||||
## Immutability
|
||||
|
||||
- Prefer `let` over `var` -- define everything as `let` and only change to `var` if the compiler requires it
|
||||
- Use `struct` with value semantics by default; use `class` only when identity or reference semantics are needed
|
||||
|
||||
## Naming
|
||||
|
||||
Follow [Apple API Design Guidelines](https://www.swift.org/documentation/api-design-guidelines/):
|
||||
|
||||
- Clarity at the point of use -- omit needless words
|
||||
- Name methods and properties for their roles, not their types
|
||||
- Use `static let` for constants over global constants
|
||||
|
||||
## Error Handling
|
||||
|
||||
Use typed throws (Swift 6+) and pattern matching:
|
||||
|
||||
```swift
|
||||
func load(id: String) throws(LoadError) -> Item {
|
||||
guard let data = try? read(from: path) else {
|
||||
throw .fileNotFound(id)
|
||||
}
|
||||
return try decode(data)
|
||||
}
|
||||
```
|
||||
|
||||
## Concurrency
|
||||
|
||||
Enable Swift 6 strict concurrency checking. Prefer:
|
||||
|
||||
- `Sendable` value types for data crossing isolation boundaries
|
||||
- Actors for shared mutable state
|
||||
- Structured concurrency (`async let`, `TaskGroup`) over unstructured `Task {}`
|
||||
20
.cursor/rules/swift-hooks.md
Normal file
20
.cursor/rules/swift-hooks.md
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
description: "Swift hooks extending common rules"
|
||||
globs: ["**/*.swift", "**/Package.swift"]
|
||||
alwaysApply: false
|
||||
---
|
||||
# Swift Hooks
|
||||
|
||||
> This file extends the common hooks rule with Swift specific content.
|
||||
|
||||
## PostToolUse Hooks
|
||||
|
||||
Configure in `~/.claude/settings.json`:
|
||||
|
||||
- **SwiftFormat**: Auto-format `.swift` files after edit
|
||||
- **SwiftLint**: Run lint checks after editing `.swift` files
|
||||
- **swift build**: Type-check modified packages after edit
|
||||
|
||||
## Warning
|
||||
|
||||
Flag `print()` statements -- use `os.Logger` or structured logging instead for production code.
|
||||
66
.cursor/rules/swift-patterns.md
Normal file
66
.cursor/rules/swift-patterns.md
Normal file
@@ -0,0 +1,66 @@
|
||||
---
|
||||
description: "Swift patterns extending common rules"
|
||||
globs: ["**/*.swift", "**/Package.swift"]
|
||||
alwaysApply: false
|
||||
---
|
||||
# Swift Patterns
|
||||
|
||||
> This file extends the common patterns rule with Swift specific content.
|
||||
|
||||
## Protocol-Oriented Design
|
||||
|
||||
Define small, focused protocols. Use protocol extensions for shared defaults:
|
||||
|
||||
```swift
|
||||
protocol Repository: Sendable {
|
||||
associatedtype Item: Identifiable & Sendable
|
||||
func find(by id: Item.ID) async throws -> Item?
|
||||
func save(_ item: Item) async throws
|
||||
}
|
||||
```
|
||||
|
||||
## Value Types
|
||||
|
||||
- Use structs for data transfer objects and models
|
||||
- Use enums with associated values to model distinct states:
|
||||
|
||||
```swift
|
||||
enum LoadState<T: Sendable>: Sendable {
|
||||
case idle
|
||||
case loading
|
||||
case loaded(T)
|
||||
case failed(Error)
|
||||
}
|
||||
```
|
||||
|
||||
## Actor Pattern
|
||||
|
||||
Use actors for shared mutable state instead of locks or dispatch queues:
|
||||
|
||||
```swift
|
||||
actor Cache<Key: Hashable & Sendable, Value: Sendable> {
|
||||
private var storage: [Key: Value] = [:]
|
||||
|
||||
func get(_ key: Key) -> Value? { storage[key] }
|
||||
func set(_ key: Key, value: Value) { storage[key] = value }
|
||||
}
|
||||
```
|
||||
|
||||
## Dependency Injection
|
||||
|
||||
Inject protocols with default parameters -- production uses defaults, tests inject mocks:
|
||||
|
||||
```swift
|
||||
struct UserService {
|
||||
private let repository: any UserRepository
|
||||
|
||||
init(repository: any UserRepository = DefaultUserRepository()) {
|
||||
self.repository = repository
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
See skill: `swift-actor-persistence` for actor-based persistence patterns.
|
||||
See skill: `swift-protocol-di-testing` for protocol-based DI and testing.
|
||||
33
.cursor/rules/swift-security.md
Normal file
33
.cursor/rules/swift-security.md
Normal file
@@ -0,0 +1,33 @@
|
||||
---
|
||||
description: "Swift security extending common rules"
|
||||
globs: ["**/*.swift", "**/Package.swift"]
|
||||
alwaysApply: false
|
||||
---
|
||||
# Swift Security
|
||||
|
||||
> This file extends the common security rule with Swift specific content.
|
||||
|
||||
## Secret Management
|
||||
|
||||
- Use **Keychain Services** for sensitive data (tokens, passwords, keys) -- never `UserDefaults`
|
||||
- Use environment variables or `.xcconfig` files for build-time secrets
|
||||
- Never hardcode secrets in source -- decompilation tools extract them trivially
|
||||
|
||||
```swift
|
||||
let apiKey = ProcessInfo.processInfo.environment["API_KEY"]
|
||||
guard let apiKey, !apiKey.isEmpty else {
|
||||
fatalError("API_KEY not configured")
|
||||
}
|
||||
```
|
||||
|
||||
## Transport Security
|
||||
|
||||
- App Transport Security (ATS) is enforced by default -- do not disable it
|
||||
- Use certificate pinning for critical endpoints
|
||||
- Validate all server certificates
|
||||
|
||||
## Input Validation
|
||||
|
||||
- Sanitize all user input before display to prevent injection
|
||||
- Use `URL(string:)` with validation rather than force-unwrapping
|
||||
- Validate data from external sources (APIs, deep links, pasteboard) before processing
|
||||
45
.cursor/rules/swift-testing.md
Normal file
45
.cursor/rules/swift-testing.md
Normal file
@@ -0,0 +1,45 @@
|
||||
---
|
||||
description: "Swift testing extending common rules"
|
||||
globs: ["**/*.swift", "**/Package.swift"]
|
||||
alwaysApply: false
|
||||
---
|
||||
# Swift Testing
|
||||
|
||||
> This file extends the common testing rule with Swift specific content.
|
||||
|
||||
## Framework
|
||||
|
||||
Use **Swift Testing** (`import Testing`) for new tests. Use `@Test` and `#expect`:
|
||||
|
||||
```swift
|
||||
@Test("User creation validates email")
|
||||
func userCreationValidatesEmail() throws {
|
||||
#expect(throws: ValidationError.invalidEmail) {
|
||||
try User(email: "not-an-email")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Test Isolation
|
||||
|
||||
Each test gets a fresh instance -- set up in `init`, tear down in `deinit`. No shared mutable state between tests.
|
||||
|
||||
## Parameterized Tests
|
||||
|
||||
```swift
|
||||
@Test("Validates formats", arguments: ["json", "xml", "csv"])
|
||||
func validatesFormat(format: String) throws {
|
||||
let parser = try Parser(format: format)
|
||||
#expect(parser.isValid)
|
||||
}
|
||||
```
|
||||
|
||||
## Coverage
|
||||
|
||||
```bash
|
||||
swift test --enable-code-coverage
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
See skill: `swift-protocol-di-testing` for protocol-based dependency injection and mock patterns with Swift Testing.
|
||||
63
.cursor/rules/typescript-coding-style.md
Normal file
63
.cursor/rules/typescript-coding-style.md
Normal file
@@ -0,0 +1,63 @@
|
||||
---
|
||||
description: "TypeScript coding style extending common rules"
|
||||
globs: ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx"]
|
||||
alwaysApply: false
|
||||
---
|
||||
# TypeScript/JavaScript Coding Style
|
||||
|
||||
> This file extends the common coding style rule with TypeScript/JavaScript specific content.
|
||||
|
||||
## Immutability
|
||||
|
||||
Use spread operator for immutable updates:
|
||||
|
||||
```typescript
|
||||
// WRONG: Mutation
|
||||
function updateUser(user, name) {
|
||||
user.name = name // MUTATION!
|
||||
return user
|
||||
}
|
||||
|
||||
// CORRECT: Immutability
|
||||
function updateUser(user, name) {
|
||||
return {
|
||||
...user,
|
||||
name
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
Use async/await with try-catch:
|
||||
|
||||
```typescript
|
||||
try {
|
||||
const result = await riskyOperation()
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Operation failed:', error)
|
||||
throw new Error('Detailed user-friendly message')
|
||||
}
|
||||
```
|
||||
|
||||
## Input Validation
|
||||
|
||||
Use Zod for schema-based validation:
|
||||
|
||||
```typescript
|
||||
import { z } from 'zod'
|
||||
|
||||
const schema = z.object({
|
||||
email: z.string().email(),
|
||||
age: z.number().int().min(0).max(150)
|
||||
})
|
||||
|
||||
const validated = schema.parse(input)
|
||||
```
|
||||
|
||||
## Console.log
|
||||
|
||||
- No `console.log` statements in production code
|
||||
- Use proper logging libraries instead
|
||||
- See hooks for automatic detection
|
||||
20
.cursor/rules/typescript-hooks.md
Normal file
20
.cursor/rules/typescript-hooks.md
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
description: "TypeScript hooks extending common rules"
|
||||
globs: ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx"]
|
||||
alwaysApply: false
|
||||
---
|
||||
# TypeScript/JavaScript Hooks
|
||||
|
||||
> This file extends the common hooks rule with TypeScript/JavaScript specific content.
|
||||
|
||||
## PostToolUse Hooks
|
||||
|
||||
Configure in `~/.claude/settings.json`:
|
||||
|
||||
- **Prettier**: Auto-format JS/TS files after edit
|
||||
- **TypeScript check**: Run `tsc` after editing `.ts`/`.tsx` files
|
||||
- **console.log warning**: Warn about `console.log` in edited files
|
||||
|
||||
## Stop Hooks
|
||||
|
||||
- **console.log audit**: Check all modified files for `console.log` before session ends
|
||||
50
.cursor/rules/typescript-patterns.md
Normal file
50
.cursor/rules/typescript-patterns.md
Normal file
@@ -0,0 +1,50 @@
|
||||
---
|
||||
description: "TypeScript patterns extending common rules"
|
||||
globs: ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx"]
|
||||
alwaysApply: false
|
||||
---
|
||||
# TypeScript/JavaScript Patterns
|
||||
|
||||
> This file extends the common patterns rule with TypeScript/JavaScript specific content.
|
||||
|
||||
## API Response Format
|
||||
|
||||
```typescript
|
||||
interface ApiResponse<T> {
|
||||
success: boolean
|
||||
data?: T
|
||||
error?: string
|
||||
meta?: {
|
||||
total: number
|
||||
page: number
|
||||
limit: number
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Custom Hooks Pattern
|
||||
|
||||
```typescript
|
||||
export function useDebounce<T>(value: T, delay: number): T {
|
||||
const [debouncedValue, setDebouncedValue] = useState<T>(value)
|
||||
|
||||
useEffect(() => {
|
||||
const handler = setTimeout(() => setDebouncedValue(value), delay)
|
||||
return () => clearTimeout(handler)
|
||||
}, [value, delay])
|
||||
|
||||
return debouncedValue
|
||||
}
|
||||
```
|
||||
|
||||
## Repository Pattern
|
||||
|
||||
```typescript
|
||||
interface Repository<T> {
|
||||
findAll(filters?: Filters): Promise<T[]>
|
||||
findById(id: string): Promise<T | null>
|
||||
create(data: CreateDto): Promise<T>
|
||||
update(id: string, data: UpdateDto): Promise<T>
|
||||
delete(id: string): Promise<void>
|
||||
}
|
||||
```
|
||||
26
.cursor/rules/typescript-security.md
Normal file
26
.cursor/rules/typescript-security.md
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
description: "TypeScript security extending common rules"
|
||||
globs: ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx"]
|
||||
alwaysApply: false
|
||||
---
|
||||
# TypeScript/JavaScript Security
|
||||
|
||||
> This file extends the common security rule with TypeScript/JavaScript specific content.
|
||||
|
||||
## Secret Management
|
||||
|
||||
```typescript
|
||||
// NEVER: Hardcoded secrets
|
||||
const apiKey = "sk-proj-xxxxx"
|
||||
|
||||
// ALWAYS: Environment variables
|
||||
const apiKey = process.env.OPENAI_API_KEY
|
||||
|
||||
if (!apiKey) {
|
||||
throw new Error('OPENAI_API_KEY not configured')
|
||||
}
|
||||
```
|
||||
|
||||
## Agent Support
|
||||
|
||||
- Use **security-reviewer** skill for comprehensive security audits
|
||||
16
.cursor/rules/typescript-testing.md
Normal file
16
.cursor/rules/typescript-testing.md
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
description: "TypeScript testing extending common rules"
|
||||
globs: ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx"]
|
||||
alwaysApply: false
|
||||
---
|
||||
# TypeScript/JavaScript Testing
|
||||
|
||||
> This file extends the common testing rule with TypeScript/JavaScript specific content.
|
||||
|
||||
## E2E Testing
|
||||
|
||||
Use **Playwright** as the E2E testing framework for critical user flows.
|
||||
|
||||
## Agent Support
|
||||
|
||||
- **e2e-runner** - Playwright E2E testing specialist
|
||||
Reference in New Issue
Block a user