claudia-mentor 0.1.0

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 (52) hide show
  1. package/.claude-plugin/plugin.json +9 -0
  2. package/LICENSE +21 -0
  3. package/README.md +219 -0
  4. package/commands/claudia-health.md +93 -0
  5. package/commands/claudia.md +27 -0
  6. package/config/defaults.json +25 -0
  7. package/hooks/hooks.json +77 -0
  8. package/hooks/scripts/check-accessibility.py +169 -0
  9. package/hooks/scripts/check-deps.py +119 -0
  10. package/hooks/scripts/check-dockerfile.py +176 -0
  11. package/hooks/scripts/check-git-hygiene.py +144 -0
  12. package/hooks/scripts/check-license.py +166 -0
  13. package/hooks/scripts/check-practices.py +169 -0
  14. package/hooks/scripts/check-secrets.sh +116 -0
  15. package/package.json +30 -0
  16. package/scripts/postinstall.js +29 -0
  17. package/skills/claudia-api/SKILL.md +96 -0
  18. package/skills/claudia-api/references/api-patterns.md +261 -0
  19. package/skills/claudia-api/references/graphql-grpc-trpc.md +161 -0
  20. package/skills/claudia-api/references/rest-design.md +234 -0
  21. package/skills/claudia-data/SKILL.md +85 -0
  22. package/skills/claudia-data/references/migrations-indexing.md +238 -0
  23. package/skills/claudia-data/references/schema-patterns.md +313 -0
  24. package/skills/claudia-databases/SKILL.md +77 -0
  25. package/skills/claudia-databases/references/sql-vs-nosql.md +72 -0
  26. package/skills/claudia-databases/references/time-series-graph.md +142 -0
  27. package/skills/claudia-databases/references/vector-databases.md +90 -0
  28. package/skills/claudia-devops/SKILL.md +111 -0
  29. package/skills/claudia-devops/references/cicd-pipelines.md +223 -0
  30. package/skills/claudia-devops/references/monitoring-incidents.md +217 -0
  31. package/skills/claudia-frontend/SKILL.md +99 -0
  32. package/skills/claudia-frontend/references/css-bundling.md +241 -0
  33. package/skills/claudia-frontend/references/frameworks-rendering.md +211 -0
  34. package/skills/claudia-frontend/references/state-management.md +195 -0
  35. package/skills/claudia-infrastructure/SKILL.md +108 -0
  36. package/skills/claudia-infrastructure/references/cloud-providers.md +136 -0
  37. package/skills/claudia-infrastructure/references/containers-orchestration.md +161 -0
  38. package/skills/claudia-infrastructure/references/serverless-edge.md +158 -0
  39. package/skills/claudia-mentor/SKILL.md +107 -0
  40. package/skills/claudia-mentor/references/personality.md +42 -0
  41. package/skills/claudia-mentor/references/prompt-coaching.md +60 -0
  42. package/skills/claudia-mentor/references/stack-detection.md +86 -0
  43. package/skills/claudia-performance/SKILL.md +111 -0
  44. package/skills/claudia-performance/references/backend-performance.md +306 -0
  45. package/skills/claudia-performance/references/frontend-performance.md +317 -0
  46. package/skills/claudia-security/SKILL.md +80 -0
  47. package/skills/claudia-security/references/auth-patterns.md +68 -0
  48. package/skills/claudia-security/references/secrets-management.md +58 -0
  49. package/skills/claudia-security/references/tees-sandboxing.md +75 -0
  50. package/skills/claudia-testing/SKILL.md +112 -0
  51. package/skills/claudia-testing/references/mocking-patterns.md +202 -0
  52. package/skills/claudia-testing/references/testing-approaches.md +144 -0
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "claudia-mentor",
3
+ "version": "0.1.0",
4
+ "description": "Proactive technology mentor, security advisor, and prompt coach for Claude Code. Catches bad practices, advises on architecture decisions, and coaches better prompting.",
5
+ "author": {
6
+ "name": "Regan O'Malley",
7
+ "email": "regan@reganomalley.com"
8
+ }
9
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Regan O'Malley
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,219 @@
1
+ # Claudia: Proactive Mentor Plugin for Claude Code
2
+
3
+ A Claude Code plugin that acts as your technology mentor, security advisor, and prompt coach. Claudia fills the gaps between writing code and making good technology decisions.
4
+
5
+ **10 knowledge domains. 7 automated hooks. Context-aware advice.**
6
+
7
+ ## What Claudia Does
8
+
9
+ - **Technology advising** -- Helps you choose databases, frameworks, APIs, infrastructure, and architecture patterns with clear trade-offs
10
+ - **Security guidance** -- Catches hardcoded secrets before they ship, advises on auth patterns and secrets management
11
+ - **Anti-pattern detection** -- Warns about common mistakes across code, Docker, dependencies, accessibility, and git hygiene
12
+ - **Prompt coaching** -- Detects vague prompts and suggests improvements to get better results from Claude
13
+ - **Context-aware** -- Reads your package.json, configs, and stack to give specific advice, not generic recommendations
14
+ - **Project health audits** -- `/claudia-health` scans your project for security, testing, dependency, and architecture issues
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ # Clone the plugin
20
+ git clone https://github.com/reganomalley/claudia.git ~/.claude/plugins/claudia
21
+
22
+ # Or install from npm
23
+ npm install -g claudia-mentor
24
+
25
+ # Enable in Claude Code
26
+ claude plugin add ~/.claude/plugins/claudia
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ ### Slash Commands
32
+
33
+ ```
34
+ /claudia what database should I use for time-series IoT data?
35
+ /claudia is JWT or session-based auth better for my SPA?
36
+ /claudia should I use REST or GraphQL for my mobile app?
37
+ /claudia how should I structure my CI/CD pipeline?
38
+ /claudia-health # Run a full project health audit
39
+ /claudia-health security # Focus on security issues
40
+ ```
41
+
42
+ ### Automatic (Model-Invoked)
43
+
44
+ Claudia automatically activates when you:
45
+ - Make technology decisions ("should I use MongoDB or Postgres?")
46
+ - Discuss architecture ("how should I structure this microservice?")
47
+ - Choose between frameworks ("React or Svelte for this project?")
48
+ - Write suboptimal prompts ("make it better")
49
+ - Introduce security anti-patterns
50
+
51
+ ### Hooks (Always Active)
52
+
53
+ **Secret detection** (blocks):
54
+ - AWS access keys, OpenAI/Stripe keys, GitHub tokens, GitLab PATs, Slack tokens
55
+ - Hardcoded passwords, secrets, and API keys
56
+ - Database connection strings with credentials
57
+ - Private keys
58
+
59
+ **Anti-pattern warnings** (advisory):
60
+ - `eval()` usage, `document.write()`, `innerHTML`
61
+ - `console.log` in production code
62
+ - Empty catch blocks
63
+ - HTTP URLs (non-HTTPS), disabled SSL verification
64
+ - SQL string concatenation
65
+ - `chmod 777`
66
+ - TODO/FIXME markers in new code
67
+
68
+ **Dependency audit** (advisory):
69
+ - Deprecated packages (moment, request, gulp)
70
+ - Compromised packages (colors, faker, event-stream)
71
+ - Trivial packages (is-odd, is-even, left-pad)
72
+
73
+ **Dockerfile lint** (advisory):
74
+ - Running as root, large base images, `:latest` tag
75
+ - Missing multi-stage builds, secrets in ENV
76
+ - npm install without --production
77
+
78
+ **Git hygiene** (blocks/advisory):
79
+ - Writing to .env files (blocks)
80
+ - Merge conflict markers in code (blocks)
81
+ - Large binary files (advisory)
82
+
83
+ **Accessibility** (advisory):
84
+ - Images without alt text
85
+ - Inputs without labels
86
+ - Icon-only buttons without aria-label
87
+ - Click handlers on non-interactive elements
88
+ - Positive tabIndex values
89
+
90
+ **License compliance** (advisory):
91
+ - Copyleft dependencies (GPL, AGPL, SSPL) in permissive-licensed projects
92
+
93
+ ## Knowledge Domains
94
+
95
+ ### Databases (`claudia-databases`)
96
+ - SQL vs NoSQL decision framework
97
+ - Vector databases for RAG/embeddings (pgvector, Pinecone, Qdrant)
98
+ - Time-series and graph database selection
99
+ - "Just use Postgres" rule (and when to break it)
100
+
101
+ ### Security (`claudia-security`)
102
+ - Authentication patterns (session, JWT, OAuth, passkeys)
103
+ - Secrets management lifecycle
104
+ - TEEs and sandboxing
105
+ - Common security mistakes with fixes
106
+
107
+ ### Infrastructure (`claudia-infrastructure`)
108
+ - AWS vs GCP vs Azure vs self-host
109
+ - Container orchestration (Docker, ECS, Cloud Run, k8s)
110
+ - Serverless decision framework
111
+ - Edge computing and cost estimation
112
+
113
+ ### Frontend (`claudia-frontend`)
114
+ - Framework selection (React, Vue, Svelte, Solid, Angular)
115
+ - SSR vs SPA vs SSG vs islands architecture
116
+ - State management (when to use what)
117
+ - CSS approaches, bundlers, Core Web Vitals
118
+
119
+ ### API Design (`claudia-api`)
120
+ - REST vs GraphQL vs gRPC vs tRPC
121
+ - API versioning, pagination, error handling
122
+ - Webhook design, rate limiting
123
+ - Real-time patterns (WebSockets, SSE, polling)
124
+
125
+ ### Testing (`claudia-testing`)
126
+ - Test pyramid and what to test at each level
127
+ - Framework comparison (Jest, Vitest, Playwright)
128
+ - Mocking patterns (and when NOT to mock)
129
+ - Testing strategy by app type
130
+
131
+ ### Performance (`claudia-performance`)
132
+ - "Measure before you optimize" framework
133
+ - Backend: N+1 queries, caching, connection pooling
134
+ - Frontend: Core Web Vitals, bundle optimization, image/font loading
135
+ - Profiling tools for Node.js and Python
136
+
137
+ ### DevOps (`claudia-devops`)
138
+ - CI/CD pipeline design (GitHub Actions patterns)
139
+ - Deployment strategies (rolling, blue-green, canary)
140
+ - Monitoring hierarchy and the four golden signals
141
+ - Incident response and SLI/SLO framework
142
+
143
+ ### Data Modeling (`claudia-data`)
144
+ - Schema design patterns (multi-tenancy, soft deletes, hierarchical data)
145
+ - Migration safety (zero-downtime patterns)
146
+ - Indexing strategy (B-tree, GIN, partial, composite)
147
+ - Normalization, denormalization, and anti-patterns
148
+
149
+ ### Prompt Coaching (built into mentor)
150
+ - Detects vague or underspecified prompts
151
+ - Suggests improvements across 5 quality dimensions
152
+ - Offers rewritten versions
153
+
154
+ ## Configuration
155
+
156
+ Override Claudia's personality and proactivity level:
157
+
158
+ ### Global (`~/.claude/claudia.json`)
159
+
160
+ ```json
161
+ {
162
+ "proactivity": "high",
163
+ "personality": {
164
+ "tone": "casual"
165
+ }
166
+ }
167
+ ```
168
+
169
+ ### Per-project (`.claudia.json` in project root)
170
+
171
+ ```json
172
+ {
173
+ "proactivity": "low",
174
+ "hooks": {
175
+ "check_practices": {
176
+ "enabled": false
177
+ }
178
+ }
179
+ }
180
+ ```
181
+
182
+ ### Proactivity Levels
183
+
184
+ | Level | Behavior |
185
+ |-------|----------|
186
+ | `low` | Only responds when you use `/claudia` |
187
+ | `moderate` | Proactive on security issues and major anti-patterns (default) |
188
+ | `high` | Flags any suboptimal pattern or technology decision |
189
+
190
+ ## Contributing
191
+
192
+ Claudia is designed for community contributions. The easiest ways to contribute:
193
+
194
+ ### Add Reference Files
195
+ Drop a new `.md` file in any `references/` directory. Follow the voice: opinionated, direct, explains why, uses concrete examples.
196
+
197
+ ### Add Anti-Patterns
198
+ Add entries to any hook script in `hooks/scripts/`.
199
+
200
+ ### New Knowledge Domains
201
+
202
+ Use the scaffolding tool:
203
+
204
+ ```bash
205
+ ./scripts/create-domain.sh architecture
206
+ ```
207
+
208
+ This creates the directory structure and template files. Fill in the SKILL.md, add reference files, and update the mentor's routing table.
209
+
210
+ ### Guidelines
211
+ - Be opinionated -- "it depends" without follow-up is not helpful
212
+ - Use decision trees and comparison tables
213
+ - Explain the "why" behind every recommendation
214
+ - Include "when NOT to use this" alongside recommendations
215
+ - Keep SKILL.md under ~2000 words, put depth in references
216
+
217
+ ## License
218
+
219
+ MIT
@@ -0,0 +1,93 @@
1
+ ---
2
+ description: Run a health check on the current project -- security, testing, architecture, dependencies
3
+ argument-hint: [optional: focus area like "security" or "deps"]
4
+ allowed-tools: [Read, Glob, Grep, Bash, WebSearch]
5
+ ---
6
+
7
+ # Claudia Health Check
8
+
9
+ You are Claudia, running a project health audit. Scan the current project and report findings.
10
+
11
+ **Focus area (optional):** $ARGUMENTS
12
+
13
+ ## Audit Process
14
+
15
+ ### 1. Discover the Stack
16
+
17
+ Read `package.json` (or `pyproject.toml`, `go.mod`, etc.) and scan for config files:
18
+
19
+ ```
20
+ Glob: **/package.json, **/tsconfig.json, **/Dockerfile, **/docker-compose.yml,
21
+ **/.env.example, **/prisma/schema.prisma, **/.github/workflows/*.yml,
22
+ **/vite.config.*, **/next.config.*, **/vitest.config.*, **/jest.config.*,
23
+ **/.eslintrc.*, **/tailwind.config.*
24
+ ```
25
+
26
+ ### 2. Run Checks
27
+
28
+ **Security:**
29
+ - [ ] .env file is gitignored (check `.gitignore`)
30
+ - [ ] No hardcoded secrets in source (grep for `sk-`, `AKIA`, `password =`)
31
+ - [ ] Dependencies don't have known vulnerabilities (run `npm audit --json` if Node.js)
32
+ - [ ] HTTPS enforced in configs
33
+ - [ ] CORS configured (not `*` in production)
34
+ - [ ] Auth library used (not hand-rolled)
35
+
36
+ **Testing:**
37
+ - [ ] Test framework configured (jest.config, vitest.config, pytest.ini)
38
+ - [ ] Tests exist (glob for `**/*.test.*`, `**/*.spec.*`, `**/test_*.py`)
39
+ - [ ] CI runs tests (check `.github/workflows/`)
40
+ - [ ] Test coverage configured
41
+
42
+ **Dependencies:**
43
+ - [ ] Lock file exists and tracked (package-lock.json, yarn.lock, pnpm-lock.yaml)
44
+ - [ ] No deprecated packages (check against known list)
45
+ - [ ] Node/Python version pinned (engines in package.json, .python-version, .nvmrc)
46
+ - [ ] devDependencies not in production dependencies
47
+
48
+ **Architecture:**
49
+ - [ ] README exists
50
+ - [ ] Environment variables documented (.env.example)
51
+ - [ ] Dockerfile uses multi-stage builds (if containerized)
52
+ - [ ] TypeScript strict mode enabled (if using TS)
53
+ - [ ] Linting configured
54
+
55
+ **Performance:**
56
+ - [ ] Images optimized (next/image, responsive images)
57
+ - [ ] Bundle analysis available
58
+ - [ ] Caching configured (Redis, CDN, HTTP cache headers)
59
+
60
+ ### 3. Report Format
61
+
62
+ Present findings as a health report:
63
+
64
+ ```
65
+ ## Project Health: [project-name]
66
+
67
+ **Stack:** [detected framework, DB, hosting]
68
+ **Overall:** [Good / Needs Attention / Critical Issues]
69
+
70
+ ### Security [score/5]
71
+ - [finding]
72
+ - [finding]
73
+
74
+ ### Testing [score/5]
75
+ - [finding]
76
+
77
+ ### Dependencies [score/5]
78
+ - [finding]
79
+
80
+ ### Architecture [score/5]
81
+ - [finding]
82
+
83
+ ### Top 3 Actions
84
+ 1. [most impactful fix]
85
+ 2. [second most impactful]
86
+ 3. [third]
87
+ ```
88
+
89
+ ### 4. Personality
90
+
91
+ Be direct. Don't soften findings. If something is bad, say it's bad and say how to fix it. But also acknowledge what's done well -- a clean security setup deserves a note.
92
+
93
+ If the user specified a focus area ($ARGUMENTS), go deeper on that area and lighter on others.
@@ -0,0 +1,27 @@
1
+ ---
2
+ description: Ask Claudia for technology advice, architecture guidance, or prompt coaching
3
+ argument-hint: <question about databases, security, architecture, or prompts>
4
+ allowed-tools: [Read, Glob, Grep, WebSearch, WebFetch]
5
+ ---
6
+
7
+ # Claudia: Technology Mentor
8
+
9
+ You are Claudia, a proactive technology mentor. The user is asking you a direct question.
10
+
11
+ **User's question:** $ARGUMENTS
12
+
13
+ ## How to Respond
14
+
15
+ 1. Read `${CLAUDE_PLUGIN_ROOT}/skills/claudia-mentor/SKILL.md` for your personality and routing logic.
16
+
17
+ 2. Determine the domain:
18
+ - **Database question** → Read `${CLAUDE_PLUGIN_ROOT}/skills/claudia-databases/SKILL.md` and relevant references
19
+ - **Security question** → Read `${CLAUDE_PLUGIN_ROOT}/skills/claudia-security/SKILL.md` and relevant references
20
+ - **Prompt quality** → Read `${CLAUDE_PLUGIN_ROOT}/skills/claudia-mentor/references/prompt-coaching.md`
21
+ - **General architecture/infra** → Use your knowledge + WebSearch for current information
22
+
23
+ 3. Check for personality overrides at `~/.claude/claudia.json` or `.claudia.json` in the current project.
24
+
25
+ 4. Respond following Claudia's personality: direct, explains why, uses analogies, admits uncertainty. Keep it focused -- direct answer, reasoning, trade-offs, next step.
26
+
27
+ 5. If the question is outside your knowledge base, use WebSearch to find current authoritative information. Clearly distinguish between what you know and what you looked up.
@@ -0,0 +1,25 @@
1
+ {
2
+ "personality": {
3
+ "name": "Claudia",
4
+ "tone": "direct",
5
+ "style": "explains-why",
6
+ "uses_analogies": true,
7
+ "admits_uncertainty": true
8
+ },
9
+ "proactivity": "moderate",
10
+ "proactivity_levels": {
11
+ "low": "Only responds when invoked via /claudia",
12
+ "moderate": "Proactive on security issues and major anti-patterns",
13
+ "high": "Proactive on any suboptimal pattern or decision"
14
+ },
15
+ "hooks": {
16
+ "check_secrets": {
17
+ "enabled": true,
18
+ "action": "block"
19
+ },
20
+ "check_practices": {
21
+ "enabled": true,
22
+ "action": "advisory"
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,77 @@
1
+ {
2
+ "description": "Claudia mentor hooks: security, anti-patterns, dependencies, Docker, git hygiene, accessibility, and license compliance",
3
+ "hooks": {
4
+ "PreToolUse": [
5
+ {
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/check-secrets.sh",
10
+ "timeout": 10
11
+ }
12
+ ],
13
+ "matcher": "Edit|Write|MultiEdit"
14
+ },
15
+ {
16
+ "hooks": [
17
+ {
18
+ "type": "command",
19
+ "command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/check-practices.py",
20
+ "timeout": 10
21
+ }
22
+ ],
23
+ "matcher": "Edit|Write|MultiEdit"
24
+ },
25
+ {
26
+ "hooks": [
27
+ {
28
+ "type": "command",
29
+ "command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/check-deps.py",
30
+ "timeout": 10
31
+ }
32
+ ],
33
+ "matcher": "Edit|Write|MultiEdit"
34
+ },
35
+ {
36
+ "hooks": [
37
+ {
38
+ "type": "command",
39
+ "command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/check-dockerfile.py",
40
+ "timeout": 10
41
+ }
42
+ ],
43
+ "matcher": "Edit|Write|MultiEdit"
44
+ },
45
+ {
46
+ "hooks": [
47
+ {
48
+ "type": "command",
49
+ "command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/check-git-hygiene.py",
50
+ "timeout": 10
51
+ }
52
+ ],
53
+ "matcher": "Edit|Write|MultiEdit"
54
+ },
55
+ {
56
+ "hooks": [
57
+ {
58
+ "type": "command",
59
+ "command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/check-accessibility.py",
60
+ "timeout": 10
61
+ }
62
+ ],
63
+ "matcher": "Edit|Write|MultiEdit"
64
+ },
65
+ {
66
+ "hooks": [
67
+ {
68
+ "type": "command",
69
+ "command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/check-license.py",
70
+ "timeout": 10
71
+ }
72
+ ],
73
+ "matcher": "Edit|Write|MultiEdit"
74
+ }
75
+ ]
76
+ }
77
+ }
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Claudia: check-accessibility.py
4
+ PreToolUse hook that warns on accessibility issues in HTML/JSX writes.
5
+ Advisory only (exit 0 with systemMessage), never blocks.
6
+ Session-aware dedup.
7
+ """
8
+
9
+ import json
10
+ import os
11
+ import re
12
+ import sys
13
+
14
+ # Accessibility patterns to check
15
+ # (pattern_regex, negative_pattern, description, advice, pattern_id)
16
+ # negative_pattern: if this matches, skip the warning (false positive prevention)
17
+ A11Y_PATTERNS = [
18
+ (
19
+ r'<img\b(?![^>]*\balt\b)',
20
+ None,
21
+ "Image without alt attribute",
22
+ "All `<img>` elements need an `alt` attribute. Use descriptive text, or `alt=\"\"` for decorative images.",
23
+ "a11y_img_alt",
24
+ ),
25
+ (
26
+ r'<input\b(?![^>]*\b(?:aria-label|aria-labelledby|id\s*=\s*["\'][^"\']+["\'])\b)(?![^>]*\btype\s*=\s*["\'](?:hidden|submit|button|reset)["\'])',
27
+ r'<label\b',
28
+ "Form input without label or aria-label",
29
+ "Inputs need associated labels. Use `<label htmlFor>`, `aria-label`, or `aria-labelledby`.",
30
+ "a11y_input_label",
31
+ ),
32
+ (
33
+ r'<button\b(?![^>]*\b(?:aria-label|aria-labelledby)\b)[^>]*>\s*<(?:img|svg|i|span\s+class)',
34
+ None,
35
+ "Icon-only button without accessible label",
36
+ "Buttons with only icons need `aria-label` to describe their action (e.g., `aria-label=\"Close\"`).",
37
+ "a11y_icon_button",
38
+ ),
39
+ (
40
+ r'onClick\s*=\s*\{[^}]+\}\s*(?:className|style)',
41
+ r'<(?:button|a|input|select|textarea)\b',
42
+ "Click handler on non-interactive element",
43
+ "Use `<button>` for clickable elements, not `<div onClick>`. Buttons are keyboard-accessible and announced by screen readers.",
44
+ "a11y_div_click",
45
+ ),
46
+ (
47
+ r'tabIndex\s*=\s*["\']?[1-9]',
48
+ None,
49
+ "Positive tabIndex value",
50
+ "Avoid positive `tabIndex` values. They override natural tab order and confuse keyboard users. Use `tabIndex={0}` or `-1`.",
51
+ "a11y_tabindex",
52
+ ),
53
+ (
54
+ r'<a\b(?![^>]*\bhref\b)',
55
+ None,
56
+ "Anchor tag without href",
57
+ "Use `<button>` for actions, `<a href>` for navigation. An `<a>` without `href` is not keyboard-accessible.",
58
+ "a11y_anchor_href",
59
+ ),
60
+ (
61
+ r'autoFocus|autofocus',
62
+ None,
63
+ "autoFocus attribute used",
64
+ "Avoid `autoFocus` -- it can disorient screen reader users and disrupt keyboard navigation. Let users control focus.",
65
+ "a11y_autofocus",
66
+ ),
67
+ (
68
+ r'<(?:h[1-6])\b[^>]*>\s*</(?:h[1-6])>',
69
+ None,
70
+ "Empty heading element",
71
+ "Headings should contain text content. Empty headings confuse screen readers navigating by heading structure.",
72
+ "a11y_empty_heading",
73
+ ),
74
+ ]
75
+
76
+ # File extensions to check
77
+ A11Y_EXTENSIONS = {'.html', '.htm', '.jsx', '.tsx', '.vue', '.svelte', '.astro'}
78
+
79
+
80
+ def get_state_file(session_id):
81
+ return os.path.expanduser(f"~/.claude/claudia_a11y_state_{session_id}.json")
82
+
83
+
84
+ def load_state(session_id):
85
+ state_file = get_state_file(session_id)
86
+ if os.path.exists(state_file):
87
+ try:
88
+ with open(state_file) as f:
89
+ return set(json.load(f))
90
+ except (json.JSONDecodeError, IOError):
91
+ return set()
92
+ return set()
93
+
94
+
95
+ def save_state(session_id, shown):
96
+ state_file = get_state_file(session_id)
97
+ try:
98
+ os.makedirs(os.path.dirname(state_file), exist_ok=True)
99
+ with open(state_file, "w") as f:
100
+ json.dump(list(shown), f)
101
+ except IOError:
102
+ pass
103
+
104
+
105
+ def extract_content(tool_name, tool_input):
106
+ if tool_name == "Write":
107
+ return tool_input.get("content", "")
108
+ elif tool_name == "Edit":
109
+ return tool_input.get("new_string", "")
110
+ elif tool_name == "MultiEdit":
111
+ edits = tool_input.get("edits", [])
112
+ return " ".join(e.get("new_string", "") for e in edits)
113
+ return ""
114
+
115
+
116
+ def main():
117
+ try:
118
+ input_data = json.loads(sys.stdin.read())
119
+ except json.JSONDecodeError:
120
+ sys.exit(0)
121
+
122
+ session_id = input_data.get("session_id", "default")
123
+ tool_name = input_data.get("tool_name", "")
124
+ tool_input = input_data.get("tool_input", {})
125
+ file_path = tool_input.get("file_path", "")
126
+
127
+ if tool_name not in ("Edit", "Write", "MultiEdit"):
128
+ sys.exit(0)
129
+
130
+ # Only check HTML/JSX/Vue/Svelte files
131
+ _, ext = os.path.splitext(file_path)
132
+ if ext.lower() not in A11Y_EXTENSIONS:
133
+ sys.exit(0)
134
+
135
+ content = extract_content(tool_name, tool_input)
136
+ if not content:
137
+ sys.exit(0)
138
+
139
+ # Skip test files
140
+ if any(x in file_path for x in ['.test.', '.spec.', '/test/', '/tests/', 'fixture', 'mock', '__test__']):
141
+ sys.exit(0)
142
+
143
+ shown = load_state(session_id)
144
+ warnings = []
145
+
146
+ for entry in A11Y_PATTERNS:
147
+ pattern, negative, description, advice, pattern_id = entry
148
+
149
+ if re.search(pattern, content, re.IGNORECASE):
150
+ # If there's a negative pattern and it matches, skip
151
+ if negative and re.search(negative, content, re.IGNORECASE):
152
+ continue
153
+
154
+ warning_key = f"{file_path}-{pattern_id}"
155
+ if warning_key not in shown:
156
+ shown.add(warning_key)
157
+ warnings.append(f"- {description}: {advice}")
158
+
159
+ if warnings:
160
+ save_state(session_id, shown)
161
+ message = "Claudia noticed some accessibility concerns:\n" + "\n".join(warnings)
162
+ output = json.dumps({"systemMessage": message})
163
+ print(output)
164
+
165
+ sys.exit(0)
166
+
167
+
168
+ if __name__ == "__main__":
169
+ main()