oh-my-customcode 0.36.2 → 0.37.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/cli/index.js +47 -2
  2. package/dist/index.js +44 -0
  3. package/package.json +1 -1
  4. package/templates/.claude/agents/arch-documenter.md +4 -1
  5. package/templates/.claude/agents/arch-speckit-agent.md +15 -0
  6. package/templates/.claude/agents/be-django-expert.md +1 -0
  7. package/templates/.claude/agents/be-express-expert.md +1 -0
  8. package/templates/.claude/agents/be-fastapi-expert.md +1 -0
  9. package/templates/.claude/agents/be-go-backend-expert.md +1 -0
  10. package/templates/.claude/agents/be-nestjs-expert.md +1 -0
  11. package/templates/.claude/agents/be-springboot-expert.md +1 -0
  12. package/templates/.claude/agents/db-postgres-expert.md +1 -0
  13. package/templates/.claude/agents/db-redis-expert.md +1 -0
  14. package/templates/.claude/agents/db-supabase-expert.md +1 -0
  15. package/templates/.claude/agents/de-airflow-expert.md +1 -0
  16. package/templates/.claude/agents/de-dbt-expert.md +1 -0
  17. package/templates/.claude/agents/de-kafka-expert.md +1 -0
  18. package/templates/.claude/agents/de-pipeline-expert.md +1 -0
  19. package/templates/.claude/agents/de-snowflake-expert.md +1 -0
  20. package/templates/.claude/agents/de-spark-expert.md +1 -0
  21. package/templates/.claude/agents/fe-flutter-agent.md +1 -0
  22. package/templates/.claude/agents/fe-svelte-agent.md +1 -0
  23. package/templates/.claude/agents/fe-vercel-agent.md +1 -0
  24. package/templates/.claude/agents/fe-vuejs-agent.md +1 -0
  25. package/templates/.claude/agents/infra-aws-expert.md +1 -0
  26. package/templates/.claude/agents/infra-docker-expert.md +1 -0
  27. package/templates/.claude/agents/lang-golang-expert.md +1 -0
  28. package/templates/.claude/agents/lang-java21-expert.md +3 -0
  29. package/templates/.claude/agents/lang-kotlin-expert.md +1 -0
  30. package/templates/.claude/agents/lang-python-expert.md +1 -0
  31. package/templates/.claude/agents/lang-rust-expert.md +1 -0
  32. package/templates/.claude/agents/lang-typescript-expert.md +1 -0
  33. package/templates/.claude/agents/mgr-claude-code-bible.md +1 -2
  34. package/templates/.claude/agents/mgr-creator.md +1 -0
  35. package/templates/.claude/agents/mgr-gitnerd.md +1 -0
  36. package/templates/.claude/agents/mgr-sauron.md +5 -2
  37. package/templates/.claude/agents/mgr-supplier.md +1 -3
  38. package/templates/.claude/agents/mgr-updater.md +1 -0
  39. package/templates/.claude/agents/qa-engineer.md +1 -0
  40. package/templates/.claude/agents/qa-planner.md +4 -1
  41. package/templates/.claude/agents/qa-writer.md +1 -1
  42. package/templates/.claude/agents/sec-codeql-expert.md +4 -2
  43. package/templates/.claude/agents/sys-memory-keeper.md +30 -0
  44. package/templates/.claude/agents/sys-naggy.md +36 -2
  45. package/templates/.claude/agents/tool-bun-expert.md +1 -1
  46. package/templates/.claude/agents/tool-npm-expert.md +1 -1
  47. package/templates/.claude/agents/tool-optimizer.md +1 -2
  48. package/templates/.claude/hooks/hooks.json +2 -2
  49. package/templates/.claude/hooks/scripts/agent-teams-advisor.sh +10 -0
  50. package/templates/.claude/hooks/scripts/content-hash-validator.sh +2 -3
  51. package/templates/.claude/hooks/scripts/schema-validator.sh +15 -0
  52. package/templates/.claude/hooks/scripts/secret-filter.sh +31 -1
  53. package/templates/.claude/rules/MUST-agent-teams.md +0 -23
  54. package/templates/.claude/rules/MUST-orchestrator-coordination.md +1 -13
  55. package/templates/.claude/skills/django-best-practices/SKILL.md +27 -134
  56. package/templates/.claude/skills/flutter-best-practices/SKILL.md +39 -146
  57. package/templates/.claude/skills/go-backend-best-practices/SKILL.md +29 -233
  58. package/templates/.claude/skills/java21-best-practices/SKILL.md +48 -163
  59. package/templates/CLAUDE.md.en +7 -65
  60. package/templates/CLAUDE.md.ko +7 -65
  61. package/templates/manifest.json +1 -1
@@ -2,6 +2,7 @@
2
2
  name: sys-naggy
3
3
  description: Use when you need TODO list management and task tracking with proactive reminders, helping maintain project momentum by monitoring stale tasks and deadlines
4
4
  model: sonnet
5
+ domain: universal
5
6
  memory: local
6
7
  effort: low
7
8
  tools:
@@ -9,8 +10,6 @@ tools:
9
10
  - Write
10
11
  - Edit
11
12
  - Grep
12
- - Glob
13
- - Bash
14
13
  ---
15
14
 
16
15
  You are a task management specialist that proactively manages TODO items and reminds users of pending tasks.
@@ -31,6 +30,41 @@ You are a task management specialist that proactively manages TODO items and rem
31
30
  | `sys-naggy:done <id>` | Mark complete |
32
31
  | `sys-naggy:remind` | Show overdue tasks |
33
32
 
33
+ ## Rule Pattern Detection
34
+
35
+ When sys-naggy detects recurring violations (3+ occurrences of the same rule ID across sessions), it proposes a rule patch:
36
+
37
+ ### Detection Flow
38
+
39
+ 1. Read violation history from native memory (`MEMORY.md` violations section)
40
+ 2. Cross-reference with session compliance data (PPID-scoped `/tmp/.claude-session-compliance-*`)
41
+ 3. Identify rules with 3+ violations across different sessions
42
+ 4. Generate rule patch proposal as GitHub issue
43
+
44
+ ### Proposal Format
45
+
46
+ ```
47
+ Title: [R016 Auto-Patch] R0XX: {weakness description}
48
+ Body:
49
+ ## Violation Pattern
50
+ - Rule: R0XX ({rule name})
51
+ - Occurrences: {count} across {session_count} sessions
52
+ - Common trigger: {pattern description}
53
+
54
+ ## Proposed Fix
55
+ {specific change to the rule file}
56
+
57
+ ## Rationale
58
+ {why the current rule is insufficient}
59
+ ```
60
+
61
+ ### Constraints
62
+
63
+ - sys-naggy proposes patches as GitHub issues — never auto-applies
64
+ - Minimum 3 occurrences before proposing (avoids noise)
65
+ - Maximum 1 proposal per rule per week (debounce)
66
+ - Proposals require human approval before implementation
67
+
34
68
  ## Behavior
35
69
 
36
70
  Proactive but not annoying. Adapt reminder frequency to user response.
@@ -2,6 +2,7 @@
2
2
  name: tool-bun-expert
3
3
  description: Use for Bun runtime development, bunfig.toml configuration, Bun test runner, fast bundling, and Node.js to Bun migrations
4
4
  model: sonnet
5
+ domain: universal
5
6
  memory: project
6
7
  effort: medium
7
8
  tools:
@@ -9,7 +10,6 @@ tools:
9
10
  - Write
10
11
  - Edit
11
12
  - Grep
12
- - Glob
13
13
  - Bash
14
14
  ---
15
15
 
@@ -2,6 +2,7 @@
2
2
  name: tool-npm-expert
3
3
  description: Use for npm package publishing workflows, semantic versioning (major/minor/patch), package.json optimization, and dependency audits
4
4
  model: sonnet
5
+ domain: universal
5
6
  memory: project
6
7
  effort: medium
7
8
  skills:
@@ -13,7 +14,6 @@ tools:
13
14
  - Write
14
15
  - Edit
15
16
  - Grep
16
- - Glob
17
17
  - Bash
18
18
  ---
19
19
 
@@ -2,6 +2,7 @@
2
2
  name: tool-optimizer
3
3
  description: Use for bundle size analysis, tree-shaking verification, performance profiling, dead code detection, and build optimization recommendations
4
4
  model: sonnet
5
+ domain: universal
5
6
  memory: project
6
7
  effort: medium
7
8
  skills:
@@ -10,8 +11,6 @@ skills:
10
11
  - optimize-report
11
12
  tools:
12
13
  - Read
13
- - Write
14
- - Edit
15
14
  - Grep
16
15
  - Glob
17
16
  - Bash
@@ -263,14 +263,14 @@
263
263
  "description": "Store content hashes for Read operations — enables Edit staleness detection"
264
264
  },
265
265
  {
266
- "matcher": "tool == \"Bash\" || tool == \"Read\"",
266
+ "matcher": "tool == \"Bash\" || tool == \"Read\" || tool == \"Grep\"",
267
267
  "hooks": [
268
268
  {
269
269
  "type": "command",
270
270
  "command": "bash .claude/hooks/scripts/secret-filter.sh"
271
271
  }
272
272
  ],
273
- "description": "Detect potential secrets in Bash/Read output — advisory warning only"
273
+ "description": "Detect potential secrets in Bash/Read/Grep output — advisory warning only"
274
274
  },
275
275
  {
276
276
  "matcher": "tool == \"Edit\" || tool == \"Write\" || tool == \"Bash\" || tool == \"Agent\"",
@@ -8,6 +8,16 @@ set -euo pipefail
8
8
 
9
9
  input=$(cat)
10
10
 
11
+ # Skip if Agent Teams is not available
12
+ ENV_STATUS="/tmp/.claude-env-status-${PPID}"
13
+ if [ -f "$ENV_STATUS" ]; then
14
+ teams_status=$(grep "agent_teams=" "$ENV_STATUS" 2>/dev/null | cut -d= -f2 || echo "unknown")
15
+ if [ "$teams_status" != "enabled" ]; then
16
+ echo "$input"
17
+ exit 0
18
+ fi
19
+ fi
20
+
11
21
  # Extract task info from input
12
22
  agent_type=$(echo "$input" | jq -r '.tool_input.subagent_type // "unknown"')
13
23
  prompt_preview=$(echo "$input" | jq -r '.tool_input.description // ""' | head -c 60)
@@ -18,10 +18,9 @@ case "$tool_name" in
18
18
  "Read")
19
19
  # Store content hash for the file that was just read
20
20
  file_path=$(echo "$input" | jq -r '.tool_input.file_path // ""')
21
- output=$(echo "$input" | jq -r '.tool_output.output // ""')
22
21
 
23
- if [ -n "$file_path" ] && [ -n "$output" ] && [ "$output" != "null" ]; then
24
- content_hash=$(echo "$output" | md5 2>/dev/null || echo "$output" | md5sum 2>/dev/null | cut -d' ' -f1 || echo "unknown")
22
+ if [ -n "$file_path" ] && [ -f "$file_path" ]; then
23
+ content_hash=$(md5 -q "$file_path" 2>/dev/null || md5sum "$file_path" 2>/dev/null | cut -d' ' -f1 || echo "unknown")
25
24
  timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)
26
25
 
27
26
  # Store hash entry (overwrite previous for same file)
@@ -72,6 +72,21 @@ case "$tool_name" in
72
72
  if echo "$command" | grep -qE 'mkfs\.'; then
73
73
  warnings+=("[Schema] Bash: filesystem format command detected")
74
74
  fi
75
+ # Remote code execution via pipe
76
+ if echo "$command" | grep -qE 'curl\s+.*\|\s*(ba)?sh'; then
77
+ warnings+=("[Schema] Bash: remote code execution pattern (curl | bash) detected")
78
+ fi
79
+ if echo "$command" | grep -qE 'wget\s+.*\|\s*(ba)?sh'; then
80
+ warnings+=("[Schema] Bash: remote code execution pattern (wget | sh) detected")
81
+ fi
82
+ # Dynamic code execution
83
+ if echo "$command" | grep -qE 'eval\s+\$\('; then
84
+ warnings+=("[Schema] Bash: dynamic code execution (eval) detected")
85
+ fi
86
+ # Broad permission grant
87
+ if echo "$command" | grep -qE 'chmod\s+777'; then
88
+ warnings+=("[Schema] Bash: broad permission grant (chmod 777) detected")
89
+ fi
75
90
  ;;
76
91
  esac
77
92
 
@@ -1,6 +1,6 @@
1
1
  #!/bin/bash
2
2
  # Secret Output Filter Hook — Detect potential secrets in tool output
3
- # Trigger: PostToolUse on Bash, Read
3
+ # Trigger: PostToolUse on Bash, Read, Grep
4
4
  # Purpose: Advisory warning when potential secrets detected in output
5
5
  # Protocol: stdin JSON -> scan -> stdout pass-through
6
6
  # Always exits 0 (advisory only, never blocks)
@@ -58,6 +58,36 @@ if echo "$output" | grep -qE 'gho_[a-zA-Z0-9]{36}'; then
58
58
  detected=true
59
59
  fi
60
60
 
61
+ # GitHub Fine-Grained PAT
62
+ if echo "$output" | grep -qE 'github_pat_[a-zA-Z0-9]{22}_[a-zA-Z0-9]{59}'; then
63
+ echo "[Security] Potential GitHub Fine-Grained PAT detected in ${tool_name} output" >&2
64
+ detected=true
65
+ fi
66
+
67
+ # GitHub Actions Token
68
+ if echo "$output" | grep -qE 'ghs_[a-zA-Z0-9]{36}'; then
69
+ echo "[Security] Potential GitHub Actions token detected in ${tool_name} output" >&2
70
+ detected=true
71
+ fi
72
+
73
+ # npm Token
74
+ if echo "$output" | grep -qE 'npm_[a-zA-Z0-9]{36}'; then
75
+ echo "[Security] Potential npm token detected in ${tool_name} output" >&2
76
+ detected=true
77
+ fi
78
+
79
+ # Slack Token
80
+ if echo "$output" | grep -qE 'xox[bsarp]-[a-zA-Z0-9-]{10,}'; then
81
+ echo "[Security] Potential Slack token detected in ${tool_name} output" >&2
82
+ detected=true
83
+ fi
84
+
85
+ # Docker Hub PAT
86
+ if echo "$output" | grep -qE 'dckr_pat_[a-zA-Z0-9_-]{20,}'; then
87
+ echo "[Security] Potential Docker Hub PAT detected in ${tool_name} output" >&2
88
+ detected=true
89
+ fi
90
+
61
91
  if [ "$detected" = true ]; then
62
92
  echo "[Security] Review output carefully — do NOT commit or expose secrets" >&2
63
93
  fi
@@ -104,17 +104,6 @@ All members must be spawned in a single message. Partial spawning needs correcti
104
104
  implementer → fixes → SendMessage(reviewer, "fixed")
105
105
  reviewer → re-reviews → done
106
106
 
107
- ❌ WRONG: Multi-expert task without coordination
108
- Agent(lang-typescript-expert) → "Implement frontend"
109
- Agent(be-express-expert) → "Implement API"
110
- (no shared state, results manually combined)
111
-
112
- ✓ CORRECT: Agent Teams for cross-domain work
113
- TeamCreate("fullstack")
114
- Agent(frontend-dev) + Agent(backend-dev) → team members
115
- Shared TaskList for interface contracts
116
- SendMessage for API schema coordination
117
-
118
107
  ❌ WRONG: Spawning team members one at a time
119
108
  TeamCreate("research-team")
120
109
  Message 1: Agent(researcher-1) → Analysis 1 (only 1/3 spawned)
@@ -127,18 +116,6 @@ All members must be spawned in a single message. Partial spawning needs correcti
127
116
  Agent(researcher-1) → Analysis 1 ┐
128
117
  Agent(researcher-2) → Analysis 2 ├─ ALL spawned together
129
118
  Agent(researcher-3) → Analysis 3 ┘
130
-
131
- ❌ WRONG: Multi-issue batch as independent agents
132
- Agent(general-purpose) → "Fix issue #1"
133
- Agent(general-purpose) → "Fix issue #2"
134
- Agent(general-purpose) → "Fix issue #3"
135
- (no coordination, no shared task tracking)
136
-
137
- ✓ CORRECT: Agent Teams for multi-issue batches
138
- TeamCreate("release-fixes")
139
- TaskCreate for each issue
140
- Agent(fixer-1) + Agent(fixer-2) + Agent(fixer-3) → team members
141
- Shared task list tracks progress across all issues
142
119
  ```
143
120
 
144
121
  ## Cost Guidelines
@@ -95,12 +95,6 @@ Main Conversation (orchestrator)
95
95
  Main conversation → Agent(mgr-gitnerd) → git commit
96
96
  Main conversation → Agent(mgr-gitnerd) → git push
97
97
 
98
- ❌ WRONG: Using general-purpose when specialist exists
99
- Main conversation → Agent(general-purpose) → "Write Go code"
100
-
101
- ✓ CORRECT: Using the right specialist
102
- Main conversation → Agent(lang-golang-expert) → "Write Go code"
103
-
104
98
  ❌ WRONG: Orchestrator creates files "just this once"
105
99
  "It's just a small config file, I'll write it directly..."
106
100
 
@@ -110,15 +104,9 @@ Main Conversation (orchestrator)
110
104
  ❌ WRONG: Bundling git operations with file editing in non-gitnerd agent
111
105
  Main conversation → Agent(general-purpose) → "git revert + edit file + git commit"
112
106
  Main conversation → Agent(lang-typescript-expert) → "fix bug and commit"
113
-
114
- ✓ CORRECT: Separate file editing from git operations
115
- Main conversation → Agent(lang-typescript-expert) → "fix bug" (file edit only)
116
- Main conversation → Agent(mgr-gitnerd) → "git commit" (git operation only)
117
-
118
- ❌ WRONG: Including git commands in non-gitnerd agent prompt for "convenience"
119
107
  Agent(general-purpose, prompt="revert the last commit, edit the file, then commit the fix")
120
108
 
121
- ✓ CORRECT: Split into separate delegations
109
+ ✓ CORRECT: Separate file editing from git operations, split delegations
122
110
  Agent(mgr-gitnerd, prompt="revert the last commit")
123
111
  Agent(appropriate-expert, prompt="edit the file to fix the issue")
124
112
  Agent(mgr-gitnerd, prompt="commit the fix")
@@ -16,26 +16,7 @@ Apply Django patterns for building production-ready, secure, and maintainable Py
16
16
  ```yaml
17
17
  structure:
18
18
  settings_split: true
19
- layout: |
20
- project/
21
- ├── config/
22
- │ ├── settings/
23
- │ │ ├── base.py
24
- │ │ ├── development.py
25
- │ │ └── production.py
26
- │ ├── urls.py
27
- │ └── wsgi.py
28
- ├── apps/
29
- │ ├── core/ # Shared utilities, base models
30
- │ ├── users/ # Custom User model (ALWAYS create)
31
- │ └── {feature}/ # Feature-specific apps
32
- ├── templates/
33
- ├── static/
34
- ├── requirements/
35
- │ ├── base.txt
36
- │ ├── development.txt
37
- │ └── production.txt
38
- └── manage.py
19
+ layout: "config/{settings/{base,development,production}.py,urls.py,wsgi.py} + apps/{core/,users/,<feature>/} + templates/ + static/ + requirements/{base,development,production}.txt"
39
20
 
40
21
  app_module_contents:
41
22
  models.py: Database models
@@ -50,6 +31,8 @@ app_module_contents:
50
31
  tests/: Test suite (mirror app structure)
51
32
  ```
52
33
 
34
+ Reference: guides/django-best-practices/README.md
35
+
53
36
  ### 2. Models Best Practices
54
37
 
55
38
  ```yaml
@@ -57,15 +40,7 @@ custom_user_model:
57
40
  rule: ALWAYS create a custom User model, even if identical to default
58
41
  location: apps/users/models.py
59
42
  reason: Impossible to swap default User model mid-project
60
- example: |
61
- # apps/users/models.py
62
- from django.contrib.auth.models import AbstractUser
63
-
64
- class User(AbstractUser):
65
- pass # Can extend later without migrations
66
-
67
- # config/settings/base.py
68
- AUTH_USER_MODEL = 'users.User'
43
+ pattern: "Extend AbstractUser, set AUTH_USER_MODEL in settings"
69
44
 
70
45
  primary_key:
71
46
  default: BigAutoField
@@ -77,18 +52,6 @@ model_meta:
77
52
  - Meta.ordering: consistent default ordering
78
53
  - Meta.verbose_name: singular display name
79
54
  - Meta.verbose_name_plural: plural display name
80
- example: |
81
- class Article(models.Model):
82
- title = models.CharField(max_length=200)
83
- created_at = models.DateTimeField(auto_now_add=True)
84
-
85
- class Meta:
86
- ordering = ['-created_at']
87
- verbose_name = 'article'
88
- verbose_name_plural = 'articles'
89
-
90
- def __str__(self):
91
- return self.title
92
55
 
93
56
  query_optimization:
94
57
  foreign_key: select_related() # Single SQL JOIN
@@ -107,18 +70,7 @@ indexing:
107
70
 
108
71
  constraints:
109
72
  use: Meta.constraints for database-level enforcement
110
- example: |
111
- class Meta:
112
- constraints = [
113
- models.UniqueConstraint(
114
- fields=['user', 'article'],
115
- name='unique_user_article'
116
- ),
117
- models.CheckConstraint(
118
- check=models.Q(price__gte=0),
119
- name='price_non_negative'
120
- )
121
- ]
73
+ types: "UniqueConstraint, CheckConstraint"
122
74
 
123
75
  soft_delete:
124
76
  pattern: is_active = models.BooleanField(default=True)
@@ -126,16 +78,10 @@ soft_delete:
126
78
 
127
79
  custom_managers:
128
80
  rule: Use managers for reusable querysets
129
- example: |
130
- class PublishedManager(models.Manager):
131
- def get_queryset(self):
132
- return super().get_queryset().filter(status='published')
133
-
134
- class Article(models.Model):
135
- objects = models.Manager() # Keep default
136
- published = PublishedManager() # Add custom
137
81
  ```
138
82
 
83
+ Reference: guides/django-best-practices/README.md
84
+
139
85
  ### 3. Views Best Practices
140
86
 
141
87
  ```yaml
@@ -145,15 +91,6 @@ cbv_vs_fbv:
145
91
 
146
92
  thin_views:
147
93
  rule: Keep views thin — delegate business logic to services/models
148
- wrong: |
149
- def create_order(request):
150
- # 50 lines of business logic in view
151
- correct: |
152
- def create_order(request):
153
- form = OrderForm(request.POST)
154
- if form.is_valid():
155
- order = order_service.create(request.user, form.cleaned_data)
156
- return redirect('order-detail', pk=order.pk)
157
94
 
158
95
  shortcuts:
159
96
  - get_object_or_404(Model, pk=pk): Returns 404 instead of 500
@@ -179,7 +116,7 @@ status_codes:
179
116
  ```yaml
180
117
  namespacing:
181
118
  app_name: Required in every app's urls.py
182
- usage: reverse('app_name:url_name') or {% url 'app_name:url_name' %}
119
+ usage: "reverse('app_name:url_name') or {% url 'app_name:url_name' %}"
183
120
 
184
121
  syntax:
185
122
  prefer: path() over re_path() for clarity
@@ -187,56 +124,29 @@ syntax:
187
124
 
188
125
  naming:
189
126
  rule: Name ALL URL patterns
190
- convention: "{resource}-{action}" (e.g., article-list, article-detail)
127
+ convention: "{resource}-{action} (e.g., article-list, article-detail)"
191
128
 
192
129
  inclusion:
193
130
  root_urls: Use include() for app-level URLs
194
- example: |
195
- # config/urls.py
196
- urlpatterns = [
197
- path('admin/', admin.site.urls),
198
- path('api/', include('apps.api.urls', namespace='api')),
199
- path('articles/', include('apps.articles.urls', namespace='articles')),
200
- ]
201
-
202
- # apps/articles/urls.py
203
- app_name = 'articles'
204
- urlpatterns = [
205
- path('', ArticleListView.as_view(), name='list'),
206
- path('<int:pk>/', ArticleDetailView.as_view(), name='detail'),
207
- ]
208
131
  ```
209
132
 
133
+ Reference: guides/django-best-practices/README.md
134
+
210
135
  ### 5. Forms & Validation
211
136
 
212
137
  ```yaml
213
138
  model_forms:
214
139
  rule: Use ModelForm when form maps to a model
215
- fields: Explicitly list fields (never use fields = '__all__')
140
+ fields: "Explicitly list fields (never use fields = '__all__')"
216
141
 
217
142
  validation:
218
143
  field_level: clean_<field>() method
219
144
  cross_field: clean() method
220
145
  built_in: Use Django validators (MaxValueValidator, RegexValidator, etc.)
221
-
222
- example: |
223
- class ArticleForm(forms.ModelForm):
224
- class Meta:
225
- model = Article
226
- fields = ['title', 'body', 'status']
227
-
228
- def clean_title(self):
229
- title = self.cleaned_data['title']
230
- if len(title) < 5:
231
- raise forms.ValidationError('Title too short.')
232
- return title
233
-
234
- def clean(self):
235
- cleaned = super().clean()
236
- # Cross-field validation here
237
- return cleaned
238
146
  ```
239
147
 
148
+ Reference: guides/django-best-practices/README.md
149
+
240
150
  ### 6. Security
241
151
 
242
152
  ```yaml
@@ -287,22 +197,13 @@ test_classes:
287
197
  test_data:
288
198
  preferred: factory_boy or model_bakery
289
199
  avoid: fixtures (hard to maintain, slow)
290
- example: |
291
- import factory
292
- from apps.users.models import User
293
-
294
- class UserFactory(factory.django.DjangoModelFactory):
295
- class Meta:
296
- model = User
297
- username = factory.Sequence(lambda n: f'user{n}')
298
- email = factory.LazyAttribute(lambda o: f'{o.username}@example.com')
299
200
 
300
201
  request_testing:
301
202
  Client: Full request/response cycle (preferred for views)
302
203
  RequestFactory: Faster, no middleware (for unit testing views)
303
204
 
304
205
  settings_override:
305
- decorator: '@override_settings(EMAIL_BACKEND="django.core.mail.backends.locmem.EmailBackend")'
206
+ decorator: '@override_settings(...)'
306
207
 
307
208
  coverage:
308
209
  target: 80%+
@@ -312,6 +213,8 @@ structure:
312
213
  mirror_app: tests/test_models.py, tests/test_views.py, tests/test_forms.py
313
214
  ```
314
215
 
216
+ Reference: guides/django-best-practices/README.md
217
+
315
218
  ### 8. Performance
316
219
 
317
220
  ```yaml
@@ -322,15 +225,15 @@ n_plus_1_prevention:
322
225
  complex: Prefetch object with custom queryset
323
226
 
324
227
  partial_loading:
325
- only: only('id', 'title', 'created_at') # Load only these fields
326
- defer: defer('body', 'metadata') # Load all except these
327
- values: values('id', 'title') # Returns dicts (no ORM overhead)
328
- values_list: values_list('id', flat=True) # Returns flat list
228
+ only: "only('id', 'title', 'created_at') Load only these fields"
229
+ defer: "defer('body', 'metadata') Load all except these"
230
+ values: "values('id', 'title') Returns dicts (no ORM overhead)"
231
+ values_list: "values_list('id', flat=True) Returns flat list"
329
232
 
330
233
  caching:
331
234
  backend: Redis (preferred), Memcached
332
- view_cache: '@cache_page(60 * 15)' decorator
333
- template_cache: '{% cache 500 sidebar %}' template tag
235
+ view_cache: "'@cache_page(60 * 15)' decorator"
236
+ template_cache: "'{% cache 500 sidebar %}' template tag"
334
237
  low_level: cache.get/set/delete for fine-grained control
335
238
 
336
239
  pagination:
@@ -339,8 +242,8 @@ pagination:
339
242
  drf: PageNumberPagination or CursorPagination
340
243
 
341
244
  bulk_operations:
342
- create: Article.objects.bulk_create(articles, batch_size=1000)
343
- update: Article.objects.bulk_update(articles, ['status'], batch_size=1000)
245
+ create: "bulk_create(articles, batch_size=1000)"
246
+ update: "bulk_update(articles, ['status'], batch_size=1000)"
344
247
  avoid: Loops calling .save() on many objects
345
248
  ```
346
249
 
@@ -351,17 +254,6 @@ serializers:
351
254
  standard_crud: ModelSerializer
352
255
  read_only: Use SerializerMethodField for computed values
353
256
  write_validation: validate_<field>() and validate() methods
354
- example: |
355
- class ArticleSerializer(serializers.ModelSerializer):
356
- author_name = serializers.SerializerMethodField()
357
-
358
- class Meta:
359
- model = Article
360
- fields = ['id', 'title', 'body', 'author_name', 'created_at']
361
- read_only_fields = ['id', 'created_at']
362
-
363
- def get_author_name(self, obj):
364
- return obj.author.get_full_name()
365
257
 
366
258
  viewsets:
367
259
  standard: ModelViewSet for full CRUD
@@ -380,7 +272,6 @@ permissions:
380
272
 
381
273
  versioning:
382
274
  method: NamespaceVersioning or URLPathVersioning
383
- example: "/api/v1/articles/" vs "/api/v2/articles/"
384
275
 
385
276
  throttling:
386
277
  anonymous: AnonRateThrottle
@@ -392,6 +283,8 @@ pagination:
392
283
  types: PageNumberPagination (simple), CursorPagination (large datasets)
393
284
  ```
394
285
 
286
+ Reference: guides/django-best-practices/README.md
287
+
395
288
  ### 10. Deployment
396
289
 
397
290
  ```yaml