crucible-mcp 0.5.0__tar.gz → 1.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. crucible_mcp-1.0.1/PKG-INFO +198 -0
  2. crucible_mcp-1.0.1/README.md +180 -0
  3. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/pyproject.toml +8 -1
  4. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible/cli.py +109 -2
  5. crucible_mcp-1.0.1/src/crucible/enforcement/bundled/error-handling.yaml +84 -0
  6. crucible_mcp-1.0.1/src/crucible/enforcement/bundled/security.yaml +123 -0
  7. crucible_mcp-1.0.1/src/crucible/enforcement/bundled/smart-contract.yaml +110 -0
  8. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible/enforcement/compliance.py +9 -5
  9. crucible_mcp-1.0.1/src/crucible/hooks/claudecode.py +388 -0
  10. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible/hooks/precommit.py +117 -25
  11. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible/knowledge/loader.py +186 -0
  12. crucible_mcp-1.0.1/src/crucible/knowledge/principles/API_DESIGN.md +176 -0
  13. crucible_mcp-1.0.1/src/crucible/knowledge/principles/COMMITS.md +127 -0
  14. crucible_mcp-1.0.1/src/crucible/knowledge/principles/DATABASE.md +138 -0
  15. crucible_mcp-1.0.1/src/crucible/knowledge/principles/DOCUMENTATION.md +201 -0
  16. crucible_mcp-1.0.1/src/crucible/knowledge/principles/ERROR_HANDLING.md +157 -0
  17. crucible_mcp-1.0.1/src/crucible/knowledge/principles/FP.md +162 -0
  18. crucible_mcp-1.0.1/src/crucible/knowledge/principles/GITIGNORE.md +218 -0
  19. crucible_mcp-1.0.1/src/crucible/knowledge/principles/OBSERVABILITY.md +147 -0
  20. crucible_mcp-1.0.1/src/crucible/knowledge/principles/PRECOMMIT.md +201 -0
  21. crucible_mcp-1.0.1/src/crucible/knowledge/principles/SECURITY.md +136 -0
  22. crucible_mcp-1.0.1/src/crucible/knowledge/principles/SMART_CONTRACT.md +153 -0
  23. crucible_mcp-1.0.1/src/crucible/knowledge/principles/SYSTEM_DESIGN.md +153 -0
  24. crucible_mcp-1.0.1/src/crucible/knowledge/principles/TESTING.md +129 -0
  25. crucible_mcp-1.0.1/src/crucible/knowledge/principles/TYPE_SAFETY.md +170 -0
  26. crucible_mcp-1.0.1/src/crucible/skills/accessibility-engineer/SKILL.md +71 -0
  27. crucible_mcp-1.0.1/src/crucible/skills/backend-engineer/SKILL.md +69 -0
  28. crucible_mcp-1.0.1/src/crucible/skills/customer-success/SKILL.md +69 -0
  29. crucible_mcp-1.0.1/src/crucible/skills/data-engineer/SKILL.md +70 -0
  30. crucible_mcp-1.0.1/src/crucible/skills/devops-engineer/SKILL.md +69 -0
  31. crucible_mcp-1.0.1/src/crucible/skills/fde-engineer/SKILL.md +69 -0
  32. crucible_mcp-1.0.1/src/crucible/skills/formal-verification/SKILL.md +86 -0
  33. crucible_mcp-1.0.1/src/crucible/skills/gas-optimizer/SKILL.md +89 -0
  34. crucible_mcp-1.0.1/src/crucible/skills/incident-responder/SKILL.md +91 -0
  35. crucible_mcp-1.0.1/src/crucible/skills/mev-researcher/SKILL.md +87 -0
  36. crucible_mcp-1.0.1/src/crucible/skills/mobile-engineer/SKILL.md +70 -0
  37. crucible_mcp-1.0.1/src/crucible/skills/performance-engineer/SKILL.md +68 -0
  38. crucible_mcp-1.0.1/src/crucible/skills/product-engineer/SKILL.md +68 -0
  39. crucible_mcp-1.0.1/src/crucible/skills/protocol-architect/SKILL.md +83 -0
  40. crucible_mcp-1.0.1/src/crucible/skills/security-engineer/SKILL.md +63 -0
  41. crucible_mcp-1.0.1/src/crucible/skills/tech-lead/SKILL.md +92 -0
  42. crucible_mcp-1.0.1/src/crucible/skills/uiux-engineer/SKILL.md +70 -0
  43. crucible_mcp-1.0.1/src/crucible/skills/web3-engineer/SKILL.md +79 -0
  44. crucible_mcp-1.0.1/src/crucible_mcp.egg-info/PKG-INFO +198 -0
  45. crucible_mcp-1.0.1/src/crucible_mcp.egg-info/SOURCES.txt +83 -0
  46. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/tests/test_cli.py +5 -5
  47. crucible_mcp-0.5.0/PKG-INFO +0 -161
  48. crucible_mcp-0.5.0/README.md +0 -143
  49. crucible_mcp-0.5.0/src/crucible_mcp.egg-info/PKG-INFO +0 -161
  50. crucible_mcp-0.5.0/src/crucible_mcp.egg-info/SOURCES.txt +0 -47
  51. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/setup.cfg +0 -0
  52. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible/__init__.py +0 -0
  53. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible/domain/__init__.py +0 -0
  54. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible/domain/detection.py +0 -0
  55. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible/enforcement/__init__.py +0 -0
  56. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible/enforcement/assertions.py +0 -0
  57. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible/enforcement/budget.py +0 -0
  58. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible/enforcement/models.py +0 -0
  59. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible/enforcement/patterns.py +0 -0
  60. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible/errors.py +0 -0
  61. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible/hooks/__init__.py +0 -0
  62. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible/knowledge/__init__.py +0 -0
  63. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible/models.py +0 -0
  64. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible/review/__init__.py +0 -0
  65. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible/review/core.py +0 -0
  66. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible/server.py +0 -0
  67. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible/skills/__init__.py +0 -0
  68. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible/skills/loader.py +0 -0
  69. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible/synthesis/__init__.py +0 -0
  70. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible/tools/__init__.py +0 -0
  71. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible/tools/delegation.py +0 -0
  72. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible/tools/git.py +0 -0
  73. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible_mcp.egg-info/dependency_links.txt +0 -0
  74. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible_mcp.egg-info/entry_points.txt +0 -0
  75. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible_mcp.egg-info/requires.txt +0 -0
  76. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/src/crucible_mcp.egg-info/top_level.txt +0 -0
  77. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/tests/test_compliance.py +0 -0
  78. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/tests/test_detection.py +0 -0
  79. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/tests/test_enforcement.py +0 -0
  80. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/tests/test_full_review.py +0 -0
  81. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/tests/test_git.py +0 -0
  82. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/tests/test_hooks_cli.py +0 -0
  83. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/tests/test_integration.py +0 -0
  84. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/tests/test_knowledge.py +0 -0
  85. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/tests/test_precommit.py +0 -0
  86. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/tests/test_server.py +0 -0
  87. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/tests/test_skills.py +0 -0
  88. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/tests/test_skills_loader.py +0 -0
  89. {crucible_mcp-0.5.0 → crucible_mcp-1.0.1}/tests/test_tools.py +0 -0
@@ -0,0 +1,198 @@
1
+ Metadata-Version: 2.4
2
+ Name: crucible-mcp
3
+ Version: 1.0.1
4
+ Summary: Code review MCP server for Claude. Not affiliated with Atlassian.
5
+ Author: be.nvy
6
+ License-Expression: MIT
7
+ Keywords: mcp,code-review,static-analysis,claude
8
+ Requires-Python: >=3.11
9
+ Description-Content-Type: text/markdown
10
+ Requires-Dist: mcp>=1.0.0
11
+ Requires-Dist: pyyaml>=6.0
12
+ Requires-Dist: anthropic>=0.40.0
13
+ Provides-Extra: dev
14
+ Requires-Dist: pytest>=8.0; extra == "dev"
15
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
16
+ Requires-Dist: mypy>=1.8; extra == "dev"
17
+ Requires-Dist: ruff>=0.3; extra == "dev"
18
+
19
+ # Crucible
20
+
21
+ **Your team's standards, applied by Claude, every time.**
22
+
23
+ Claude without context applies generic best practices. Crucible loads *your* patterns—so Claude reviews code the way your team would, not the way the internet would.
24
+
25
+ ```
26
+ ├── Enforcement: Pattern + LLM assertions that block bad code
27
+ ├── Personas: Domain-specific thinking (how to approach problems)
28
+ ├── Knowledge: Coding patterns and principles (what to apply)
29
+ ├── Cascade: Project → User → Bundled (customizable at every level)
30
+ └── Context-aware: Loads relevant skills based on what you're working on
31
+ ```
32
+
33
+ **Why Crucible?**
34
+ - **Enforcement** — Not suggestions, constraints. Assertions block code that violates your patterns
35
+ - **Consistency** — Same checklist every time, for every engineer, every session
36
+ - **Automation** — Runs in CI, pre-commit hooks, and Claude Code hooks
37
+ - **Institutional knowledge** — Your senior engineer's mental checklist, in the repo
38
+ - **Your context** — Security fundamentals plus *your* auth patterns, *your* conventions
39
+ - **Cost efficiency** — Filter with free tools first, LLM only on what needs judgment
40
+
41
+ > Not affiliated with Atlassian's Crucible.
42
+
43
+ ## Quick Start
44
+
45
+ ```bash
46
+ pip install crucible-mcp
47
+
48
+ # Initialize your project
49
+ crucible init --with-claudemd
50
+
51
+ # Install enforcement hooks
52
+ crucible hooks install # Git pre-commit
53
+ crucible hooks claudecode init # Claude Code hooks
54
+ ```
55
+
56
+ That's it. Crucible will now:
57
+ 1. Run on every commit (pre-commit hook)
58
+ 2. Review files Claude edits (Claude Code hook)
59
+ 3. Block code that violates bundled assertions (security, error handling, smart contracts)
60
+
61
+ ## How Enforcement Works
62
+
63
+ ```
64
+ Claude writes code
65
+
66
+ PostToolUse hook triggers
67
+
68
+ Crucible runs pattern assertions
69
+
70
+ Finding detected → Exit 2 (block) + feedback to Claude
71
+
72
+ Claude fixes the issue
73
+ ```
74
+
75
+ **30 bundled assertions** covering:
76
+ - Security: eval, exec, shell injection, pickle, hardcoded secrets, SQL injection
77
+ - Error handling: bare except, silent catch, empty catch blocks
78
+ - Smart contracts: reentrancy, CEI violations, access control, tx.origin auth
79
+
80
+ **Customize with your own assertions** in `.crucible/assertions/`:
81
+
82
+ ```yaml
83
+ # .crucible/assertions/my-rules.yaml
84
+ version: "1.0"
85
+ name: my-rules
86
+ assertions:
87
+ - id: no-console-log
88
+ type: pattern
89
+ pattern: "console\\.log\\("
90
+ message: "Remove console.log before committing"
91
+ severity: warning
92
+ priority: medium
93
+ languages: [javascript, typescript]
94
+ ```
95
+
96
+ ## MCP Tools
97
+
98
+ Add to Claude Code (`.mcp.json`):
99
+
100
+ ```json
101
+ {
102
+ "mcpServers": {
103
+ "crucible": {
104
+ "command": "crucible-mcp"
105
+ }
106
+ }
107
+ }
108
+ ```
109
+
110
+ | Tool | Purpose |
111
+ |------|---------|
112
+ | `review(path)` | Full review: analysis + skills + knowledge + assertions |
113
+ | `review(mode='staged')` | Review git changes with enforcement |
114
+ | `load_knowledge(files)` | Load specific knowledge files |
115
+ | `get_principles(topic)` | Load engineering knowledge by topic |
116
+ | `delegate_*` | Direct tool access (semgrep, ruff, slither, bandit) |
117
+ | `check_tools()` | Show installed analysis tools |
118
+
119
+ ## CLI
120
+
121
+ ```bash
122
+ # Review
123
+ crucible review # Review staged changes
124
+ crucible review --mode branch # Review current branch vs main
125
+ crucible review src/file.py --no-git # Review without git
126
+
127
+ # Assertions
128
+ crucible assertions list # List all assertion files
129
+ crucible assertions test file.py # Test assertions against a file
130
+
131
+ # Hooks
132
+ crucible hooks install # Install pre-commit hook
133
+ crucible hooks claudecode init # Initialize Claude Code hooks
134
+
135
+ # Customize
136
+ crucible skills init <skill> # Copy skill for customization
137
+ crucible knowledge init <file> # Copy knowledge for customization
138
+
139
+ # CI
140
+ crucible ci generate # Generate GitHub Actions workflow
141
+ ```
142
+
143
+ ## Customization
144
+
145
+ Everything follows cascade resolution (first found wins):
146
+ 1. `.crucible/` — Project overrides (checked into repo)
147
+ 2. `~/.claude/crucible/` — User preferences
148
+ 3. Bundled — Package defaults
149
+
150
+ **Override a skill:**
151
+ ```bash
152
+ crucible skills init security-engineer
153
+ # Edit .crucible/skills/security-engineer/SKILL.md
154
+ ```
155
+
156
+ **Add project knowledge:**
157
+ ```bash
158
+ crucible knowledge init SECURITY
159
+ # Edit .crucible/knowledge/SECURITY.md
160
+ ```
161
+
162
+ **Add custom assertions:**
163
+ ```bash
164
+ mkdir -p .crucible/assertions
165
+ # Create .crucible/assertions/my-rules.yaml
166
+ ```
167
+
168
+ See [CUSTOMIZATION.md](docs/CUSTOMIZATION.md) for the full guide.
169
+
170
+ ## What's Included
171
+
172
+ **30 Bundled Assertions** — Pattern rules for security, error handling, and smart contracts.
173
+
174
+ **18 Personas** — Domain-specific thinking: security, performance, accessibility, web3, backend, and more.
175
+
176
+ **14 Knowledge Files** — Coding patterns and principles for security, testing, APIs, databases, smart contracts, etc.
177
+
178
+ See [SKILLS.md](docs/SKILLS.md) and [KNOWLEDGE.md](docs/KNOWLEDGE.md) for details.
179
+
180
+ ## Documentation
181
+
182
+ | Doc | What's In It |
183
+ |-----|--------------|
184
+ | [QUICKSTART.md](docs/QUICKSTART.md) | 5-minute setup guide |
185
+ | [FEATURES.md](docs/FEATURES.md) | Complete feature reference |
186
+ | [ARCHITECTURE.md](docs/ARCHITECTURE.md) | How MCP, tools, skills, and knowledge fit together |
187
+ | [CUSTOMIZATION.md](docs/CUSTOMIZATION.md) | Override skills and knowledge for your project |
188
+ | [SKILLS.md](docs/SKILLS.md) | All 18 personas with triggers and focus areas |
189
+ | [KNOWLEDGE.md](docs/KNOWLEDGE.md) | All 14 knowledge files with topics covered |
190
+ | [CONTRIBUTING.md](docs/CONTRIBUTING.md) | Adding tools, skills, and knowledge |
191
+
192
+ ## Development
193
+
194
+ ```bash
195
+ pip install -e ".[dev]"
196
+ pytest # Run tests (580+ tests)
197
+ ruff check src/ --fix # Lint
198
+ ```
@@ -0,0 +1,180 @@
1
+ # Crucible
2
+
3
+ **Your team's standards, applied by Claude, every time.**
4
+
5
+ Claude without context applies generic best practices. Crucible loads *your* patterns—so Claude reviews code the way your team would, not the way the internet would.
6
+
7
+ ```
8
+ ├── Enforcement: Pattern + LLM assertions that block bad code
9
+ ├── Personas: Domain-specific thinking (how to approach problems)
10
+ ├── Knowledge: Coding patterns and principles (what to apply)
11
+ ├── Cascade: Project → User → Bundled (customizable at every level)
12
+ └── Context-aware: Loads relevant skills based on what you're working on
13
+ ```
14
+
15
+ **Why Crucible?**
16
+ - **Enforcement** — Not suggestions, constraints. Assertions block code that violates your patterns
17
+ - **Consistency** — Same checklist every time, for every engineer, every session
18
+ - **Automation** — Runs in CI, pre-commit hooks, and Claude Code hooks
19
+ - **Institutional knowledge** — Your senior engineer's mental checklist, in the repo
20
+ - **Your context** — Security fundamentals plus *your* auth patterns, *your* conventions
21
+ - **Cost efficiency** — Filter with free tools first, LLM only on what needs judgment
22
+
23
+ > Not affiliated with Atlassian's Crucible.
24
+
25
+ ## Quick Start
26
+
27
+ ```bash
28
+ pip install crucible-mcp
29
+
30
+ # Initialize your project
31
+ crucible init --with-claudemd
32
+
33
+ # Install enforcement hooks
34
+ crucible hooks install # Git pre-commit
35
+ crucible hooks claudecode init # Claude Code hooks
36
+ ```
37
+
38
+ That's it. Crucible will now:
39
+ 1. Run on every commit (pre-commit hook)
40
+ 2. Review files Claude edits (Claude Code hook)
41
+ 3. Block code that violates bundled assertions (security, error handling, smart contracts)
42
+
43
+ ## How Enforcement Works
44
+
45
+ ```
46
+ Claude writes code
47
+
48
+ PostToolUse hook triggers
49
+
50
+ Crucible runs pattern assertions
51
+
52
+ Finding detected → Exit 2 (block) + feedback to Claude
53
+
54
+ Claude fixes the issue
55
+ ```
56
+
57
+ **30 bundled assertions** covering:
58
+ - Security: eval, exec, shell injection, pickle, hardcoded secrets, SQL injection
59
+ - Error handling: bare except, silent catch, empty catch blocks
60
+ - Smart contracts: reentrancy, CEI violations, access control, tx.origin auth
61
+
62
+ **Customize with your own assertions** in `.crucible/assertions/`:
63
+
64
+ ```yaml
65
+ # .crucible/assertions/my-rules.yaml
66
+ version: "1.0"
67
+ name: my-rules
68
+ assertions:
69
+ - id: no-console-log
70
+ type: pattern
71
+ pattern: "console\\.log\\("
72
+ message: "Remove console.log before committing"
73
+ severity: warning
74
+ priority: medium
75
+ languages: [javascript, typescript]
76
+ ```
77
+
78
+ ## MCP Tools
79
+
80
+ Add to Claude Code (`.mcp.json`):
81
+
82
+ ```json
83
+ {
84
+ "mcpServers": {
85
+ "crucible": {
86
+ "command": "crucible-mcp"
87
+ }
88
+ }
89
+ }
90
+ ```
91
+
92
+ | Tool | Purpose |
93
+ |------|---------|
94
+ | `review(path)` | Full review: analysis + skills + knowledge + assertions |
95
+ | `review(mode='staged')` | Review git changes with enforcement |
96
+ | `load_knowledge(files)` | Load specific knowledge files |
97
+ | `get_principles(topic)` | Load engineering knowledge by topic |
98
+ | `delegate_*` | Direct tool access (semgrep, ruff, slither, bandit) |
99
+ | `check_tools()` | Show installed analysis tools |
100
+
101
+ ## CLI
102
+
103
+ ```bash
104
+ # Review
105
+ crucible review # Review staged changes
106
+ crucible review --mode branch # Review current branch vs main
107
+ crucible review src/file.py --no-git # Review without git
108
+
109
+ # Assertions
110
+ crucible assertions list # List all assertion files
111
+ crucible assertions test file.py # Test assertions against a file
112
+
113
+ # Hooks
114
+ crucible hooks install # Install pre-commit hook
115
+ crucible hooks claudecode init # Initialize Claude Code hooks
116
+
117
+ # Customize
118
+ crucible skills init <skill> # Copy skill for customization
119
+ crucible knowledge init <file> # Copy knowledge for customization
120
+
121
+ # CI
122
+ crucible ci generate # Generate GitHub Actions workflow
123
+ ```
124
+
125
+ ## Customization
126
+
127
+ Everything follows cascade resolution (first found wins):
128
+ 1. `.crucible/` — Project overrides (checked into repo)
129
+ 2. `~/.claude/crucible/` — User preferences
130
+ 3. Bundled — Package defaults
131
+
132
+ **Override a skill:**
133
+ ```bash
134
+ crucible skills init security-engineer
135
+ # Edit .crucible/skills/security-engineer/SKILL.md
136
+ ```
137
+
138
+ **Add project knowledge:**
139
+ ```bash
140
+ crucible knowledge init SECURITY
141
+ # Edit .crucible/knowledge/SECURITY.md
142
+ ```
143
+
144
+ **Add custom assertions:**
145
+ ```bash
146
+ mkdir -p .crucible/assertions
147
+ # Create .crucible/assertions/my-rules.yaml
148
+ ```
149
+
150
+ See [CUSTOMIZATION.md](docs/CUSTOMIZATION.md) for the full guide.
151
+
152
+ ## What's Included
153
+
154
+ **30 Bundled Assertions** — Pattern rules for security, error handling, and smart contracts.
155
+
156
+ **18 Personas** — Domain-specific thinking: security, performance, accessibility, web3, backend, and more.
157
+
158
+ **14 Knowledge Files** — Coding patterns and principles for security, testing, APIs, databases, smart contracts, etc.
159
+
160
+ See [SKILLS.md](docs/SKILLS.md) and [KNOWLEDGE.md](docs/KNOWLEDGE.md) for details.
161
+
162
+ ## Documentation
163
+
164
+ | Doc | What's In It |
165
+ |-----|--------------|
166
+ | [QUICKSTART.md](docs/QUICKSTART.md) | 5-minute setup guide |
167
+ | [FEATURES.md](docs/FEATURES.md) | Complete feature reference |
168
+ | [ARCHITECTURE.md](docs/ARCHITECTURE.md) | How MCP, tools, skills, and knowledge fit together |
169
+ | [CUSTOMIZATION.md](docs/CUSTOMIZATION.md) | Override skills and knowledge for your project |
170
+ | [SKILLS.md](docs/SKILLS.md) | All 18 personas with triggers and focus areas |
171
+ | [KNOWLEDGE.md](docs/KNOWLEDGE.md) | All 14 knowledge files with topics covered |
172
+ | [CONTRIBUTING.md](docs/CONTRIBUTING.md) | Adding tools, skills, and knowledge |
173
+
174
+ ## Development
175
+
176
+ ```bash
177
+ pip install -e ".[dev]"
178
+ pytest # Run tests (580+ tests)
179
+ ruff check src/ --fix # Lint
180
+ ```
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "crucible-mcp"
3
- version = "0.5.0"
3
+ version = "1.0.1"
4
4
  description = "Code review MCP server for Claude. Not affiliated with Atlassian."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -33,6 +33,13 @@ build-backend = "setuptools.build_meta"
33
33
  [tool.setuptools.packages.find]
34
34
  where = ["src"]
35
35
 
36
+ [tool.setuptools.package-data]
37
+ crucible = [
38
+ "skills/**/*.md",
39
+ "knowledge/principles/*.md",
40
+ "enforcement/bundled/*.yaml",
41
+ ]
42
+
36
43
  [tool.ruff]
37
44
  line-length = 100
38
45
  target-version = "py311"
@@ -578,6 +578,27 @@ def _cmd_review_no_git(args: argparse.Namespace, path: str) -> int:
578
578
  # Deduplicate
579
579
  all_findings = deduplicate_findings(all_findings)
580
580
 
581
+ # Run enforcement assertions
582
+ from crucible.review.core import run_enforcement
583
+
584
+ compliance_config = _build_compliance_config(
585
+ config,
586
+ cli_token_budget=getattr(args, "token_budget", None),
587
+ cli_model=getattr(args, "compliance_model", None),
588
+ cli_no_compliance=getattr(args, "no_compliance", False),
589
+ )
590
+
591
+ # Use current directory as repo root for enforcement
592
+ enforcement_findings, enforcement_errors, assertions_checked, assertions_skipped, budget_state = (
593
+ run_enforcement(
594
+ ".",
595
+ changed_files=files_to_analyze,
596
+ repo_root=".",
597
+ compliance_config=compliance_config,
598
+ )
599
+ )
600
+ tool_errors.extend(enforcement_errors)
601
+
581
602
  # Compute severity summary
582
603
  severity_counts = compute_severity_counts(all_findings)
583
604
 
@@ -607,6 +628,21 @@ def _cmd_review_no_git(args: argparse.Namespace, path: str) -> int:
607
628
  }
608
629
  for f in all_findings
609
630
  ],
631
+ "enforcement": {
632
+ "findings": [
633
+ {
634
+ "assertion_id": f.assertion_id,
635
+ "severity": f.severity,
636
+ "message": f.message,
637
+ "location": f.location,
638
+ "source": f.source,
639
+ }
640
+ for f in enforcement_findings
641
+ ],
642
+ "assertions_checked": assertions_checked,
643
+ "assertions_skipped": assertions_skipped,
644
+ "tokens_used": budget_state.tokens_used if budget_state else 0,
645
+ },
610
646
  "severity_counts": severity_counts,
611
647
  "passed": passed,
612
648
  "threshold": default_threshold.value if default_threshold else None,
@@ -616,7 +652,7 @@ def _cmd_review_no_git(args: argparse.Namespace, path: str) -> int:
616
652
  else:
617
653
  # Text output
618
654
  if all_findings:
619
- print(f"\nFound {len(all_findings)} issue(s):\n")
655
+ print(f"\nFound {len(all_findings)} static analysis issue(s):\n")
620
656
  for f in all_findings:
621
657
  sev_icon = {"critical": "🔴", "high": "🟠", "medium": "🟡", "low": "🔵", "info": "⚪"}.get(
622
658
  f.severity.value, "⚪"
@@ -626,7 +662,18 @@ def _cmd_review_no_git(args: argparse.Namespace, path: str) -> int:
626
662
  if f.suggestion:
627
663
  print(f" 💡 {f.suggestion}")
628
664
  print()
629
- else:
665
+
666
+ # Enforcement findings
667
+ if enforcement_findings:
668
+ print(f"\nEnforcement Assertions ({len(enforcement_findings)}):")
669
+ for f in enforcement_findings:
670
+ sev_icon = {"error": "🔴", "warning": "🟠", "info": "⚪"}.get(f.severity, "⚪")
671
+ source_tag = "[LLM]" if f.source == "llm" else "[Pattern]"
672
+ print(f" {sev_icon} [{f.severity.upper()}] {source_tag} {f.assertion_id}: {f.location}")
673
+ print(f" {f.message}")
674
+ print()
675
+
676
+ if not all_findings and not enforcement_findings:
630
677
  print("\n✅ No issues found.")
631
678
 
632
679
  # Summary
@@ -634,6 +681,11 @@ def _cmd_review_no_git(args: argparse.Namespace, path: str) -> int:
634
681
  counts_str = ", ".join(f"{k}: {v}" for k, v in severity_counts.items() if v > 0)
635
682
  print(f"Summary: {counts_str}")
636
683
 
684
+ if assertions_checked or assertions_skipped:
685
+ print(f"Assertions: {assertions_checked} checked, {assertions_skipped} skipped")
686
+ if budget_state and budget_state.tokens_used > 0:
687
+ print(f" LLM tokens used: {budget_state.tokens_used}")
688
+
637
689
  if tool_errors and not args.quiet:
638
690
  print(f"\n⚠️ {len(tool_errors)} tool error(s)")
639
691
  for err in tool_errors[:5]:
@@ -1682,11 +1734,30 @@ include_context: false
1682
1734
  if not gitignore_path.exists():
1683
1735
  gitignore_path.write_text("# Local overrides (optional)\n*.local.md\n")
1684
1736
 
1737
+ # Create minimal CLAUDE.md if requested
1738
+ if args.with_claudemd:
1739
+ claudemd_path = project_path / "CLAUDE.md"
1740
+ if claudemd_path.exists() and not args.force:
1741
+ print(f"Warning: {claudemd_path} exists, skipping (use --force to overwrite)")
1742
+ else:
1743
+ project_name = project_path.name
1744
+ claudemd_content = f"""# {project_name}
1745
+
1746
+ Use Crucible for code review: `crucible review`
1747
+
1748
+ For full engineering principles and patterns, run:
1749
+ - `crucible knowledge list` - see available knowledge
1750
+ - `crucible skills list` - see available review personas
1751
+ """
1752
+ claudemd_path.write_text(claudemd_content)
1753
+ print(f"Created {claudemd_path}")
1754
+
1685
1755
  print(f"\nInitialized {crucible_dir}")
1686
1756
  print("\nNext steps:")
1687
1757
  print(" 1. Customize skills: crucible skills init <skill>")
1688
1758
  print(" 2. Customize knowledge: crucible knowledge init <file>")
1689
1759
  print(" 3. Install git hooks: crucible hooks install")
1760
+ print(" 4. Claude Code hooks: crucible hooks claudecode init")
1690
1761
  return 0
1691
1762
 
1692
1763
 
@@ -1950,6 +2021,28 @@ def main() -> int:
1950
2021
  "path", nargs="?", default=".", help="Repository path"
1951
2022
  )
1952
2023
 
2024
+ # hooks claudecode
2025
+ hooks_claudecode_parser = hooks_sub.add_parser(
2026
+ "claudecode",
2027
+ help="Claude Code hooks integration"
2028
+ )
2029
+ hooks_claudecode_sub = hooks_claudecode_parser.add_subparsers(dest="claudecode_command")
2030
+
2031
+ # hooks claudecode init
2032
+ hooks_cc_init_parser = hooks_claudecode_sub.add_parser(
2033
+ "init",
2034
+ help="Initialize Claude Code hooks for project"
2035
+ )
2036
+ hooks_cc_init_parser.add_argument(
2037
+ "path", nargs="?", default=".", help="Project path"
2038
+ )
2039
+
2040
+ # hooks claudecode hook (called by Claude Code)
2041
+ hooks_claudecode_sub.add_parser(
2042
+ "hook",
2043
+ help="Run hook (reads JSON from stdin)"
2044
+ )
2045
+
1953
2046
  # === review command ===
1954
2047
  review_parser = subparsers.add_parser(
1955
2048
  "review",
@@ -2044,6 +2137,10 @@ def main() -> int:
2044
2137
  "--minimal", action="store_true",
2045
2138
  help="Create minimal config without copying skills"
2046
2139
  )
2140
+ init_proj_parser.add_argument(
2141
+ "--with-claudemd", action="store_true",
2142
+ help="Generate minimal CLAUDE.md that points to Crucible"
2143
+ )
2047
2144
  init_proj_parser.add_argument(
2048
2145
  "path", nargs="?", default=".",
2049
2146
  help="Project path (default: current directory)"
@@ -2161,6 +2258,15 @@ def main() -> int:
2161
2258
  return cmd_hooks_uninstall(args)
2162
2259
  elif args.hooks_command == "status":
2163
2260
  return cmd_hooks_status(args)
2261
+ elif args.hooks_command == "claudecode":
2262
+ from crucible.hooks.claudecode import main_init, run_hook
2263
+ if args.claudecode_command == "init":
2264
+ return main_init(args.path)
2265
+ elif args.claudecode_command == "hook":
2266
+ return run_hook()
2267
+ else:
2268
+ hooks_claudecode_parser.print_help()
2269
+ return 0
2164
2270
  else:
2165
2271
  hooks_parser.print_help()
2166
2272
  return 0
@@ -2211,6 +2317,7 @@ def main() -> int:
2211
2317
  print(" crucible hooks install Install pre-commit hook to .git/hooks/")
2212
2318
  print(" crucible hooks uninstall Remove pre-commit hook")
2213
2319
  print(" crucible hooks status Show hook installation status")
2320
+ print(" crucible hooks claudecode init Initialize Claude Code hooks")
2214
2321
  print()
2215
2322
  print(" crucible assertions list List assertion files from all sources")
2216
2323
  print(" crucible assertions validate Validate assertion files")
@@ -0,0 +1,84 @@
1
+ version: "1.0"
2
+ name: error-handling
3
+ description: Error handling best practices to prevent silent failures
4
+ linked_knowledge: ERROR_HANDLING.md
5
+
6
+ assertions:
7
+ # High: Silent failures
8
+ - id: no-bare-except
9
+ type: pattern
10
+ pattern: "except\\s*:"
11
+ message: "Bare except catches everything including SystemExit/KeyboardInterrupt - catch specific exceptions"
12
+ severity: warning
13
+ priority: high
14
+ languages: [python]
15
+
16
+ - id: no-pass-in-except
17
+ type: pattern
18
+ pattern: "except[^:]*:\\s*\\n\\s*pass\\s*$"
19
+ message: "Empty except block silently swallows errors - log or re-raise"
20
+ severity: warning
21
+ priority: high
22
+ languages: [python]
23
+
24
+ - id: no-empty-catch
25
+ type: pattern
26
+ pattern: "catch\\s*\\([^)]*\\)\\s*\\{\\s*\\}"
27
+ message: "Empty catch block silently swallows errors - log or re-throw"
28
+ severity: warning
29
+ priority: high
30
+ languages: [javascript, typescript]
31
+
32
+ # Medium: Pokemon exception handling
33
+ - id: no-catch-exception
34
+ type: pattern
35
+ pattern: "except\\s+Exception\\s*:"
36
+ message: "Catching Exception is too broad - catch specific exception types"
37
+ severity: info
38
+ priority: medium
39
+ languages: [python]
40
+
41
+ - id: no-catch-base-exception
42
+ type: pattern
43
+ pattern: "except\\s+BaseException\\s*:"
44
+ message: "Catching BaseException includes SystemExit/KeyboardInterrupt - use Exception or specific types"
45
+ severity: warning
46
+ priority: medium
47
+ languages: [python]
48
+
49
+ # Medium: Error suppression
50
+ - id: no-ignore-errors-flag
51
+ type: pattern
52
+ pattern: "errors\\s*=\\s*[\"']ignore[\"']"
53
+ message: "errors='ignore' silently drops data - use 'replace' or handle explicitly"
54
+ severity: warning
55
+ priority: medium
56
+ languages: [python]
57
+
58
+ # Info: Best practices
59
+ - id: prefer-contextlib-suppress
60
+ type: pattern
61
+ pattern: "except\\s+\\w+\\s*:\\s*\\n\\s*pass\\s*$"
62
+ message: "Consider contextlib.suppress() for intentionally ignoring specific exceptions"
63
+ severity: info
64
+ priority: low
65
+ languages: [python]
66
+
67
+ # LLM assertion for complex error handling patterns
68
+ - id: error-handling-semantic
69
+ type: llm
70
+ compliance: |
71
+ Check that error handling follows best practices:
72
+ 1. Errors are not silently swallowed (no empty except/catch blocks that do nothing)
73
+ 2. Exceptions are logged or reported before being suppressed
74
+ 3. Error messages provide enough context to debug issues
75
+ 4. Errors at API/system boundaries are handled (not just propagated)
76
+ message: "Error handling may need improvement"
77
+ severity: warning
78
+ priority: medium
79
+ languages: [python, javascript, typescript]
80
+ applicability:
81
+ exclude:
82
+ - "**/test_*.py"
83
+ - "**/*_test.py"
84
+ - "**/tests/**"