import from local vendored copy (2026-05-06)
Some checks failed
CI / validate (push) Failing after 0s

This commit is contained in:
Hongming Wang 2026-05-06 13:53:20 -07:00
commit 0da5021d18
29 changed files with 3253 additions and 0 deletions

5
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,5 @@
name: CI
on: [push, pull_request]
jobs:
validate:
uses: Molecule-AI/molecule-ci/.github/workflows/validate-plugin.yml@main

21
.gitignore vendored Normal file
View File

@ -0,0 +1,21 @@
# Credentials — never commit. Use .env.example as the template.
.env
.env.local
.env.*.local
.env.*
!.env.example
!.env.sample
# Private keys + certs
*.pem
*.key
*.crt
*.p12
*.pfx
# Secret directories
.secrets/
# Workspace auth tokens
.auth-token
.auth_token

View File

@ -0,0 +1 @@
pyyaml>=6.0

View File

@ -0,0 +1,52 @@
#!/usr/bin/env python3
"""Validate a Molecule AI plugin repo."""
import os, sys, yaml
errors = []
# 1. plugin.yaml exists
if not os.path.isfile("plugin.yaml"):
print("::error::plugin.yaml not found at repo root")
sys.exit(1)
with open("plugin.yaml") as f:
plugin = yaml.safe_load(f)
# 2. Required fields
for field in ["name", "version", "description"]:
if not plugin.get(field):
errors.append(f"Missing required field: {field}")
# 3. Version format
v = str(plugin.get("version", ""))
if v and not all(c in "0123456789." for c in v):
errors.append(f"Invalid version format: {v}")
# 4. Runtimes type
runtimes = plugin.get("runtimes")
if runtimes is not None and not isinstance(runtimes, list):
errors.append(f"runtimes must be a list, got {type(runtimes).__name__}")
# 5. Has content
content_paths = ["SKILL.md", "hooks", "skills", "rules"]
found = [p for p in content_paths if os.path.exists(p)]
if not found:
errors.append("Plugin must contain at least one of: SKILL.md, hooks/, skills/, rules/")
# 6. SKILL.md formatting check
if os.path.isfile("SKILL.md"):
with open("SKILL.md") as f:
first_line = f.readline().strip()
if first_line and not first_line.startswith("#"):
print("::warning::SKILL.md should start with a markdown heading (e.g., # Plugin Name)")
if errors:
for e in errors:
print(f"::error::{e}")
sys.exit(1)
print(f"✓ plugin.yaml valid: {plugin['name']} v{plugin['version']}")
if found:
print(f" Content: {', '.join(found)}")
if runtimes:
print(f" Runtimes: {', '.join(runtimes)}")

166
AGENTS.md Normal file
View File

@ -0,0 +1,166 @@
# Everything Claude Code (ECC) — Agent Instructions
This is a **production-ready AI coding plugin** providing 38 specialized agents, 156 skills, 72 commands, and automated hook workflows for software development.
**Version:** 1.9.0
## Core Principles
1. **Agent-First** — Delegate to specialized agents for domain tasks
2. **Test-Driven** — Write tests before implementation, 80%+ coverage required
3. **Security-First** — Never compromise on security; validate all inputs
4. **Immutability** — Always create new objects, never mutate existing ones
5. **Plan Before Execute** — Plan complex features before writing code
## Available Agents
| Agent | Purpose | When to Use |
|-------|---------|-------------|
| planner | Implementation planning | Complex features, refactoring |
| architect | System design and scalability | Architectural decisions |
| tdd-guide | Test-driven development | New features, bug fixes |
| code-reviewer | Code quality and maintainability | After writing/modifying code |
| security-reviewer | Vulnerability detection | Before commits, sensitive code |
| build-error-resolver | Fix build/type errors | When build fails |
| e2e-runner | End-to-end Playwright testing | Critical user flows |
| refactor-cleaner | Dead code cleanup | Code maintenance |
| doc-updater | Documentation and codemaps | Updating docs |
| cpp-reviewer | C++ code review | C++ projects |
| cpp-build-resolver | C++ build errors | C++ build failures |
| docs-lookup | Documentation lookup via Context7 | API/docs questions |
| go-reviewer | Go code review | Go projects |
| go-build-resolver | Go build errors | Go build failures |
| kotlin-reviewer | Kotlin code review | Kotlin/Android/KMP projects |
| kotlin-build-resolver | Kotlin/Gradle build errors | Kotlin build failures |
| database-reviewer | PostgreSQL/Supabase specialist | Schema design, query optimization |
| python-reviewer | Python code review | Python projects |
| java-reviewer | Java and Spring Boot code review | Java/Spring Boot projects |
| java-build-resolver | Java/Maven/Gradle build errors | Java build failures |
| loop-operator | Autonomous loop execution | Run loops safely, monitor stalls, intervene |
| harness-optimizer | Harness config tuning | Reliability, cost, throughput |
| rust-reviewer | Rust code review | Rust projects |
| rust-build-resolver | Rust build errors | Rust build failures |
| pytorch-build-resolver | PyTorch runtime/CUDA/training errors | PyTorch build/training failures |
| typescript-reviewer | TypeScript/JavaScript code review | TypeScript/JavaScript projects |
## Agent Orchestration
Use agents proactively without user prompt:
- Complex feature requests → **planner**
- Code just written/modified → **code-reviewer**
- Bug fix or new feature → **tdd-guide**
- Architectural decision → **architect**
- Security-sensitive code → **security-reviewer**
- Autonomous loops / loop monitoring → **loop-operator**
- Harness config reliability and cost → **harness-optimizer**
Use parallel execution for independent operations — launch multiple agents simultaneously.
## Security Guidelines
**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. Use environment variables or a secret manager. Validate required secrets at startup. Rotate any exposed secrets immediately.
**If security issue found:** STOP → use security-reviewer agent → fix CRITICAL issues → rotate exposed secrets → review codebase for similar issues.
## Coding Style
**Immutability (CRITICAL):** Always create new objects, never mutate. Return new copies with changes applied.
**File organization:** Many small files over few large ones. 200-400 lines typical, 800 max. Organize by feature/domain, not by type. High cohesion, low coupling.
**Error handling:** Handle errors at every level. Provide user-friendly messages in UI code. Log detailed context server-side. Never silently swallow errors.
**Input validation:** Validate all user input at system boundaries. Use schema-based validation. Fail fast with clear messages. Never trust external data.
**Code quality checklist:**
- Functions small (<50 lines), files focused (<800 lines)
- No deep nesting (>4 levels)
- Proper error handling, no hardcoded values
- Readable, well-named identifiers
## Testing Requirements
**Minimum 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
**TDD workflow (mandatory):**
1. Write test first (RED) — test should FAIL
2. Write minimal implementation (GREEN) — test should PASS
3. Refactor (IMPROVE) — verify coverage 80%+
Troubleshoot failures: check test isolation → verify mocks → fix implementation (not tests, unless tests are wrong).
## Development Workflow
1. **Plan** — Use planner agent, identify dependencies and risks, break into phases
2. **TDD** — Use tdd-guide agent, write tests first, implement, refactor
3. **Review** — Use code-reviewer agent immediately, address CRITICAL/HIGH issues
4. **Capture knowledge in the right place**
- Personal debugging notes, preferences, and temporary context → auto memory
- Team/project knowledge (architecture decisions, API changes, runbooks) → the project's existing docs structure
- If the current task already produces the relevant docs or code comments, do not duplicate the same information elsewhere
- If there is no obvious project doc location, ask before creating a new top-level file
5. **Commit** — Conventional commits format, comprehensive PR summaries
## Workflow Surface Policy
- `skills/` is the canonical workflow surface.
- New workflow contributions should land in `skills/` first.
- `commands/` is a legacy slash-entry compatibility surface and should only be added or updated when a shim is still required for migration or cross-harness parity.
## Git Workflow
**Commit format:** `<type>: <description>` — Types: feat, fix, refactor, docs, test, chore, perf, ci
**PR workflow:** Analyze full commit history → draft comprehensive summary → include test plan → push with `-u` flag.
## Architecture Patterns
**API response format:** Consistent envelope with success indicator, data payload, error message, and pagination metadata.
**Repository pattern:** Encapsulate data access behind standard interface (findAll, findById, create, update, delete). Business logic depends on abstract interface, not storage mechanism.
**Skeleton projects:** Search for battle-tested templates, evaluate with parallel agents (security, extensibility, relevance), clone best match, iterate within proven structure.
## Performance
**Context management:** Avoid last 20% of context window for large refactoring and multi-file features. Lower-sensitivity tasks (single edits, docs, simple fixes) tolerate higher utilization.
**Build troubleshooting:** Use build-error-resolver agent → analyze errors → fix incrementally → verify after each fix.
## Project Structure
```
agents/ — 38 specialized subagents
skills/ — 156 workflow skills and domain knowledge
commands/ — 72 slash commands
hooks/ — Trigger-based automations
rules/ — Always-follow guidelines (common + per-language)
scripts/ — Cross-platform Node.js utilities
mcp-configs/ — 14 MCP server configurations
tests/ — Test suite
```
`commands/` remains in the repo for compatibility, but the long-term direction is skills-first.
## Success Metrics
- All tests pass with 80%+ coverage
- No security vulnerabilities
- Code is readable and maintainable
- Performance is acceptable
- User requirements are met

121
CLAUDE.md Normal file
View File

@ -0,0 +1,121 @@
# plugin-ecc — Everything Claude Code
ECC is a **plugin aggregator** that bundles the Everything Claude Code (ECC) ecosystem — 38 agents, 156 skills, 72 commands, and hook workflows — for use on the Molecule AI platform.
This repository itself is minimal: it wires the ecosystem together via `plugin.yaml` and provides plugin-specific conventions. Most content lives in `rules/`, `skills/`, and `AGENTS.md`.
**Version:** 1.9.0
**Runtime:** `claude_code`, `deepagents`, `hermes`
---
## Repository Layout
```
ecc/
├── AGENTS.md — Agent manifest (38 agents, their purposes, when to use)
├── plugin.yaml — Plugin manifest (runtimes, rules, skills, prompt_fragments)
├── rules/
│ ├── everything-claude-code-guardrails.md — Generated guardrails from ECC repo
│ └── node.md — Node.js development rules
├── skills/ — Skill definitions (installed as workflow surface)
└── adapters/ — Harness adaptor (wraps ECC via plugins_registry)
```
---
## Conventions
### File Naming
| Directory | Convention | Example |
|-----------|-----------|---------|
| `rules/` | lowercase with hyphens | `codebase-conventions.md` |
| `skills/` | lowercase with hyphens | `tdd-workflow.md` |
| `agents/` | lowercase with hyphens | `code-reviewer.md` |
| `commands/` | lowercase with hyphens | `security-review.md` |
| `scripts/` | lowercase with hyphens (CommonJS) | `session-start.js` |
### Markdown Files
All `.md` files in `skills/`, `agents/`, `commands/`, and `rules/` must pass markdownlint before commit:
```bash
npx markdownlint '**/*.md' --ignore node_modules
```
### YAML Frontmatter
- **Agents**: must have `name`, `description`, `tools`, `model`
- **Skills**: must have "When to Use", "How It Works", "Examples" sections
- **Commands**: must have `description:` frontmatter line
---
## Development
### Setup
```bash
# No npm install needed for the plugin repo itself
# (adapters/ depends on plugins_registry at runtime)
```
### Validation
```bash
# Validate the plugin structure (CI uses molecule-ci workflow)
# Run locally via:
gh workflow run validate-plugin.yml --ref main
```
### Adding a New Rule
1. Create `rules/<rule-name>.md` with frontmatter (`name`, `description`)
2. Add it to `rules/` list in `plugin.yaml`
3. Add it to the `rules/` section in `AGENTS.md` if it affects agent behavior
4. Run markdownlint validation
### Adding a New Skill
1. Create `skills/<skill-name>.md` with frontmatter (`name`, `description`)
2. Add it to `skills/` list in `plugin.yaml`
3. Skills are the canonical workflow surface — prefer adding here over `commands/`
---
## Release Process
See `runbooks/release-procedure.md` for full details.
Brief overview:
1. Ensure all markdown files pass linting
2. Bump version in `plugin.yaml` (semver)
3. Update `AGENTS.md` version number if agents list changed
4. Commit with `chore: bump version to X.Y.Z`
5. Tag and push: `git tag vX.Y.Z && git push origin main --tags`
6. Create GitHub release with `## Changelog` section
---
## Known Issues
See `known-issues.md` for current issues and workarounds.
---
## Key Principles
1. **Agent-First** — Delegate to specialized agents for domain tasks
2. **Test-Driven** — 80%+ coverage required for any new scripts
3. **Security-First** — No hardcoded secrets; validate all inputs
4. **Immutability** — Always create new objects, never mutate existing ones
5. **Plan Before Execute** — Use planner agent for complex features
---
## Workflow Surface
- `skills/` is the **canonical** workflow surface
- `commands/` is legacy for slash-command compatibility only
- New workflows should land in `skills/` first

45
README.md Normal file
View File

@ -0,0 +1,45 @@
# ECC — Claude Code Guardrails and Standards
Plugin for Claude Code (and Claude Code-compatible runtimes). Provides coding guardrails,
development standards, and production API conventions — everything a Claude Code agent
needs to write production-quality code without prompting.
## What it provides
**Skills (invoke via the Skill tool):**
| Skill | What it does |
|-------|-------------|
| `ecc:api-design` | REST API design patterns — resource naming, HTTP methods, status codes, pagination, filtering, error responses |
| `ecc:coding-standards` | Code quality standards — naming, modularity, error handling, testing conventions |
| `ecc:deep-research` | Research methodology for technical investigations — how to gather context, validate assumptions, cite sources |
| `ecc:security-review` | Security-first code review — common vulnerability patterns, injection vectors, secrets handling |
| `ecc:tdd-workflow` | Test-driven development workflow — red-green-refactor cycle, what makes a good test |
**Rules (ambient — always active):**
- `everything-claude-code-guardrails.md` — platform-wide Claude Code guardrails
- `node.md` — Node.js / TypeScript conventions
- `plugin-ecc-conventions.md` — Molecule AI internal conventions
**Prompt fragments:**
- `AGENTS.md` — injected into the agent's system prompt on startup
## When to use it
Install on any Claude Code (or compatible) workspace. The skills are invoked on-demand
via the `Skill` tool; the rules and prompt fragments activate automatically.
## Installation
### In org template (org.yaml)
```yaml
plugins:
- ecc
```
### From URL (community install)
```
github://Molecule-AI/molecule-ai-plugin-ecc
```
## License
Business Source License 1.1 — © Molecule AI.

Binary file not shown.

Binary file not shown.

2
adapters/claude_code.py Normal file
View File

@ -0,0 +1,2 @@
"""Claude Code adaptor — uses the generic rule+skill installer."""
from plugins_registry.builtins import AgentskillsAdaptor as Adaptor # noqa: F401

2
adapters/deepagents.py Normal file
View File

@ -0,0 +1,2 @@
"""DeepAgents adaptor — uses the generic rule+skill installer."""
from plugins_registry.builtins import AgentskillsAdaptor as Adaptor # noqa: F401

56
known-issues.md Normal file
View File

@ -0,0 +1,56 @@
# Known Issues
Active and recently resolved issues for `plugin-ecc`.
---
## Active Issues
*(None currently open. This section is updated when issues are filed.)*
---
## Recently Resolved
*(No recently resolved issues.)*
---
## How to Update This File
When a new issue is identified:
1. Add it under **Active Issues** with the template below
2. Include: symptom, cause (if known), workaround
3. When fixed, move it to **Recently Resolved** and add the fix version
### Issue Template
```markdown
## [TICKET-NUMBER] <Short Title>
**Severity:** P0 / P1 / P2 / P3
**Status:** Workaround / Fix in progress / Fix available
**Affected versions:** All / vX.Y.Z+
**Symptoms:**
**Cause:**
**Workaround:**
**Fix (if available):**
```
---
## Severity Definitions
| Level | Description |
|-------|-------------|
| P0 | Plugin fails to load; no workaround |
| P1 | Core feature broken; major impact |
| P2 | Non-core feature broken; minor impact |
| P3 | Cosmetic or edge case |
---
## Reporting New Issues
Use the internal Molecule-AI/internal repo issue tracker. Tag with `plugin-ecc`.

25
plugin.yaml Normal file
View File

@ -0,0 +1,25 @@
name: ecc
version: 1.0.0
description: Everything Claude Code — coding guardrails, standards, and development skills
author: Molecule AI
tags: [claude-code, coding, standards, guardrails]
runtimes:
- claude_code
- deepagents
- hermes
rules:
- rules/everything-claude-code-guardrails.md
- rules/node.md
- rules/plugin-ecc-conventions.md
prompt_fragments:
- AGENTS.md
skills:
- api-design
- coding-standards
- deep-research
- security-review
- tdd-workflow

View File

@ -0,0 +1,34 @@
# Everything Claude Code Guardrails
Generated by ECC Tools from repository history. Review before treating it as a hard policy file.
## Commit Workflow
- Prefer `conventional` commit messaging with prefixes such as fix, test, feat, docs.
- Keep new changes aligned with the existing pull-request and review flow already present in the repo.
## Architecture
- Preserve the current `hybrid` module organization.
- Respect the current test layout: `separate`.
## Code Style
- Use `camelCase` file naming.
- Prefer `relative` imports and `mixed` exports.
## ECC Defaults
- Current recommended install profile: `full`.
- Validate risky config changes in PRs and keep the install manifest in source control.
## Detected Workflows
- database-migration: Database schema changes with migration files
- feature-development: Standard feature implementation workflow
- add-language-rules: Adds a new programming language to the rules system, including coding style, hooks, patterns, security, and testing guidelines.
## Review Reminder
- Regenerate this bundle when repository conventions materially change.
- Keep suppressions narrow and auditable.

47
rules/node.md Normal file
View File

@ -0,0 +1,47 @@
# Node.js Rules for everything-claude-code
> Project-specific rules for the ECC codebase. Extends common rules.
## Stack
- **Runtime**: Node.js >=18 (no transpilation, plain CommonJS)
- **Test runner**: `node tests/run-all.js` — individual files via `node tests/**/*.test.js`
- **Linter**: ESLint (`@eslint/js`, flat config)
- **Coverage**: c8
- **Lint**: markdownlint-cli for `.md` files
## File Conventions
- `scripts/` — Node.js utilities, hooks. CommonJS (`require`/`module.exports`)
- `agents/`, `commands/`, `skills/`, `rules/` — Markdown with YAML frontmatter
- `tests/` — Mirror the `scripts/` structure. Test files named `*.test.js`
- File naming: **lowercase with hyphens** (e.g. `session-start.js`, `post-edit-format.js`)
## Code Style
- CommonJS only — no ESM (`import`/`export`) unless file ends in `.mjs`
- No TypeScript — plain `.js` throughout
- Prefer `const` over `let`; never `var`
- Keep hook scripts under 200 lines — extract helpers to `scripts/lib/`
- All hooks must `exit 0` on non-critical errors (never block tool execution unexpectedly)
## Hook Development
- Hook scripts normally receive JSON on stdin, but hooks routed through `scripts/hooks/run-with-flags.js` can export `run(rawInput)` and let the wrapper handle parsing/gating
- Async hooks: mark `"async": true` in `settings.json` with a timeout ≤30s
- Blocking hooks (PreToolUse, stop): keep fast (<200ms) no network calls
- Use `run-with-flags.js` wrapper for all hooks so `ECC_HOOK_PROFILE` and `ECC_DISABLED_HOOKS` runtime gating works
- Always exit 0 on parse errors; log to stderr with `[HookName]` prefix
## Testing Requirements
- Run `node tests/run-all.js` before committing
- New scripts in `scripts/lib/` require a matching test in `tests/lib/`
- New hooks require at least one integration test in `tests/hooks/`
## Markdown / Agent Files
- Agents: YAML frontmatter with `name`, `description`, `tools`, `model`
- Skills: sections — When to Use, How It Works, Examples
- Commands: `description:` frontmatter line required
- Run `npx markdownlint-cli '**/*.md' --ignore node_modules` before committing

View File

@ -0,0 +1,69 @@
# plugin-ecc Conventions
> Plugin-specific rules for `plugin-ecc`. These complement the ECC ecosystem rules and are specific to how this plugin is packaged, released, and maintained.
## Error Handling
- **Parse errors in rules/skills**: Log to stderr with a `[PluginName]` prefix and `exit 0`. Never block tool execution due to a malformed doc.
- **Adapter errors**: The `adapters/` layer is a thin wrapper — any runtime errors from `plugins_registry` should propagate, not be swallowed.
- **Markdown parse failures**: If a markdown file fails to parse (missing frontmatter, broken sections), report in the agent response but do not abort the session.
## Logging Patterns
- **In hooks** (via `run-with-flags.js`): Use `console.error` for diagnostic output — stdout is reserved for the JSON response.
- **Prefix all log lines**: `[ECC] <component>: <message>` — e.g., `[ECC] guardrails: rule loaded`, `[ECC] adapter: init`.
- **No token/secret logging**: Never log API keys, tokens, or user credentials, even at DEBUG level.
- **Structured fields**: Prefer `console.error('[ECC] key=value key2=value2')` over freeform strings for parseable output.
## Config / Environment Variables
| Variable | Purpose | Required |
|----------|---------|----------|
| `ECC_HOOK_PROFILE` | Gate which hooks fire at runtime | No |
| `ECC_DISABLED_HOOKS` | Colon-separated list of hooks to skip | No |
| `PLUGINS_REGISTRY_URL` | Override registry base URL | No |
- Validate required env vars at adapter init time. Fail fast with a clear message.
- No hardcoded defaults for credentials — require them to be set or inherited from the harness.
## Release Process
### Version Bump
1. Update `version` in `plugin.yaml` (semver: `MAJOR.MINOR.PATCH`).
2. Update version number in `AGENTS.md` (`**Version:** X.Y.Z`) if agents list changed.
3. Update `**Version:**` in `CLAUDE.md` if conventions changed.
### Pre-Release Checklist
- [ ] All markdown files pass `npx markdownlint '**/*.md' --ignore node_modules`
- [ ] `plugin.yaml` is valid YAML and references all existing files
- [ ] No `.pyc` or `__pycache__` files committed (gitignore covers this — verify)
- [ ] Changelog section in release notes covers: new rules, removed rules, breaking changes
### Tag & Push
```bash
git tag -a vX.Y.Z -m "chore: release vX.Y.Z"
git push origin main
git push origin --tags
```
### Post-Release
Create a GitHub Release with:
- Tag version and SHA
- `## Changelog` section listing all changes since last release
- Any migration notes if `rules/` or `skills/` were reorganized
## File Integrity
- All `.md` files committed to the plugin must be valid Markdown — test with `npx markdownlint`.
- No binary files in `rules/`, `skills/`, `agents/`, or `commands/`.
- The `.gitignore` must cover: `__pycache__/`, `*.pyc`, `.DS_Store`, editor backups.
## Adapter Layer
- The `adapters/claude_code.py` file wraps the ECC ecosystem via `plugins_registry.builtins.AgentskillsAdaptor`.
- Do not add business logic to the adapter — keep it as a thin import shim.
- If the adapter needs configuration, add it to `plugin.yaml` under an `adapter:` section, not as code constants.

View File

@ -0,0 +1,143 @@
# Known Failure Modes
This document tracks known issues in `plugin-ecc`, their symptoms, and workarounds.
---
## Markdown Lint Failures in CI
**Symptom:** CI `validate-plugin.yml` workflow fails on the `markdownlint` step.
**Cause:** A new or edited `.md` file violates markdownlint rules (e.g., line length > 80, missing blank lines around headings, or inline HTML).
**Fix:**
```bash
npx markdownlint '**/*.md' --ignore node_modules
# Fix reported issues manually or auto-fix:
npx markdownlint '**/*.md' --ignore node_modules --fix
git add -A && git commit --amend --no-edit
git push --force-with-lease
```
**Prevention:** Run the lint command before every commit.
---
## Missing Referenced File in plugin.yaml
**Symptom:** CI fails with "MISSING: rules/xxx.md" or "MISSING: skills/xxx.md".
**Cause:** `plugin.yaml` references a file that doesn't exist on disk (file deleted, renamed, or never created).
**Fix:**
1. Check the `rules:` and `skills:` lists in `plugin.yaml`
2. For each entry, verify the corresponding `.md` file exists
3. Either add the missing file or remove the reference from `plugin.yaml`
```bash
python3 -c "
import yaml, os
with open('plugin.yaml') as f:
data = yaml.safe_load(f)
for key in ['rules', 'skills']:
for ref in data.get(key, []):
path = ref if ref.endswith('.md') else ref + '.md'
exists = os.path.exists(path)
print(f'[{\"OK\" if exists else \"MISSING\"}] {path}')
"
```
---
## Adapter Import Failure
**Symptom:** Python import error at runtime:
```
ModuleNotFoundError: No module named 'plugins_registry'
```
**Cause:** `plugins_registry` is not installed in the runtime environment. It is a harness-level dependency, not bundled in the plugin.
**Workaround:** This is expected in isolated dev environments. The adapter works when the plugin is installed in the Molecule AI harness. If testing locally, see `runbooks/local-dev-setup.md`.
---
## Stale __pycache__ / .pyc Files
**Symptom:** "module has no attribute X" errors after a rename.
**Cause:** Python bytecode cache (`__pycache__/`) holds stale `.pyc` files from a renamed or deleted module.
**Fix:**
```bash
find . -type d -name '__pycache__' -exec rm -rf {} + 2>/dev/null
find . -name '*.pyc' -delete
# Re-run the failing test/import
```
**Prevention:** `.gitignore` excludes these; they won't be committed. Always work in a clean venv.
---
## Duplicate Rule/Skill Names
**Symptom:** CI passes but agents load duplicate rules, or behavior is inconsistent.
**Cause:** The same rule or skill appears multiple times in `plugin.yaml`'s list. The harness may deduplicate, but behavior can be unpredictable.
**Fix:**
```bash
python3 -c "
import yaml
with open('plugin.yaml') as f:
data = yaml.safe_load(f)
for key in ['rules', 'skills']:
items = data.get(key, [])
seen = set()
for item in items:
if item in seen:
print(f'DUPLICATE in {key}: {item}')
seen.add(item)
"
```
---
## Large Context from AGENTS.md
**Symptom:** Agent runs out of context quickly, or first response is delayed.
**Cause:** `AGENTS.md` is 167 lines. If included in the system prompt on every message, it consumes significant context budget.
**Mitigation:** `AGENTS.md` is referenced via `prompt_fragments` in `plugin.yaml`, so it is loaded selectively. No action needed unless the file grows significantly beyond its current size.
---
## Git Push Blocked by Pre-Receive Hook
**Symptom:** `git push` fails with:
```
remote: error: pre-receive hook declined
```
**Cause:** Either (a) branch protection requires PR review, or (b) CI failed on the latest commit.
**Fix:**
1. Check CI status at: `https://github.com/Molecule-AI/molecule-ai-plugin-ecc/actions`
2. If CI failed, fix the failures and push again
3. If CI passed but push still blocked, use a PR instead of pushing directly to `main`
---
## Template: Adding a New Issue
When a new issue is discovered, add it here with:
```markdown
## <Issue Title>
**Symptom:**
**Cause:**
**Fix/Workaround:**
**Prevention:**
```

161
runbooks/local-dev-setup.md Normal file
View File

@ -0,0 +1,161 @@
# Local Development Setup
This runbook covers setting up a local development environment for `plugin-ecc`.
---
## Prerequisites
- Node.js >= 18 (for markdownlint)
- Python 3.11+ (for the `adapters/` layer)
- `gh` CLI authenticated: `gh auth status`
- Write access to `Molecule-AI/molecule-ai-plugin-ecc`
---
## Clone & Bootstrap
```bash
# Clone the repo
git clone https://github.com/Molecule-AI/molecule-ai-plugin-ecc.git
cd molecule-ai-plugin-ecc
# Install markdownlint CLI (used for pre-commit linting)
npm install -g markdownlint-cli
# Verify markdownlint works
npx markdownlint '**/*.md' --ignore node_modules
```
---
## Adapter Dev Environment
The `adapters/` layer requires the `plugins_registry` package:
```bash
# Create a virtualenv
python3 -m venv .venv
source .venv/bin/activate
# Install the adapter runtime dependencies
pip install plugins_registry # published from molecule-core
```
To test the adapter:
```bash
python -c "from adapters.claude_code import Adaptor; print('Adaptor OK')"
```
---
## Validating Locally
### Markdown Lint
```bash
npx markdownlint '**/*.md' --ignore node_modules
```
### YAML Validation
```bash
# Ensure plugin.yaml is valid YAML and all referenced files exist
python3 -c "
import yaml, sys
with open('plugin.yaml') as f:
data = yaml.safe_load(f)
refs = data.get('rules', []) + data.get('skills', [])
for ref in refs:
path = ref if ref.endswith('.md') else ref + '.md'
if not __import__('os').path.exists(path):
print(f'MISSING: {path}')
print('plugin.yaml OK')
"
```
---
## IDE Setup
### VS Code
Recommended extensions (see `.vscode/extensions.json` if present):
- `esbenp.prettier-vscode` — Markdown formatting
- `DavidAnson.vscode-markdownlint` — Inline linting
Settings for this project (`.vscode/settings.json`):
```json
{
"editor.formatOnSave": true,
"[markdown]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"markdownlint.config": {
"MD013": false,
"MD033": false
}
}
```
---
## Pre-Commit Checklist
Before pushing changes:
```bash
# 1. Lint all markdown
npx markdownlint '**/*.md' --ignore node_modules || exit 1
# 2. Validate plugin.yaml
python3 -c "import yaml; yaml.safe_load(open('plugin.yaml'))" || exit 1
# 3. Check no pycache
find . -name '__pycache__' -o -name '*.pyc' | grep -v '.gitignore' && echo "FAIL: pycache found" && exit 1
# 4. Run tests if any exist
node tests/run-all.js 2>/dev/null || true
```
---
## Working with the Skills/Agents/Commands Surface
The plugin exposes workflow definitions from the ECC ecosystem. To inspect which skills are available:
```bash
ls skills/
cat skills/*.md | grep -A2 'name:'
```
Adding a new skill:
1. Create `skills/<new-skill>.md` with proper YAML frontmatter
2. Add ` - <new-skill>` to the `skills:` list in `plugin.yaml`
3. Run the YAML validation above to confirm the reference is valid
---
## Troubleshooting
### markdownlint command not found
```bash
npm install -g markdownlint-cli
# If still not found, check your PATH or use npx
npx markdownlint-cli '**/*.md'
```
### Adapter import fails
Verify `plugins_registry` is installed in the active venv:
```bash
pip show plugins_registry
# If not installed:
pip install git+https://github.com/Molecule-AI/plugins_registry.git
```
### CI failure on markdownlint
GitHub Actions runs the same `markdownlint` check. Failures usually mean a new `.md` file or edit broke lint rules. Run locally first to catch.

View File

@ -0,0 +1,155 @@
# Release Procedure
This runbook describes the steps to release a new version of `plugin-ecc`.
---
## Overview
Releases are version-tagged GitHub releases. The plugin follows semver (`MAJOR.MINOR.PATCH`). The CI workflow validates the plugin structure on every push.
---
## Pre-Release Steps
### 1. Review Changed Files
```bash
git fetch origin main
git log origin/main..HEAD --oneline
```
Identify what changed: new rules, new skills, breaking changes, or just a version bump.
### 2. Run Full Validation
```bash
# Markdown lint
npx markdownlint '**/*.md' --ignore node_modules
# YAML structure
python3 -c "
import yaml, os
with open('plugin.yaml') as f:
data = yaml.safe_load(f)
for key in ['rules', 'skills']:
for ref in data.get(key, []):
path = ref if ref.endswith('.md') else ref + '.md'
if not os.path.exists(path):
print(f'MISSING: {path}')
print('All refs OK')
"
```
### 3. Bump Version
Edit `plugin.yaml`:
```yaml
version: X.Y.Z # ← update this
```
If agents list changed, update the version in `AGENTS.md`:
```markdown
**Version:** X.Y.Z
```
Also update `CLAUDE.md`:
```markdown
**Version:** X.Y.Z
```
### 4. Commit Version Bump
```bash
git add plugin.yaml AGENTS.md CLAUDE.md
git commit -m "chore: bump version to X.Y.Z"
```
---
## Release Tagging
### Lightweight Tag (patch/minor)
```bash
git tag vX.Y.Z
git push origin main
git push origin --tags
```
### Annotated Tag (recommended for releases)
```bash
git tag -a vX.Y.Z -m "Release vX.Y.Z — <summary of changes>"
git push origin main
git push origin --tags
```
---
## Create GitHub Release
```bash
gh release create vX.Y.Z \
--title "plugin-ecc vX.Y.Z" \
--notes "$(cat <<'EOF'
## Changelog
- <describe change 1>
- <describe change 2>
### Migration Notes
<any breaking changes or config changes>
EOF
)"
```
Or via the GitHub web UI:
1. Go to https://github.com/Molecule-AI/molecule-ai-plugin-ecc/releases/new
2. Select the tag `vX.Y.Z`
3. Paste the changelog into the release body
4. Publish release
---
## Post-Release Verification
1. **CI green**: Confirm the `validate-plugin.yml` workflow passed on the release commit.
2. **Tag visible**: `git fetch --tags && git tag -l` shows the new tag.
3. **Release page**: The GitHub Release is published with changelog.
4. **Plugin registry**: If molecule-core pulls from the registry, confirm the new version is indexed.
---
## Rollback
If a release is bad:
```bash
# Remove the remote tag
git push origin :refs/tags/vX.Y.Z
# Revert the version commit
git revert HEAD --no-edit
git push origin main
```
Then cut a new release with the fix.
---
## Release Types
| Type | When to use |
|------|-------------|
| `patch` | Bug fixes, doc corrections, non-breaking additions |
| `minor` | New rules/skills, backward-compatible changes |
| `major` | Breaking changes to `plugin.yaml` schema, removed rules/skills |
---
## Automation Opportunities
- **Auto-bump on PR merge**: A GitHub Action can detect `feat:` commits and auto-PR a version bump.
- **Auto-changelog**: `generate-release-notes` action can draft changelog from conventional commits.
- Currently these are manual; implement if release frequency increases.

523
skills/api-design/SKILL.md Normal file
View File

@ -0,0 +1,523 @@
---
name: api-design
description: REST API design patterns including resource naming, status codes, pagination, filtering, error responses, versioning, and rate limiting for production APIs.
origin: ECC
---
# API Design Patterns
Conventions and best practices for designing consistent, developer-friendly REST APIs.
## When to Activate
- Designing new API endpoints
- Reviewing existing API contracts
- Adding pagination, filtering, or sorting
- Implementing error handling for APIs
- Planning API versioning strategy
- Building public or partner-facing APIs
## Resource Design
### URL Structure
```
# Resources are nouns, plural, lowercase, kebab-case
GET /api/v1/users
GET /api/v1/users/:id
POST /api/v1/users
PUT /api/v1/users/:id
PATCH /api/v1/users/:id
DELETE /api/v1/users/:id
# Sub-resources for relationships
GET /api/v1/users/:id/orders
POST /api/v1/users/:id/orders
# Actions that don't map to CRUD (use verbs sparingly)
POST /api/v1/orders/:id/cancel
POST /api/v1/auth/login
POST /api/v1/auth/refresh
```
### Naming Rules
```
# GOOD
/api/v1/team-members # kebab-case for multi-word resources
/api/v1/orders?status=active # query params for filtering
/api/v1/users/123/orders # nested resources for ownership
# BAD
/api/v1/getUsers # verb in URL
/api/v1/user # singular (use plural)
/api/v1/team_members # snake_case in URLs
/api/v1/users/123/getOrders # verb in nested resource
```
## HTTP Methods and Status Codes
### Method Semantics
| Method | Idempotent | Safe | Use For |
|--------|-----------|------|---------|
| GET | Yes | Yes | Retrieve resources |
| POST | No | No | Create resources, trigger actions |
| PUT | Yes | No | Full replacement of a resource |
| PATCH | No* | No | Partial update of a resource |
| DELETE | Yes | No | Remove a resource |
*PATCH can be made idempotent with proper implementation
### Status Code Reference
```
# Success
200 OK — GET, PUT, PATCH (with response body)
201 Created — POST (include Location header)
204 No Content — DELETE, PUT (no response body)
# Client Errors
400 Bad Request — Validation failure, malformed JSON
401 Unauthorized — Missing or invalid authentication
403 Forbidden — Authenticated but not authorized
404 Not Found — Resource doesn't exist
409 Conflict — Duplicate entry, state conflict
422 Unprocessable Entity — Semantically invalid (valid JSON, bad data)
429 Too Many Requests — Rate limit exceeded
# Server Errors
500 Internal Server Error — Unexpected failure (never expose details)
502 Bad Gateway — Upstream service failed
503 Service Unavailable — Temporary overload, include Retry-After
```
### Common Mistakes
```
# BAD: 200 for everything
{ "status": 200, "success": false, "error": "Not found" }
# GOOD: Use HTTP status codes semantically
HTTP/1.1 404 Not Found
{ "error": { "code": "not_found", "message": "User not found" } }
# BAD: 500 for validation errors
# GOOD: 400 or 422 with field-level details
# BAD: 200 for created resources
# GOOD: 201 with Location header
HTTP/1.1 201 Created
Location: /api/v1/users/abc-123
```
## Response Format
### Success Response
```json
{
"data": {
"id": "abc-123",
"email": "alice@example.com",
"name": "Alice",
"created_at": "2025-01-15T10:30:00Z"
}
}
```
### Collection Response (with Pagination)
```json
{
"data": [
{ "id": "abc-123", "name": "Alice" },
{ "id": "def-456", "name": "Bob" }
],
"meta": {
"total": 142,
"page": 1,
"per_page": 20,
"total_pages": 8
},
"links": {
"self": "/api/v1/users?page=1&per_page=20",
"next": "/api/v1/users?page=2&per_page=20",
"last": "/api/v1/users?page=8&per_page=20"
}
}
```
### Error Response
```json
{
"error": {
"code": "validation_error",
"message": "Request validation failed",
"details": [
{
"field": "email",
"message": "Must be a valid email address",
"code": "invalid_format"
},
{
"field": "age",
"message": "Must be between 0 and 150",
"code": "out_of_range"
}
]
}
}
```
### Response Envelope Variants
```typescript
// Option A: Envelope with data wrapper (recommended for public APIs)
interface ApiResponse<T> {
data: T;
meta?: PaginationMeta;
links?: PaginationLinks;
}
interface ApiError {
error: {
code: string;
message: string;
details?: FieldError[];
};
}
// Option B: Flat response (simpler, common for internal APIs)
// Success: just return the resource directly
// Error: return error object
// Distinguish by HTTP status code
```
## Pagination
### Offset-Based (Simple)
```
GET /api/v1/users?page=2&per_page=20
# Implementation
SELECT * FROM users
ORDER BY created_at DESC
LIMIT 20 OFFSET 20;
```
**Pros:** Easy to implement, supports "jump to page N"
**Cons:** Slow on large offsets (OFFSET 100000), inconsistent with concurrent inserts
### Cursor-Based (Scalable)
```
GET /api/v1/users?cursor=eyJpZCI6MTIzfQ&limit=20
# Implementation
SELECT * FROM users
WHERE id > :cursor_id
ORDER BY id ASC
LIMIT 21; -- fetch one extra to determine has_next
```
```json
{
"data": [...],
"meta": {
"has_next": true,
"next_cursor": "eyJpZCI6MTQzfQ"
}
}
```
**Pros:** Consistent performance regardless of position, stable with concurrent inserts
**Cons:** Cannot jump to arbitrary page, cursor is opaque
### When to Use Which
| Use Case | Pagination Type |
|----------|----------------|
| Admin dashboards, small datasets (<10K) | Offset |
| Infinite scroll, feeds, large datasets | Cursor |
| Public APIs | Cursor (default) with offset (optional) |
| Search results | Offset (users expect page numbers) |
## Filtering, Sorting, and Search
### Filtering
```
# Simple equality
GET /api/v1/orders?status=active&customer_id=abc-123
# Comparison operators (use bracket notation)
GET /api/v1/products?price[gte]=10&price[lte]=100
GET /api/v1/orders?created_at[after]=2025-01-01
# Multiple values (comma-separated)
GET /api/v1/products?category=electronics,clothing
# Nested fields (dot notation)
GET /api/v1/orders?customer.country=US
```
### Sorting
```
# Single field (prefix - for descending)
GET /api/v1/products?sort=-created_at
# Multiple fields (comma-separated)
GET /api/v1/products?sort=-featured,price,-created_at
```
### Full-Text Search
```
# Search query parameter
GET /api/v1/products?q=wireless+headphones
# Field-specific search
GET /api/v1/users?email=alice
```
### Sparse Fieldsets
```
# Return only specified fields (reduces payload)
GET /api/v1/users?fields=id,name,email
GET /api/v1/orders?fields=id,total,status&include=customer.name
```
## Authentication and Authorization
### Token-Based Auth
```
# Bearer token in Authorization header
GET /api/v1/users
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
# API key (for server-to-server)
GET /api/v1/data
X-API-Key: sk_live_abc123
```
### Authorization Patterns
```typescript
// Resource-level: check ownership
app.get("/api/v1/orders/:id", async (req, res) => {
const order = await Order.findById(req.params.id);
if (!order) return res.status(404).json({ error: { code: "not_found" } });
if (order.userId !== req.user.id) return res.status(403).json({ error: { code: "forbidden" } });
return res.json({ data: order });
});
// Role-based: check permissions
app.delete("/api/v1/users/:id", requireRole("admin"), async (req, res) => {
await User.delete(req.params.id);
return res.status(204).send();
});
```
## Rate Limiting
### Headers
```
HTTP/1.1 200 OK
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1640000000
# When exceeded
HTTP/1.1 429 Too Many Requests
Retry-After: 60
{
"error": {
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded. Try again in 60 seconds."
}
}
```
### Rate Limit Tiers
| Tier | Limit | Window | Use Case |
|------|-------|--------|----------|
| Anonymous | 30/min | Per IP | Public endpoints |
| Authenticated | 100/min | Per user | Standard API access |
| Premium | 1000/min | Per API key | Paid API plans |
| Internal | 10000/min | Per service | Service-to-service |
## Versioning
### URL Path Versioning (Recommended)
```
/api/v1/users
/api/v2/users
```
**Pros:** Explicit, easy to route, cacheable
**Cons:** URL changes between versions
### Header Versioning
```
GET /api/users
Accept: application/vnd.myapp.v2+json
```
**Pros:** Clean URLs
**Cons:** Harder to test, easy to forget
### Versioning Strategy
```
1. Start with /api/v1/ — don't version until you need to
2. Maintain at most 2 active versions (current + previous)
3. Deprecation timeline:
- Announce deprecation (6 months notice for public APIs)
- Add Sunset header: Sunset: Sat, 01 Jan 2026 00:00:00 GMT
- Return 410 Gone after sunset date
4. Non-breaking changes don't need a new version:
- Adding new fields to responses
- Adding new optional query parameters
- Adding new endpoints
5. Breaking changes require a new version:
- Removing or renaming fields
- Changing field types
- Changing URL structure
- Changing authentication method
```
## Implementation Patterns
### TypeScript (Next.js API Route)
```typescript
import { z } from "zod";
import { NextRequest, NextResponse } from "next/server";
const createUserSchema = z.object({
email: z.string().email(),
name: z.string().min(1).max(100),
});
export async function POST(req: NextRequest) {
const body = await req.json();
const parsed = createUserSchema.safeParse(body);
if (!parsed.success) {
return NextResponse.json({
error: {
code: "validation_error",
message: "Request validation failed",
details: parsed.error.issues.map(i => ({
field: i.path.join("."),
message: i.message,
code: i.code,
})),
},
}, { status: 422 });
}
const user = await createUser(parsed.data);
return NextResponse.json(
{ data: user },
{
status: 201,
headers: { Location: `/api/v1/users/${user.id}` },
},
);
}
```
### Python (Django REST Framework)
```python
from rest_framework import serializers, viewsets, status
from rest_framework.response import Response
class CreateUserSerializer(serializers.Serializer):
email = serializers.EmailField()
name = serializers.CharField(max_length=100)
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ["id", "email", "name", "created_at"]
class UserViewSet(viewsets.ModelViewSet):
serializer_class = UserSerializer
permission_classes = [IsAuthenticated]
def get_serializer_class(self):
if self.action == "create":
return CreateUserSerializer
return UserSerializer
def create(self, request):
serializer = CreateUserSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = UserService.create(**serializer.validated_data)
return Response(
{"data": UserSerializer(user).data},
status=status.HTTP_201_CREATED,
headers={"Location": f"/api/v1/users/{user.id}"},
)
```
### Go (net/http)
```go
func (h *UserHandler) CreateUser(w http.ResponseWriter, r *http.Request) {
var req CreateUserRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeError(w, http.StatusBadRequest, "invalid_json", "Invalid request body")
return
}
if err := req.Validate(); err != nil {
writeError(w, http.StatusUnprocessableEntity, "validation_error", err.Error())
return
}
user, err := h.service.Create(r.Context(), req)
if err != nil {
switch {
case errors.Is(err, domain.ErrEmailTaken):
writeError(w, http.StatusConflict, "email_taken", "Email already registered")
default:
writeError(w, http.StatusInternalServerError, "internal_error", "Internal error")
}
return
}
w.Header().Set("Location", fmt.Sprintf("/api/v1/users/%s", user.ID))
writeJSON(w, http.StatusCreated, map[string]any{"data": user})
}
```
## API Design Checklist
Before shipping a new endpoint:
- [ ] Resource URL follows naming conventions (plural, kebab-case, no verbs)
- [ ] Correct HTTP method used (GET for reads, POST for creates, etc.)
- [ ] Appropriate status codes returned (not 200 for everything)
- [ ] Input validated with schema (Zod, Pydantic, Bean Validation)
- [ ] Error responses follow standard format with codes and messages
- [ ] Pagination implemented for list endpoints (cursor or offset)
- [ ] Authentication required (or explicitly marked as public)
- [ ] Authorization checked (user can only access their own resources)
- [ ] Rate limiting configured
- [ ] Response does not leak internal details (stack traces, SQL errors)
- [ ] Consistent naming with existing endpoints (camelCase vs snake_case)
- [ ] Documented (OpenAPI/Swagger spec updated)

View File

@ -0,0 +1,7 @@
interface:
display_name: "API Design"
short_description: "REST API design patterns and best practices"
brand_color: "#F97316"
default_prompt: "Design REST API: resources, status codes, pagination"
policy:
allow_implicit_invocation: true

View File

@ -0,0 +1,530 @@
---
name: coding-standards
description: Universal coding standards, best practices, and patterns for TypeScript, JavaScript, React, and Node.js development.
origin: ECC
---
# Coding Standards & Best Practices
Universal coding standards applicable across all projects.
## When to Activate
- Starting a new project or module
- Reviewing code for quality and maintainability
- Refactoring existing code to follow conventions
- Enforcing naming, formatting, or structural consistency
- Setting up linting, formatting, or type-checking rules
- Onboarding new contributors to coding conventions
## Code Quality Principles
### 1. Readability First
- Code is read more than written
- Clear variable and function names
- Self-documenting code preferred over comments
- Consistent formatting
### 2. KISS (Keep It Simple, Stupid)
- Simplest solution that works
- Avoid over-engineering
- No premature optimization
- Easy to understand > clever code
### 3. DRY (Don't Repeat Yourself)
- Extract common logic into functions
- Create reusable components
- Share utilities across modules
- Avoid copy-paste programming
### 4. YAGNI (You Aren't Gonna Need It)
- Don't build features before they're needed
- Avoid speculative generality
- Add complexity only when required
- Start simple, refactor when needed
## TypeScript/JavaScript Standards
### Variable Naming
```typescript
// PASS: GOOD: Descriptive names
const marketSearchQuery = 'election'
const isUserAuthenticated = true
const totalRevenue = 1000
// FAIL: BAD: Unclear names
const q = 'election'
const flag = true
const x = 1000
```
### Function Naming
```typescript
// PASS: GOOD: Verb-noun pattern
async function fetchMarketData(marketId: string) { }
function calculateSimilarity(a: number[], b: number[]) { }
function isValidEmail(email: string): boolean { }
// FAIL: BAD: Unclear or noun-only
async function market(id: string) { }
function similarity(a, b) { }
function email(e) { }
```
### Immutability Pattern (CRITICAL)
```typescript
// PASS: ALWAYS use spread operator
const updatedUser = {
...user,
name: 'New Name'
}
const updatedArray = [...items, newItem]
// FAIL: NEVER mutate directly
user.name = 'New Name' // BAD
items.push(newItem) // BAD
```
### Error Handling
```typescript
// PASS: GOOD: Comprehensive error handling
async function fetchData(url: string) {
try {
const response = await fetch(url)
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
}
return await response.json()
} catch (error) {
console.error('Fetch failed:', error)
throw new Error('Failed to fetch data')
}
}
// FAIL: BAD: No error handling
async function fetchData(url) {
const response = await fetch(url)
return response.json()
}
```
### Async/Await Best Practices
```typescript
// PASS: GOOD: Parallel execution when possible
const [users, markets, stats] = await Promise.all([
fetchUsers(),
fetchMarkets(),
fetchStats()
])
// FAIL: BAD: Sequential when unnecessary
const users = await fetchUsers()
const markets = await fetchMarkets()
const stats = await fetchStats()
```
### Type Safety
```typescript
// PASS: GOOD: Proper types
interface Market {
id: string
name: string
status: 'active' | 'resolved' | 'closed'
created_at: Date
}
function getMarket(id: string): Promise<Market> {
// Implementation
}
// FAIL: BAD: Using 'any'
function getMarket(id: any): Promise<any> {
// Implementation
}
```
## React Best Practices
### Component Structure
```typescript
// PASS: GOOD: Functional component with types
interface ButtonProps {
children: React.ReactNode
onClick: () => void
disabled?: boolean
variant?: 'primary' | 'secondary'
}
export function Button({
children,
onClick,
disabled = false,
variant = 'primary'
}: ButtonProps) {
return (
<button
onClick={onClick}
disabled={disabled}
className={`btn btn-${variant}`}
>
{children}
</button>
)
}
// FAIL: BAD: No types, unclear structure
export function Button(props) {
return <button onClick={props.onClick}>{props.children}</button>
}
```
### Custom Hooks
```typescript
// PASS: GOOD: Reusable custom hook
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
}
// Usage
const debouncedQuery = useDebounce(searchQuery, 500)
```
### State Management
```typescript
// PASS: GOOD: Proper state updates
const [count, setCount] = useState(0)
// Functional update for state based on previous state
setCount(prev => prev + 1)
// FAIL: BAD: Direct state reference
setCount(count + 1) // Can be stale in async scenarios
```
### Conditional Rendering
```typescript
// PASS: GOOD: Clear conditional rendering
{isLoading && <Spinner />}
{error && <ErrorMessage error={error} />}
{data && <DataDisplay data={data} />}
// FAIL: BAD: Ternary hell
{isLoading ? <Spinner /> : error ? <ErrorMessage error={error} /> : data ? <DataDisplay data={data} /> : null}
```
## API Design Standards
### REST API Conventions
```
GET /api/markets # List all markets
GET /api/markets/:id # Get specific market
POST /api/markets # Create new market
PUT /api/markets/:id # Update market (full)
PATCH /api/markets/:id # Update market (partial)
DELETE /api/markets/:id # Delete market
# Query parameters for filtering
GET /api/markets?status=active&limit=10&offset=0
```
### Response Format
```typescript
// PASS: GOOD: Consistent response structure
interface ApiResponse<T> {
success: boolean
data?: T
error?: string
meta?: {
total: number
page: number
limit: number
}
}
// Success response
return NextResponse.json({
success: true,
data: markets,
meta: { total: 100, page: 1, limit: 10 }
})
// Error response
return NextResponse.json({
success: false,
error: 'Invalid request'
}, { status: 400 })
```
### Input Validation
```typescript
import { z } from 'zod'
// PASS: GOOD: Schema validation
const CreateMarketSchema = z.object({
name: z.string().min(1).max(200),
description: z.string().min(1).max(2000),
endDate: z.string().datetime(),
categories: z.array(z.string()).min(1)
})
export async function POST(request: Request) {
const body = await request.json()
try {
const validated = CreateMarketSchema.parse(body)
// Proceed with validated data
} catch (error) {
if (error instanceof z.ZodError) {
return NextResponse.json({
success: false,
error: 'Validation failed',
details: error.errors
}, { status: 400 })
}
}
}
```
## File Organization
### Project Structure
```
src/
├── app/ # Next.js App Router
│ ├── api/ # API routes
│ ├── markets/ # Market pages
│ └── (auth)/ # Auth pages (route groups)
├── components/ # React components
│ ├── ui/ # Generic UI components
│ ├── forms/ # Form components
│ └── layouts/ # Layout components
├── hooks/ # Custom React hooks
├── lib/ # Utilities and configs
│ ├── api/ # API clients
│ ├── utils/ # Helper functions
│ └── constants/ # Constants
├── types/ # TypeScript types
└── styles/ # Global styles
```
### File Naming
```
components/Button.tsx # PascalCase for components
hooks/useAuth.ts # camelCase with 'use' prefix
lib/formatDate.ts # camelCase for utilities
types/market.types.ts # camelCase with .types suffix
```
## Comments & Documentation
### When to Comment
```typescript
// PASS: GOOD: Explain WHY, not WHAT
// Use exponential backoff to avoid overwhelming the API during outages
const delay = Math.min(1000 * Math.pow(2, retryCount), 30000)
// Deliberately using mutation here for performance with large arrays
items.push(newItem)
// FAIL: BAD: Stating the obvious
// Increment counter by 1
count++
// Set name to user's name
name = user.name
```
### JSDoc for Public APIs
```typescript
/**
* Searches markets using semantic similarity.
*
* @param query - Natural language search query
* @param limit - Maximum number of results (default: 10)
* @returns Array of markets sorted by similarity score
* @throws {Error} If OpenAI API fails or Redis unavailable
*
* @example
* ```typescript
* const results = await searchMarkets('election', 5)
* console.log(results[0].name) // "Trump vs Biden"
* ```
*/
export async function searchMarkets(
query: string,
limit: number = 10
): Promise<Market[]> {
// Implementation
}
```
## Performance Best Practices
### Memoization
```typescript
import { useMemo, useCallback } from 'react'
// PASS: GOOD: Memoize expensive computations
const sortedMarkets = useMemo(() => {
return markets.sort((a, b) => b.volume - a.volume)
}, [markets])
// PASS: GOOD: Memoize callbacks
const handleSearch = useCallback((query: string) => {
setSearchQuery(query)
}, [])
```
### Lazy Loading
```typescript
import { lazy, Suspense } from 'react'
// PASS: GOOD: Lazy load heavy components
const HeavyChart = lazy(() => import('./HeavyChart'))
export function Dashboard() {
return (
<Suspense fallback={<Spinner />}>
<HeavyChart />
</Suspense>
)
}
```
### Database Queries
```typescript
// PASS: GOOD: Select only needed columns
const { data } = await supabase
.from('markets')
.select('id, name, status')
.limit(10)
// FAIL: BAD: Select everything
const { data } = await supabase
.from('markets')
.select('*')
```
## Testing Standards
### Test Structure (AAA Pattern)
```typescript
test('calculates similarity correctly', () => {
// Arrange
const vector1 = [1, 0, 0]
const vector2 = [0, 1, 0]
// Act
const similarity = calculateCosineSimilarity(vector1, vector2)
// Assert
expect(similarity).toBe(0)
})
```
### Test Naming
```typescript
// PASS: GOOD: Descriptive test names
test('returns empty array when no markets match query', () => { })
test('throws error when OpenAI API key is missing', () => { })
test('falls back to substring search when Redis unavailable', () => { })
// FAIL: BAD: Vague test names
test('works', () => { })
test('test search', () => { })
```
## Code Smell Detection
Watch for these anti-patterns:
### 1. Long Functions
```typescript
// FAIL: BAD: Function > 50 lines
function processMarketData() {
// 100 lines of code
}
// PASS: GOOD: Split into smaller functions
function processMarketData() {
const validated = validateData()
const transformed = transformData(validated)
return saveData(transformed)
}
```
### 2. Deep Nesting
```typescript
// FAIL: BAD: 5+ levels of nesting
if (user) {
if (user.isAdmin) {
if (market) {
if (market.isActive) {
if (hasPermission) {
// Do something
}
}
}
}
}
// PASS: GOOD: Early returns
if (!user) return
if (!user.isAdmin) return
if (!market) return
if (!market.isActive) return
if (!hasPermission) return
// Do something
```
### 3. Magic Numbers
```typescript
// FAIL: BAD: Unexplained numbers
if (retryCount > 3) { }
setTimeout(callback, 500)
// PASS: GOOD: Named constants
const MAX_RETRIES = 3
const DEBOUNCE_DELAY_MS = 500
if (retryCount > MAX_RETRIES) { }
setTimeout(callback, DEBOUNCE_DELAY_MS)
```
**Remember**: Code quality is not negotiable. Clear, maintainable code enables rapid development and confident refactoring.

View File

@ -0,0 +1,7 @@
interface:
display_name: "Coding Standards"
short_description: "Universal coding standards and best practices"
brand_color: "#3B82F6"
default_prompt: "Apply standards: immutability, error handling, type safety"
policy:
allow_implicit_invocation: true

View File

@ -0,0 +1,155 @@
---
name: deep-research
description: Multi-source deep research using firecrawl and exa MCPs. Searches the web, synthesizes findings, and delivers cited reports with source attribution. Use when the user wants thorough research on any topic with evidence and citations.
origin: ECC
---
# Deep Research
Produce thorough, cited research reports from multiple web sources using firecrawl and exa MCP tools.
## When to Activate
- User asks to research any topic in depth
- Competitive analysis, technology evaluation, or market sizing
- Due diligence on companies, investors, or technologies
- Any question requiring synthesis from multiple sources
- User says "research", "deep dive", "investigate", or "what's the current state of"
## MCP Requirements
At least one of:
- **firecrawl**`firecrawl_search`, `firecrawl_scrape`, `firecrawl_crawl`
- **exa**`web_search_exa`, `web_search_advanced_exa`, `crawling_exa`
Both together give the best coverage. Configure in `~/.claude.json` or `~/.codex/config.toml`.
## Workflow
### Step 1: Understand the Goal
Ask 1-2 quick clarifying questions:
- "What's your goal — learning, making a decision, or writing something?"
- "Any specific angle or depth you want?"
If the user says "just research it" — skip ahead with reasonable defaults.
### Step 2: Plan the Research
Break the topic into 3-5 research sub-questions. Example:
- Topic: "Impact of AI on healthcare"
- What are the main AI applications in healthcare today?
- What clinical outcomes have been measured?
- What are the regulatory challenges?
- What companies are leading this space?
- What's the market size and growth trajectory?
### Step 3: Execute Multi-Source Search
For EACH sub-question, search using available MCP tools:
**With firecrawl:**
```
firecrawl_search(query: "<sub-question keywords>", limit: 8)
```
**With exa:**
```
web_search_exa(query: "<sub-question keywords>", numResults: 8)
web_search_advanced_exa(query: "<keywords>", numResults: 5, startPublishedDate: "2025-01-01")
```
**Search strategy:**
- Use 2-3 different keyword variations per sub-question
- Mix general and news-focused queries
- Aim for 15-30 unique sources total
- Prioritize: academic, official, reputable news > blogs > forums
### Step 4: Deep-Read Key Sources
For the most promising URLs, fetch full content:
**With firecrawl:**
```
firecrawl_scrape(url: "<url>")
```
**With exa:**
```
crawling_exa(url: "<url>", tokensNum: 5000)
```
Read 3-5 key sources in full for depth. Do not rely only on search snippets.
### Step 5: Synthesize and Write Report
Structure the report:
```markdown
# [Topic]: Research Report
*Generated: [date] | Sources: [N] | Confidence: [High/Medium/Low]*
## Executive Summary
[3-5 sentence overview of key findings]
## 1. [First Major Theme]
[Findings with inline citations]
- Key point ([Source Name](url))
- Supporting data ([Source Name](url))
## 2. [Second Major Theme]
...
## 3. [Third Major Theme]
...
## Key Takeaways
- [Actionable insight 1]
- [Actionable insight 2]
- [Actionable insight 3]
## Sources
1. [Title](url) — [one-line summary]
2. ...
## Methodology
Searched [N] queries across web and news. Analyzed [M] sources.
Sub-questions investigated: [list]
```
### Step 6: Deliver
- **Short topics**: Post the full report in chat
- **Long reports**: Post the executive summary + key takeaways, save full report to a file
## Parallel Research with Subagents
For broad topics, use Claude Code's Task tool to parallelize:
```
Launch 3 research agents in parallel:
1. Agent 1: Research sub-questions 1-2
2. Agent 2: Research sub-questions 3-4
3. Agent 3: Research sub-question 5 + cross-cutting themes
```
Each agent searches, reads sources, and returns findings. The main session synthesizes into the final report.
## Quality Rules
1. **Every claim needs a source.** No unsourced assertions.
2. **Cross-reference.** If only one source says it, flag it as unverified.
3. **Recency matters.** Prefer sources from the last 12 months.
4. **Acknowledge gaps.** If you couldn't find good info on a sub-question, say so.
5. **No hallucination.** If you don't know, say "insufficient data found."
6. **Separate fact from inference.** Label estimates, projections, and opinions clearly.
## Examples
```
"Research the current state of nuclear fusion energy"
"Deep dive into Rust vs Go for backend services in 2026"
"Research the best strategies for bootstrapping a SaaS business"
"What's happening with the US housing market right now?"
"Investigate the competitive landscape for AI code editors"
```

View File

@ -0,0 +1,7 @@
interface:
display_name: "Deep Research"
short_description: "Multi-source deep research with firecrawl and exa MCPs"
brand_color: "#6366F1"
default_prompt: "Research the given topic using firecrawl and exa, produce a cited report"
policy:
allow_implicit_invocation: true

View File

@ -0,0 +1,495 @@
---
name: security-review
description: Use this skill when adding authentication, handling user input, working with secrets, creating API endpoints, or implementing payment/sensitive features. Provides comprehensive security checklist and patterns.
origin: ECC
---
# Security Review Skill
This skill ensures all code follows security best practices and identifies potential vulnerabilities.
## When to Activate
- Implementing authentication or authorization
- Handling user input or file uploads
- Creating new API endpoints
- Working with secrets or credentials
- Implementing payment features
- Storing or transmitting sensitive data
- Integrating third-party APIs
## Security Checklist
### 1. Secrets Management
#### FAIL: NEVER Do This
```typescript
const apiKey = "sk-proj-xxxxx" // Hardcoded secret
const dbPassword = "password123" // In source code
```
#### PASS: ALWAYS Do This
```typescript
const apiKey = process.env.OPENAI_API_KEY
const dbUrl = process.env.DATABASE_URL
// Verify secrets exist
if (!apiKey) {
throw new Error('OPENAI_API_KEY not configured')
}
```
#### Verification Steps
- [ ] No hardcoded API keys, tokens, or passwords
- [ ] All secrets in environment variables
- [ ] `.env.local` in .gitignore
- [ ] No secrets in git history
- [ ] Production secrets in hosting platform (Vercel, Railway)
### 2. Input Validation
#### Always Validate User Input
```typescript
import { z } from 'zod'
// Define validation schema
const CreateUserSchema = z.object({
email: z.string().email(),
name: z.string().min(1).max(100),
age: z.number().int().min(0).max(150)
})
// Validate before processing
export async function createUser(input: unknown) {
try {
const validated = CreateUserSchema.parse(input)
return await db.users.create(validated)
} catch (error) {
if (error instanceof z.ZodError) {
return { success: false, errors: error.errors }
}
throw error
}
}
```
#### File Upload Validation
```typescript
function validateFileUpload(file: File) {
// Size check (5MB max)
const maxSize = 5 * 1024 * 1024
if (file.size > maxSize) {
throw new Error('File too large (max 5MB)')
}
// Type check
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif']
if (!allowedTypes.includes(file.type)) {
throw new Error('Invalid file type')
}
// Extension check
const allowedExtensions = ['.jpg', '.jpeg', '.png', '.gif']
const extension = file.name.toLowerCase().match(/\.[^.]+$/)?.[0]
if (!extension || !allowedExtensions.includes(extension)) {
throw new Error('Invalid file extension')
}
return true
}
```
#### Verification Steps
- [ ] All user inputs validated with schemas
- [ ] File uploads restricted (size, type, extension)
- [ ] No direct use of user input in queries
- [ ] Whitelist validation (not blacklist)
- [ ] Error messages don't leak sensitive info
### 3. SQL Injection Prevention
#### FAIL: NEVER Concatenate SQL
```typescript
// DANGEROUS - SQL Injection vulnerability
const query = `SELECT * FROM users WHERE email = '${userEmail}'`
await db.query(query)
```
#### PASS: ALWAYS Use Parameterized Queries
```typescript
// Safe - parameterized query
const { data } = await supabase
.from('users')
.select('*')
.eq('email', userEmail)
// Or with raw SQL
await db.query(
'SELECT * FROM users WHERE email = $1',
[userEmail]
)
```
#### Verification Steps
- [ ] All database queries use parameterized queries
- [ ] No string concatenation in SQL
- [ ] ORM/query builder used correctly
- [ ] Supabase queries properly sanitized
### 4. Authentication & Authorization
#### JWT Token Handling
```typescript
// FAIL: WRONG: localStorage (vulnerable to XSS)
localStorage.setItem('token', token)
// PASS: CORRECT: httpOnly cookies
res.setHeader('Set-Cookie',
`token=${token}; HttpOnly; Secure; SameSite=Strict; Max-Age=3600`)
```
#### Authorization Checks
```typescript
export async function deleteUser(userId: string, requesterId: string) {
// ALWAYS verify authorization first
const requester = await db.users.findUnique({
where: { id: requesterId }
})
if (requester.role !== 'admin') {
return NextResponse.json(
{ error: 'Unauthorized' },
{ status: 403 }
)
}
// Proceed with deletion
await db.users.delete({ where: { id: userId } })
}
```
#### Row Level Security (Supabase)
```sql
-- Enable RLS on all tables
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
-- Users can only view their own data
CREATE POLICY "Users view own data"
ON users FOR SELECT
USING (auth.uid() = id);
-- Users can only update their own data
CREATE POLICY "Users update own data"
ON users FOR UPDATE
USING (auth.uid() = id);
```
#### Verification Steps
- [ ] Tokens stored in httpOnly cookies (not localStorage)
- [ ] Authorization checks before sensitive operations
- [ ] Row Level Security enabled in Supabase
- [ ] Role-based access control implemented
- [ ] Session management secure
### 5. XSS Prevention
#### Sanitize HTML
```typescript
import DOMPurify from 'isomorphic-dompurify'
// ALWAYS sanitize user-provided HTML
function renderUserContent(html: string) {
const clean = DOMPurify.sanitize(html, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'p'],
ALLOWED_ATTR: []
})
return <div dangerouslySetInnerHTML={{ __html: clean }} />
}
```
#### Content Security Policy
```typescript
// next.config.js
const securityHeaders = [
{
key: 'Content-Security-Policy',
value: `
default-src 'self';
script-src 'self' 'unsafe-eval' 'unsafe-inline';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self';
connect-src 'self' https://api.example.com;
`.replace(/\s{2,}/g, ' ').trim()
}
]
```
#### Verification Steps
- [ ] User-provided HTML sanitized
- [ ] CSP headers configured
- [ ] No unvalidated dynamic content rendering
- [ ] React's built-in XSS protection used
### 6. CSRF Protection
#### CSRF Tokens
```typescript
import { csrf } from '@/lib/csrf'
export async function POST(request: Request) {
const token = request.headers.get('X-CSRF-Token')
if (!csrf.verify(token)) {
return NextResponse.json(
{ error: 'Invalid CSRF token' },
{ status: 403 }
)
}
// Process request
}
```
#### SameSite Cookies
```typescript
res.setHeader('Set-Cookie',
`session=${sessionId}; HttpOnly; Secure; SameSite=Strict`)
```
#### Verification Steps
- [ ] CSRF tokens on state-changing operations
- [ ] SameSite=Strict on all cookies
- [ ] Double-submit cookie pattern implemented
### 7. Rate Limiting
#### API Rate Limiting
```typescript
import rateLimit from 'express-rate-limit'
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // 100 requests per window
message: 'Too many requests'
})
// Apply to routes
app.use('/api/', limiter)
```
#### Expensive Operations
```typescript
// Aggressive rate limiting for searches
const searchLimiter = rateLimit({
windowMs: 60 * 1000, // 1 minute
max: 10, // 10 requests per minute
message: 'Too many search requests'
})
app.use('/api/search', searchLimiter)
```
#### Verification Steps
- [ ] Rate limiting on all API endpoints
- [ ] Stricter limits on expensive operations
- [ ] IP-based rate limiting
- [ ] User-based rate limiting (authenticated)
### 8. Sensitive Data Exposure
#### Logging
```typescript
// FAIL: WRONG: Logging sensitive data
console.log('User login:', { email, password })
console.log('Payment:', { cardNumber, cvv })
// PASS: CORRECT: Redact sensitive data
console.log('User login:', { email, userId })
console.log('Payment:', { last4: card.last4, userId })
```
#### Error Messages
```typescript
// FAIL: WRONG: Exposing internal details
catch (error) {
return NextResponse.json(
{ error: error.message, stack: error.stack },
{ status: 500 }
)
}
// PASS: CORRECT: Generic error messages
catch (error) {
console.error('Internal error:', error)
return NextResponse.json(
{ error: 'An error occurred. Please try again.' },
{ status: 500 }
)
}
```
#### Verification Steps
- [ ] No passwords, tokens, or secrets in logs
- [ ] Error messages generic for users
- [ ] Detailed errors only in server logs
- [ ] No stack traces exposed to users
### 9. Blockchain Security (Solana)
#### Wallet Verification
```typescript
import { verify } from '@solana/web3.js'
async function verifyWalletOwnership(
publicKey: string,
signature: string,
message: string
) {
try {
const isValid = verify(
Buffer.from(message),
Buffer.from(signature, 'base64'),
Buffer.from(publicKey, 'base64')
)
return isValid
} catch (error) {
return false
}
}
```
#### Transaction Verification
```typescript
async function verifyTransaction(transaction: Transaction) {
// Verify recipient
if (transaction.to !== expectedRecipient) {
throw new Error('Invalid recipient')
}
// Verify amount
if (transaction.amount > maxAmount) {
throw new Error('Amount exceeds limit')
}
// Verify user has sufficient balance
const balance = await getBalance(transaction.from)
if (balance < transaction.amount) {
throw new Error('Insufficient balance')
}
return true
}
```
#### Verification Steps
- [ ] Wallet signatures verified
- [ ] Transaction details validated
- [ ] Balance checks before transactions
- [ ] No blind transaction signing
### 10. Dependency Security
#### Regular Updates
```bash
# Check for vulnerabilities
npm audit
# Fix automatically fixable issues
npm audit fix
# Update dependencies
npm update
# Check for outdated packages
npm outdated
```
#### Lock Files
```bash
# ALWAYS commit lock files
git add package-lock.json
# Use in CI/CD for reproducible builds
npm ci # Instead of npm install
```
#### Verification Steps
- [ ] Dependencies up to date
- [ ] No known vulnerabilities (npm audit clean)
- [ ] Lock files committed
- [ ] Dependabot enabled on GitHub
- [ ] Regular security updates
## Security Testing
### Automated Security Tests
```typescript
// Test authentication
test('requires authentication', async () => {
const response = await fetch('/api/protected')
expect(response.status).toBe(401)
})
// Test authorization
test('requires admin role', async () => {
const response = await fetch('/api/admin', {
headers: { Authorization: `Bearer ${userToken}` }
})
expect(response.status).toBe(403)
})
// Test input validation
test('rejects invalid input', async () => {
const response = await fetch('/api/users', {
method: 'POST',
body: JSON.stringify({ email: 'not-an-email' })
})
expect(response.status).toBe(400)
})
// Test rate limiting
test('enforces rate limits', async () => {
const requests = Array(101).fill(null).map(() =>
fetch('/api/endpoint')
)
const responses = await Promise.all(requests)
const tooManyRequests = responses.filter(r => r.status === 429)
expect(tooManyRequests.length).toBeGreaterThan(0)
})
```
## Pre-Deployment Security Checklist
Before ANY production deployment:
- [ ] **Secrets**: No hardcoded secrets, all in env vars
- [ ] **Input Validation**: All user inputs validated
- [ ] **SQL Injection**: All queries parameterized
- [ ] **XSS**: User content sanitized
- [ ] **CSRF**: Protection enabled
- [ ] **Authentication**: Proper token handling
- [ ] **Authorization**: Role checks in place
- [ ] **Rate Limiting**: Enabled on all endpoints
- [ ] **HTTPS**: Enforced in production
- [ ] **Security Headers**: CSP, X-Frame-Options configured
- [ ] **Error Handling**: No sensitive data in errors
- [ ] **Logging**: No sensitive data logged
- [ ] **Dependencies**: Up to date, no vulnerabilities
- [ ] **Row Level Security**: Enabled in Supabase
- [ ] **CORS**: Properly configured
- [ ] **File Uploads**: Validated (size, type)
- [ ] **Wallet Signatures**: Verified (if blockchain)
## Resources
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
- [Next.js Security](https://nextjs.org/docs/security)
- [Supabase Security](https://supabase.com/docs/guides/auth)
- [Web Security Academy](https://portswigger.net/web-security)
---
**Remember**: Security is not optional. One vulnerability can compromise the entire platform. When in doubt, err on the side of caution.

View File

@ -0,0 +1,7 @@
interface:
display_name: "Security Review"
short_description: "Comprehensive security checklist and vulnerability detection"
brand_color: "#EF4444"
default_prompt: "Run security checklist: secrets, input validation, injection prevention"
policy:
allow_implicit_invocation: true

View File

@ -0,0 +1,410 @@
---
name: tdd-workflow
description: Use this skill when writing new features, fixing bugs, or refactoring code. Enforces test-driven development with 80%+ coverage including unit, integration, and E2E tests.
origin: ECC
---
# Test-Driven Development Workflow
This skill ensures all code development follows TDD principles with comprehensive test coverage.
## When to Activate
- Writing new features or functionality
- Fixing bugs or issues
- Refactoring existing code
- Adding API endpoints
- Creating new components
## Core Principles
### 1. Tests BEFORE Code
ALWAYS write tests first, then implement code to make tests pass.
### 2. Coverage Requirements
- Minimum 80% coverage (unit + integration + E2E)
- All edge cases covered
- Error scenarios tested
- Boundary conditions verified
### 3. Test Types
#### Unit Tests
- Individual functions and utilities
- Component logic
- Pure functions
- Helpers and utilities
#### Integration Tests
- API endpoints
- Database operations
- Service interactions
- External API calls
#### E2E Tests (Playwright)
- Critical user flows
- Complete workflows
- Browser automation
- UI interactions
## TDD Workflow Steps
### Step 1: Write User Journeys
```
As a [role], I want to [action], so that [benefit]
Example:
As a user, I want to search for markets semantically,
so that I can find relevant markets even without exact keywords.
```
### Step 2: Generate Test Cases
For each user journey, create comprehensive test cases:
```typescript
describe('Semantic Search', () => {
it('returns relevant markets for query', async () => {
// Test implementation
})
it('handles empty query gracefully', async () => {
// Test edge case
})
it('falls back to substring search when Redis unavailable', async () => {
// Test fallback behavior
})
it('sorts results by similarity score', async () => {
// Test sorting logic
})
})
```
### Step 3: Run Tests (They Should Fail)
```bash
npm test
# Tests should fail - we haven't implemented yet
```
### Step 4: Implement Code
Write minimal code to make tests pass:
```typescript
// Implementation guided by tests
export async function searchMarkets(query: string) {
// Implementation here
}
```
### Step 5: Run Tests Again
```bash
npm test
# Tests should now pass
```
### Step 6: Refactor
Improve code quality while keeping tests green:
- Remove duplication
- Improve naming
- Optimize performance
- Enhance readability
### Step 7: Verify Coverage
```bash
npm run test:coverage
# Verify 80%+ coverage achieved
```
## Testing Patterns
### Unit Test Pattern (Jest/Vitest)
```typescript
import { render, screen, fireEvent } from '@testing-library/react'
import { Button } from './Button'
describe('Button Component', () => {
it('renders with correct text', () => {
render(<Button>Click me</Button>)
expect(screen.getByText('Click me')).toBeInTheDocument()
})
it('calls onClick when clicked', () => {
const handleClick = jest.fn()
render(<Button onClick={handleClick}>Click</Button>)
fireEvent.click(screen.getByRole('button'))
expect(handleClick).toHaveBeenCalledTimes(1)
})
it('is disabled when disabled prop is true', () => {
render(<Button disabled>Click</Button>)
expect(screen.getByRole('button')).toBeDisabled()
})
})
```
### API Integration Test Pattern
```typescript
import { NextRequest } from 'next/server'
import { GET } from './route'
describe('GET /api/markets', () => {
it('returns markets successfully', async () => {
const request = new NextRequest('http://localhost/api/markets')
const response = await GET(request)
const data = await response.json()
expect(response.status).toBe(200)
expect(data.success).toBe(true)
expect(Array.isArray(data.data)).toBe(true)
})
it('validates query parameters', async () => {
const request = new NextRequest('http://localhost/api/markets?limit=invalid')
const response = await GET(request)
expect(response.status).toBe(400)
})
it('handles database errors gracefully', async () => {
// Mock database failure
const request = new NextRequest('http://localhost/api/markets')
// Test error handling
})
})
```
### E2E Test Pattern (Playwright)
```typescript
import { test, expect } from '@playwright/test'
test('user can search and filter markets', async ({ page }) => {
// Navigate to markets page
await page.goto('/')
await page.click('a[href="/markets"]')
// Verify page loaded
await expect(page.locator('h1')).toContainText('Markets')
// Search for markets
await page.fill('input[placeholder="Search markets"]', 'election')
// Wait for debounce and results
await page.waitForTimeout(600)
// Verify search results displayed
const results = page.locator('[data-testid="market-card"]')
await expect(results).toHaveCount(5, { timeout: 5000 })
// Verify results contain search term
const firstResult = results.first()
await expect(firstResult).toContainText('election', { ignoreCase: true })
// Filter by status
await page.click('button:has-text("Active")')
// Verify filtered results
await expect(results).toHaveCount(3)
})
test('user can create a new market', async ({ page }) => {
// Login first
await page.goto('/creator-dashboard')
// Fill market creation form
await page.fill('input[name="name"]', 'Test Market')
await page.fill('textarea[name="description"]', 'Test description')
await page.fill('input[name="endDate"]', '2025-12-31')
// Submit form
await page.click('button[type="submit"]')
// Verify success message
await expect(page.locator('text=Market created successfully')).toBeVisible()
// Verify redirect to market page
await expect(page).toHaveURL(/\/markets\/test-market/)
})
```
## Test File Organization
```
src/
├── components/
│ ├── Button/
│ │ ├── Button.tsx
│ │ ├── Button.test.tsx # Unit tests
│ │ └── Button.stories.tsx # Storybook
│ └── MarketCard/
│ ├── MarketCard.tsx
│ └── MarketCard.test.tsx
├── app/
│ └── api/
│ └── markets/
│ ├── route.ts
│ └── route.test.ts # Integration tests
└── e2e/
├── markets.spec.ts # E2E tests
├── trading.spec.ts
└── auth.spec.ts
```
## Mocking External Services
### Supabase Mock
```typescript
jest.mock('@/lib/supabase', () => ({
supabase: {
from: jest.fn(() => ({
select: jest.fn(() => ({
eq: jest.fn(() => Promise.resolve({
data: [{ id: 1, name: 'Test Market' }],
error: null
}))
}))
}))
}
}))
```
### Redis Mock
```typescript
jest.mock('@/lib/redis', () => ({
searchMarketsByVector: jest.fn(() => Promise.resolve([
{ slug: 'test-market', similarity_score: 0.95 }
])),
checkRedisHealth: jest.fn(() => Promise.resolve({ connected: true }))
}))
```
### OpenAI Mock
```typescript
jest.mock('@/lib/openai', () => ({
generateEmbedding: jest.fn(() => Promise.resolve(
new Array(1536).fill(0.1) // Mock 1536-dim embedding
))
}))
```
## Test Coverage Verification
### Run Coverage Report
```bash
npm run test:coverage
```
### Coverage Thresholds
```json
{
"jest": {
"coverageThresholds": {
"global": {
"branches": 80,
"functions": 80,
"lines": 80,
"statements": 80
}
}
}
}
```
## Common Testing Mistakes to Avoid
### FAIL: WRONG: Testing Implementation Details
```typescript
// Don't test internal state
expect(component.state.count).toBe(5)
```
### PASS: CORRECT: Test User-Visible Behavior
```typescript
// Test what users see
expect(screen.getByText('Count: 5')).toBeInTheDocument()
```
### FAIL: WRONG: Brittle Selectors
```typescript
// Breaks easily
await page.click('.css-class-xyz')
```
### PASS: CORRECT: Semantic Selectors
```typescript
// Resilient to changes
await page.click('button:has-text("Submit")')
await page.click('[data-testid="submit-button"]')
```
### FAIL: WRONG: No Test Isolation
```typescript
// Tests depend on each other
test('creates user', () => { /* ... */ })
test('updates same user', () => { /* depends on previous test */ })
```
### PASS: CORRECT: Independent Tests
```typescript
// Each test sets up its own data
test('creates user', () => {
const user = createTestUser()
// Test logic
})
test('updates user', () => {
const user = createTestUser()
// Update logic
})
```
## Continuous Testing
### Watch Mode During Development
```bash
npm test -- --watch
# Tests run automatically on file changes
```
### Pre-Commit Hook
```bash
# Runs before every commit
npm test && npm run lint
```
### CI/CD Integration
```yaml
# GitHub Actions
- name: Run Tests
run: npm test -- --coverage
- name: Upload Coverage
uses: codecov/codecov-action@v3
```
## Best Practices
1. **Write Tests First** - Always TDD
2. **One Assert Per Test** - Focus on single behavior
3. **Descriptive Test Names** - Explain what's tested
4. **Arrange-Act-Assert** - Clear test structure
5. **Mock External Dependencies** - Isolate unit tests
6. **Test Edge Cases** - Null, undefined, empty, large
7. **Test Error Paths** - Not just happy paths
8. **Keep Tests Fast** - Unit tests < 50ms each
9. **Clean Up After Tests** - No side effects
10. **Review Coverage Reports** - Identify gaps
## Success Metrics
- 80%+ code coverage achieved
- All tests passing (green)
- No skipped or disabled tests
- Fast test execution (< 30s for unit tests)
- E2E tests cover critical user flows
- Tests catch bugs before production
---
**Remember**: Tests are not optional. They are the safety net that enables confident refactoring, rapid development, and production reliability.

View File

@ -0,0 +1,7 @@
interface:
display_name: "TDD Workflow"
short_description: "Test-driven development with 80%+ coverage"
brand_color: "#22C55E"
default_prompt: "Follow TDD: write tests first, implement, verify 80%+ coverage"
policy:
allow_implicit_invocation: true