oh-my-customcode 0.30.9 → 0.31.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.
package/README.md CHANGED
@@ -21,7 +21,7 @@ Like oh-my-zsh transformed shell customization, oh-my-customcode makes personali
21
21
 
22
22
  | Feature | Description |
23
23
  |---------|-------------|
24
- | **Batteries Included** | 44 agents, 68 skills, 24 guides, 18 rules, 2 hooks, 4 contexts, ontology graph - ready to use out of the box |
24
+ | **Batteries Included** | 44 agents, 68 skills, 25 guides, 18 rules, 2 hooks, 4 contexts, ontology graph - ready to use out of the box |
25
25
  | **Sub-Agent Model** | Supports hierarchical agent orchestration with specialized roles |
26
26
  | **Dead Simple Customization** | Create a folder + markdown file = new agent or skill |
27
27
  | **Mix and Match** | Use built-in components, create your own, or combine both |
@@ -197,7 +197,7 @@ All commands are invoked inside the Claude Code conversation.
197
197
  | **Deploy** | 2 | vercel-deploy, codex-exec |
198
198
  | **External** | 1 | skills-sh-search |
199
199
 
200
- ### Guides (24)
200
+ ### Guides (25)
201
201
 
202
202
  Comprehensive reference documentation covering:
203
203
  - Agent creation and management
@@ -292,7 +292,8 @@ your-project/
292
292
  │ ├── rules/ # Behavior rules (18 total)
293
293
  │ ├── hooks/ # Event hooks (2 total)
294
294
  │ └── contexts/ # Context files (4 total)
295
- └── guides/ # Reference docs (24 total)
295
+ └── templates/
296
+ └── guides/ # Reference docs (25 total)
296
297
  ```
297
298
 
298
299
  **Note**: In the official Claude Code format, there is no command registry — slash commands and natural language agent references are used.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-customcode",
3
- "version": "0.30.9",
3
+ "version": "0.31.1",
4
4
  "description": "Batteries-included agent harness for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {
@@ -4,6 +4,7 @@ description: Expert Go developer for writing idiomatic, performant Go code. Use
4
4
  model: sonnet
5
5
  memory: project
6
6
  effort: high
7
+ soul: true
7
8
  skills:
8
9
  - go-best-practices
9
10
  tools:
@@ -0,0 +1,21 @@
1
+ ---
2
+ agent: lang-golang-expert
3
+ version: 1.0.0
4
+ ---
5
+
6
+ ## Personality
7
+ - Direct and concise — lead with the answer, explain after
8
+ - Always provide runnable code examples, never pseudo-code
9
+ - Treat Go idioms as non-negotiable (Effective Go is gospel)
10
+
11
+ ## Style
12
+ - Error handling first — check errors before happy path
13
+ - Prefer stdlib over third-party when possible
14
+ - Name variables for clarity, not brevity (userCount > uc)
15
+ - Use table-driven tests as default test pattern
16
+
17
+ ## Anti-patterns
18
+ - Never use interface{}/any without a compelling reason
19
+ - Avoid init() functions — explicit initialization preferred
20
+ - No global mutable state
21
+ - Avoid premature abstraction — 3 concrete cases before extracting
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: sys-memory-keeper
3
- description: Use when you need to manage session memory persistence using claude-mem, save context before compaction, restore context on session start, query past memories, or perform session-end dual-system auto-save
3
+ description: Use when you need to manage session memory persistence via native auto-memory, save context before compaction, restore context on session start, collect session summaries, or perform session-end memory operations
4
4
  model: sonnet
5
5
  memory: project
6
6
  effort: medium
@@ -47,12 +47,19 @@ Provider: claude-mem | Collection: claude_memories | Archive: ~/.claude-mem/arch
47
47
  When triggered by session-end signal from orchestrator:
48
48
 
49
49
  1. **Collect** session summary: completed tasks, key decisions, open items
50
- 2. **Save to claude-mem** (if available): `mcp__plugin_claude-mem_mcp-search__save_memory` with project name, session date, and summary
51
- 3. **Verify episodic-memory** (if available): `mcp__plugin_episodic-memory_episodic-memory__search` to confirm session is indexed
52
- 4. **Report** results to orchestrator: saved/skipped/failed per system
50
+ 2. **Extract behaviors**: analyze conversation for repeated user preferences
51
+ - Communication patterns (verbosity, format, language preferences)
52
+ - Workflow patterns (tool usage, review habits, branching conventions)
53
+ - Domain priorities (security-first, performance-first, etc.)
54
+ - New behaviors → `[confidence: low]` in `## Behaviors` section
55
+ - Existing behaviors observed again → promote confidence level
56
+ - Contradicted behaviors → flag for review or demote
57
+ 3. **Update native auto-memory** (MEMORY.md) with session learnings + behaviors
58
+ 4. **Return formatted summary** to orchestrator for MCP persistence (claude-mem, episodic-memory)
59
+
60
+ > **Note**: MCP tools (claude-mem, episodic-memory) are orchestrator-scoped and cannot be called from subagents. The orchestrator handles MCP saves directly after receiving the formatted summary.
53
61
 
54
62
  ### Failure Handling
55
63
 
56
- - claude-mem unavailableskip, report warning
57
- - episodic-memory unavailable skip, report warning
58
- - Both unavailable → warn orchestrator, do not block session end
64
+ - MEMORY.md update failure → report error to orchestrator
65
+ - MCP persistence is orchestrator's responsibility — not handled here
@@ -30,6 +30,7 @@ escalation: # Model escalation policy (optional)
30
30
  enabled: true # Enable auto-escalation advisory
31
31
  path: haiku → sonnet → opus # Escalation sequence
32
32
  threshold: 2 # Failures before advisory
33
+ soul: true # Enable SOUL.md identity injection
33
34
  isolation: worktree # Run in isolated git worktree
34
35
  background: true # Run in background
35
36
  maxTurns: 10 # Max conversation turns
@@ -64,6 +65,54 @@ When `escalation.enabled: true`, the model-escalation hooks will track outcomes
64
65
 
65
66
  When enabled: first 200 lines of MEMORY.md loaded into system prompt.
66
67
 
68
+ ## Soul Identity
69
+
70
+ Optional per-agent identity layer that separates personality/style from capabilities.
71
+
72
+ | Aspect | Location | Purpose |
73
+ |--------|----------|---------|
74
+ | Capabilities | `.claude/agents/{name}.md` | WHAT the agent does |
75
+ | Identity | `.claude/agents/souls/{name}.soul.md` | HOW the agent communicates |
76
+
77
+ ### Soul File Format
78
+
79
+ Location: `.claude/agents/souls/{name}.soul.md`
80
+
81
+ ```yaml
82
+ ---
83
+ agent: {agent-name} # Must match agent filename
84
+ version: 1.0.0
85
+ ---
86
+ ```
87
+
88
+ Sections: `## Personality`, `## Style`, `## Anti-patterns`
89
+
90
+ ### Activation
91
+
92
+ 1. Agent frontmatter includes `soul: true`
93
+ 2. Routing skill reads `souls/{name}.soul.md` at spawn time (Step 5)
94
+ 3. Soul content prepended to agent prompt as identity context
95
+ 4. Missing soul file → graceful fallback (no error)
96
+
97
+ ### Precedence
98
+
99
+ Behavioral memory observations (R011) override soul defaults when they conflict. Behaviors are user-specific; souls are template defaults.
100
+
101
+ ## Artifact Output Convention
102
+
103
+ Skills that produce significant output can persist results to local storage.
104
+
105
+ **Location**: `.claude/outputs/sessions/{YYYY-MM-DD}/{skill-name}-{HHmmss}.md`
106
+
107
+ **Format**: Metadata header with `skill`, `date`, `query` fields, followed by skill output content.
108
+
109
+ **Rules**:
110
+ - Opt-in per skill — not mandatory
111
+ - The final subagent in the skill's pipeline writes the artifact (R010 compliance)
112
+ - Skills create the directory (`mkdir -p`) before writing
113
+ - `.claude/outputs/` is git-untracked (under `.claude/` gitignore)
114
+ - No indexing required — date-based directory browsing is sufficient
115
+
67
116
  ## Separation of Concerns
68
117
 
69
118
  | Location | Purpose | Contains |
@@ -74,6 +123,42 @@ When enabled: first 200 lines of MEMORY.md loaded into system prompt.
74
123
 
75
124
  Agent body: purpose, capabilities overview, workflow. NOT detailed instructions or reference docs.
76
125
 
126
+ ## Skill Frontmatter
127
+
128
+ Location: `.claude/skills/{name}/SKILL.md`
129
+
130
+ ### Required Fields
131
+
132
+ ```yaml
133
+ name: skill-name # Unique identifier (kebab-case)
134
+ description: Brief desc # One-line summary
135
+ ```
136
+
137
+ ### Optional Fields
138
+
139
+ ```yaml
140
+ context: fork # Forked context for isolated execution
141
+ version: 1.0.0 # Semantic version
142
+ user-invocable: false # Whether user can invoke directly
143
+ disable-model-invocation: true # Prevent model from auto-invoking
144
+ ```
145
+
146
+ ### Context Fork Criteria
147
+
148
+ Use `context: fork` for skills that orchestrate multi-agent workflows. Cap at **10 total** across the project.
149
+
150
+ | Use `context: fork` | Do NOT use `context: fork` |
151
+ |---------------------|---------------------------|
152
+ | Routing skills (secretary, dev-lead, etc.) | Best-practices skills |
153
+ | Workflow orchestration (DAG, pipelines) | Hook/command skills |
154
+ | Multi-agent coordination patterns | Single-agent reference skills |
155
+ | Task decomposition/planning | External tool integrations |
156
+
157
+ Current skills with `context: fork` (8/10 cap):
158
+ - secretary-routing, dev-lead-routing, de-lead-routing, qa-lead-routing
159
+ - dag-orchestration, task-decomposition, worker-reviewer-pipeline
160
+ - pipeline-guards
161
+
77
162
  ## Naming
78
163
 
79
164
  | Type | Pattern | Example |
@@ -71,6 +71,58 @@ Memory entries in MEMORY.md should include confidence annotations to distinguish
71
71
  [any] → contradicted by evidence → demoted or removed
72
72
  ```
73
73
 
74
+ ## Behavioral Memory
75
+
76
+ MEMORY.md supports an optional `## Behaviors` section for tracking user interaction preferences and workflow patterns.
77
+
78
+ ### Behaviors Section Format
79
+
80
+ ```markdown
81
+ ## Behaviors [confidence: medium]
82
+ - User prefers concise responses — 3 sentences max
83
+ - Commit messages always include issue number
84
+ - Security-first review perspective
85
+
86
+ ## Behavior Lifecycle
87
+ - New observation → [confidence: low]
88
+ - Seen in 2+ sessions → [confidence: medium]
89
+ - User-confirmed → [confidence: high]
90
+ - Contradicted → demote or remove
91
+ ```
92
+
93
+ ### What Counts as a Behavior
94
+
95
+ | Category | Examples |
96
+ |----------|---------|
97
+ | Communication | Verbosity preference, language, format |
98
+ | Workflow | Tool preferences, review habits, branching patterns |
99
+ | Domain priority | Security-first, performance-first, simplicity-first |
100
+
101
+ ### What Does NOT Count as a Behavior
102
+
103
+ - Facts about the codebase (use existing sections)
104
+ - One-time instructions (ephemeral, not persistent)
105
+ - Tool configuration (belongs in CLAUDE.md or settings)
106
+
107
+ ### Extraction Guidelines
108
+
109
+ sys-memory-keeper extracts behavioral patterns at session end:
110
+ 1. Analyze conversation for repeated user preferences
111
+ 2. New behaviors start at `[confidence: low]`
112
+ 3. Promote on repeated observation across sessions
113
+ 4. Demote or remove when contradicted
114
+
115
+ ### Budget Management
116
+
117
+ Behaviors share the 200-line MEMORY.md budget with facts. When approaching the limit:
118
+ 1. Prune `[confidence: low]` behaviors first
119
+ 2. Then prune `[confidence: medium]` behaviors
120
+ 3. `[confidence: high]` behaviors are never auto-pruned
121
+
122
+ ### Precedence
123
+
124
+ Behavioral memory observations override soul defaults (R006 Soul Identity) when they conflict. Behaviors are user-specific and session-derived; souls are template defaults.
125
+
74
126
  ### Rules
75
127
 
76
128
  | Rule | Detail |
@@ -73,6 +73,29 @@ For **new pipeline code**, **DAG scaffolding**, or **SQL model generation**:
73
73
  ### Step 3: Expert Selection
74
74
  Route to appropriate DE expert based on tool/framework detection.
75
75
 
76
+ ### Step 4: Ontology-RAG Enrichment (R019)
77
+
78
+ After agent selection, enrich the spawned agent's prompt with ontology context:
79
+
80
+ 1. Call `get_agent_for_task(original_query)` via MCP
81
+ 2. Extract `suggested_skills` from response
82
+ 3. If `suggested_skills` non-empty, prepend to spawned agent prompt:
83
+ `"Ontology context suggests these skills may be relevant: {suggested_skills}"`
84
+ 4. On MCP failure: skip silently, proceed with unmodified prompt
85
+
86
+ **This step is advisory only — it never changes which agent is selected.**
87
+
88
+ ### Step 5: Soul Injection
89
+
90
+ If the selected agent has `soul: true` in its frontmatter:
91
+
92
+ 1. Read `.claude/agents/souls/{agent-name}.soul.md`
93
+ 2. If file exists, prepend soul content to the agent's prompt:
94
+ `"Identity context:\n{soul content}\n\n---\n\n"`
95
+ 3. If file doesn't exist → skip silently (no error, no injection)
96
+
97
+ **This step runs after ontology-RAG enrichment. Soul content is identity context, not capability instructions.**
98
+
76
99
  ## Command Routing
77
100
 
78
101
  ```
@@ -262,7 +285,7 @@ Delegate to mgr-creator with context:
262
285
  keywords: extracted tool names
263
286
  file_patterns: detected config patterns
264
287
  skills: auto-discover from .claude/skills/
265
- guides: auto-discover from guides/
288
+ guides: auto-discover from templates/guides/
266
289
  ```
267
290
 
268
291
  **Examples of dynamic creation triggers:**
@@ -107,6 +107,29 @@ For **new file creation**, **boilerplate**, or **test code generation**:
107
107
  ### Step 3: Expert Agent Selection
108
108
  Route to appropriate language/framework expert based on file extension and keyword mapping.
109
109
 
110
+ ### Step 4: Ontology-RAG Enrichment (R019)
111
+
112
+ After agent selection, enrich the spawned agent's prompt with ontology context:
113
+
114
+ 1. Call `get_agent_for_task(original_query)` via MCP
115
+ 2. Extract `suggested_skills` from response
116
+ 3. If `suggested_skills` non-empty, prepend to spawned agent prompt:
117
+ `"Ontology context suggests these skills may be relevant: {suggested_skills}"`
118
+ 4. On MCP failure: skip silently, proceed with unmodified prompt
119
+
120
+ **This step is advisory only — it never changes which agent is selected.**
121
+
122
+ ### Step 5: Soul Injection
123
+
124
+ If the selected agent has `soul: true` in its frontmatter:
125
+
126
+ 1. Read `.claude/agents/souls/{agent-name}.soul.md`
127
+ 2. If file exists, prepend soul content to the agent's prompt:
128
+ `"Identity context:\n{soul content}\n\n---\n\n"`
129
+ 3. If file doesn't exist → skip silently (no error, no injection)
130
+
131
+ **This step runs after ontology-RAG enrichment. Soul content is identity context, not capability instructions.**
132
+
110
133
  ## Routing Rules
111
134
 
112
135
  Multi-language: detect all languages, route to parallel experts (max 4). Single-language: route to matching expert. Cross-layer (frontend + backend): multiple experts in parallel.
@@ -126,7 +149,7 @@ Delegate to mgr-creator with context:
126
149
  keywords: extracted from user input
127
150
  file_patterns: detected extensions
128
151
  skills: auto-discover from .claude/skills/
129
- guides: auto-discover from guides/
152
+ guides: auto-discover from templates/guides/
130
153
  ```
131
154
 
132
155
  **Examples of dynamic creation triggers:**
@@ -32,6 +32,19 @@ Review code for best practices using language-specific expert agents.
32
32
  4. Analyze code against best practices
33
33
  5. Generate review report
34
34
  ```
35
+ 6. **Artifact persistence** (optional): Review agent saves findings to:
36
+ ```
37
+ .claude/outputs/sessions/{YYYY-MM-DD}/dev-review-{HHmmss}.md
38
+ ```
39
+ With metadata header:
40
+ ```markdown
41
+ ---
42
+ skill: dev-review
43
+ date: {ISO-8601 with timezone}
44
+ query: "{original user query}"
45
+ ---
46
+ ```
47
+ The review agent creates the directory and writes the artifact before returning results (R010 compliance).
35
48
 
36
49
  ## Agent Selection
37
50
 
@@ -44,6 +44,29 @@ quality_analysis → qa-planner + qa-engineer (parallel)
44
44
  full_qa_cycle → all agents (sequential)
45
45
  ```
46
46
 
47
+ ### Ontology-RAG Enrichment (R019)
48
+
49
+ After agent selection, enrich the spawned agent's prompt with ontology context:
50
+
51
+ 1. Call `get_agent_for_task(original_query)` via MCP
52
+ 2. Extract `suggested_skills` from response
53
+ 3. If `suggested_skills` non-empty, prepend to spawned agent prompt:
54
+ `"Ontology context suggests these skills may be relevant: {suggested_skills}"`
55
+ 4. On MCP failure: skip silently, proceed with unmodified prompt
56
+
57
+ **This step is advisory only — it never changes which agent is selected.**
58
+
59
+ ### Step 5: Soul Injection
60
+
61
+ If the selected agent has `soul: true` in its frontmatter:
62
+
63
+ 1. Read `.claude/agents/souls/{agent-name}.soul.md`
64
+ 2. If file exists, prepend soul content to the agent's prompt:
65
+ `"Identity context:\n{soul content}\n\n---\n\n"`
66
+ 3. If file doesn't exist → skip silently (no error, no injection)
67
+
68
+ **This step runs after ontology-RAG enrichment. Soul content is identity context, not capability instructions.**
69
+
47
70
  ## Routing Rules
48
71
 
49
72
  ### 1. Test Planning
@@ -293,7 +316,7 @@ Delegate to mgr-creator with context:
293
316
  type: qa-engineer
294
317
  keywords: extracted testing terms
295
318
  skills: auto-discover from .claude/skills/
296
- guides: auto-discover from guides/
319
+ guides: auto-discover from templates/guides/
297
320
  ```
298
321
 
299
322
  **Examples of dynamic creation triggers:**
@@ -45,7 +45,7 @@ Batch 2: T5, T6, T7, T8 (Integration + Comparative)
45
45
  Batch 3: T9, T10 (Innovation)
46
46
  ```
47
47
 
48
- ### Phase 2: Cross-Verification Loop (min 2, max 5 rounds)
48
+ ### Phase 2: Cross-Verification Loop (min 2, max 30 rounds)
49
49
 
50
50
  ```
51
51
  Team findings ──→ opus 4.6 verification ──→ codex-exec xhigh verification
@@ -60,7 +60,7 @@ Each round:
60
60
  3. **Contradiction resolution**: Reconcile divergent findings between teams and verifiers
61
61
  4. **Convergence check**: All major claims verified with no outstanding contradictions → proceed
62
62
 
63
- Convergence expected by round 3. Hard stop at round 5.
63
+ Convergence expected by round 3. Hard stop at round 30.
64
64
 
65
65
  ### Phase 3: Synthesis
66
66
 
@@ -71,8 +71,21 @@ Convergence expected by round 3. Hard stop at round 5.
71
71
  ### Phase 4: Output
72
72
 
73
73
  1. Structured markdown report (see Output Format below)
74
- 2. GitHub issue auto-created with findings
75
- 3. Action items with effort estimates
74
+ 2. **Artifact persistence**: The Phase 4 synthesis agent (opus) writes the report to:
75
+ ```
76
+ .claude/outputs/sessions/{YYYY-MM-DD}/research-{HHmmss}.md
77
+ ```
78
+ With metadata header:
79
+ ```markdown
80
+ ---
81
+ skill: research
82
+ date: {ISO-8601 with timezone}
83
+ query: "{original user query}"
84
+ ---
85
+ ```
86
+ The agent creates the directory (`mkdir -p`) before writing. This is a subagent operation (R010 compliance).
87
+ 3. GitHub issue auto-created with findings
88
+ 4. Action items with effort estimates
76
89
 
77
90
  ## Execution Rules
78
91
 
@@ -53,6 +53,29 @@ todo → sys-naggy
53
53
  batch → multiple (parallel)
54
54
  ```
55
55
 
56
+ ### Ontology-RAG Enrichment (R019)
57
+
58
+ After agent selection, enrich the spawned agent's prompt with ontology context:
59
+
60
+ 1. Call `get_agent_for_task(original_query)` via MCP
61
+ 2. Extract `suggested_skills` from response
62
+ 3. If `suggested_skills` non-empty, prepend to spawned agent prompt:
63
+ `"Ontology context suggests these skills may be relevant: {suggested_skills}"`
64
+ 4. On MCP failure: skip silently, proceed with unmodified prompt
65
+
66
+ **This step is advisory only — it never changes which agent is selected.**
67
+
68
+ ### Step 5: Soul Injection
69
+
70
+ If the selected agent has `soul: true` in its frontmatter:
71
+
72
+ 1. Read `.claude/agents/souls/{agent-name}.soul.md`
73
+ 2. If file exists, prepend soul content to the agent's prompt:
74
+ `"Identity context:\n{soul content}\n\n---\n\n"`
75
+ 3. If file doesn't exist → skip silently (no error, no injection)
76
+
77
+ **This step runs after ontology-RAG enrichment. Soul content is identity context, not capability instructions.**
78
+
56
79
  ## Routing Rules
57
80
 
58
81
  ### 1. Single Task Routing
@@ -168,6 +168,7 @@ Violation = immediate correction. No exception for "small changes".
168
168
  | `/optimize-analyze` | Analyze bundle and performance |
169
169
  | `/optimize-bundle` | Optimize bundle size |
170
170
  | `/optimize-report` | Generate optimization report |
171
+ | `/research` | 10-team parallel deep analysis and cross-verification |
171
172
  | `/sauron-watch` | Full R017 verification |
172
173
  | `/structured-dev-cycle` | 6-stage structured development cycle (Plan → Verify → Implement → Verify → Compound → Done) |
173
174
  | `/lists` | Show all available commands |
@@ -185,7 +186,7 @@ project/
185
186
  | +-- rules/ # Global rules (R000-R018)
186
187
  | +-- hooks/ # Hook scripts (memory, HUD)
187
188
  | +-- contexts/ # Context files (ecomode)
188
- +-- guides/ # Reference docs (23 topics)
189
+ +-- guides/ # Reference docs (25 topics)
189
190
  ```
190
191
 
191
192
  ## Orchestration
@@ -168,6 +168,7 @@ oh-my-customcode로 구동됩니다.
168
168
  | `/optimize-analyze` | 번들 및 성능 분석 |
169
169
  | `/optimize-bundle` | 번들 크기 최적화 |
170
170
  | `/optimize-report` | 최적화 리포트 생성 |
171
+ | `/research` | 10-team 병렬 딥 분석 및 교차 검증 |
171
172
  | `/sauron-watch` | 전체 R017 검증 |
172
173
  | `/structured-dev-cycle` | 6단계 구조적 개발 사이클 (Plan → Verify → Implement → Verify → Compound → Done) |
173
174
  | `/lists` | 모든 사용 가능한 커맨드 표시 |
@@ -185,7 +186,7 @@ project/
185
186
  | +-- rules/ # 전역 규칙 (R000-R018)
186
187
  | +-- hooks/ # 훅 스크립트 (메모리, HUD)
187
188
  | +-- contexts/ # 컨텍스트 파일 (ecomode)
188
- +-- guides/ # 레퍼런스 문서 (23 토픽)
189
+ +-- guides/ # 레퍼런스 문서 (25 토픽)
189
190
  ```
190
191
 
191
192
  ## 오케스트레이션
@@ -0,0 +1,120 @@
1
+ # Flutter Security Guide
2
+
3
+ > Reference: OWASP Mobile Top 10 (2024), Flutter Official Documentation
4
+
5
+ ## OWASP Mobile Top 10 Mapping
6
+
7
+ ### M1 — Improper Credential Usage
8
+
9
+ - Never hardcode API keys, tokens, or credentials in source code
10
+ - Backend proxy pattern: route ALL sensitive API calls through server
11
+ - `--dart-define-from-file=.env` is for NON-SECRET build config only (values are extractable from binary)
12
+ - Credential rotation: implement token refresh with `dio` interceptor
13
+ - OAuth2 flow: use `flutter_appauth` for PKCE-based authentication
14
+
15
+ ### M2 — Inadequate Supply Chain Security
16
+
17
+ - Run `dart pub audit` before every release to check for known vulnerabilities
18
+ - Pin exact versions in `pubspec.yaml` for production (`package: 1.2.3` not `package: ^1.2.3`)
19
+ - Verify package publisher on pub.dev (look for verified publisher badge)
20
+ - Review transitive dependencies: `dart pub deps --style=compact`
21
+ - Avoid packages with no recent updates (> 12 months without commits)
22
+
23
+ ### M3 — Insecure Authentication/Authorization
24
+
25
+ - Biometric authentication: `local_auth` package with `BiometricType.fingerprint` / `BiometricType.face`
26
+ - Session management: implement token expiry checking before API calls
27
+ - JWT client-side validation: verify `exp`, `aud`, `iss` claims before using tokens
28
+ - Re-authentication: require biometric/PIN for sensitive operations (payment, profile changes)
29
+ - Deep link auth: validate authentication state before processing deep link navigation
30
+
31
+ ### M4 — Insufficient Input/Output Validation
32
+
33
+ - Validate ALL deep link URI parameters with RegExp allowlists
34
+ - Sanitize user input before displaying in WebView (`flutter_inappwebview`)
35
+ - Use `Uri.parse()` with try-catch, never trust raw string URLs
36
+ - Output encoding: escape HTML entities when rendering user content
37
+ - Form validation: use `TextFormField` validators, never trust client-side validation alone
38
+
39
+ ### M5 — Insecure Communication
40
+
41
+ - Certificate pinning (SPKI): use `dio` with custom `SecurityContext`
42
+ - Extract SPKI hash: `openssl s_client -connect host:443 | openssl x509 -pubkey | openssl pkey -pubin -outform DER | openssl dgst -sha256 -binary | base64`
43
+ - Include backup pins for certificate rotation
44
+ - Android: `network_security_config.xml` with `cleartextTrafficPermitted=false`
45
+ - iOS: ATS enabled (`NSAllowsArbitraryLoads=false`), never override in production
46
+
47
+ ### M6 — Inadequate Privacy Controls
48
+
49
+ - Request minimum platform permissions (camera, location, contacts)
50
+ - iOS: provide usage description strings in Info.plist for every permission
51
+ - Android: use runtime permissions, respect "Don't ask again"
52
+ - Data minimization: only collect and store data that is necessary
53
+ - GDPR/CCPA: implement data export and deletion capabilities
54
+
55
+ ### M7 — Insufficient Binary Protections
56
+
57
+ - Release builds: `flutter build --obfuscate --split-debug-info=debug-info/`
58
+ - Store debug symbols securely for crash reporting (Crashlytics, Sentry)
59
+ - Android ProGuard: configure `android/app/proguard-rules.pro`
60
+ - Note: `--obfuscate` does NOT apply to `flutter build web` (JS minification is the web equivalent)
61
+ - Anti-tampering: consider `flutter_jailbreak_detection` for integrity checks
62
+
63
+ ### M8 — Security Misconfiguration
64
+
65
+ - Android: set `android:debuggable="false"` in release manifest
66
+ - Android: set `android:allowBackup="false"` to prevent ADB data extraction
67
+ - iOS: enable data protection with `NSFileProtectionComplete`
68
+ - Remove all debug logging in release: guard with `kDebugMode`
69
+ - Firebase: secure `google-services.json` / `GoogleService-Info.plist` (add to .gitignore)
70
+
71
+ ### M9 — Insecure Data Storage
72
+
73
+ - Sensitive data: `flutter_secure_storage` v10+ (iOS Keychain / Android EncryptedSharedPreferences)
74
+ - iOS: `IOSOptions(accessibility: KeychainAccessibility.first_unlock_this_device)`
75
+ - Android: `AndroidOptions(encryptedSharedPreferences: true)`
76
+ - Web WARNING: `flutter_secure_storage` uses localStorage on Web (XSS vulnerable) — use HttpOnly cookies or in-memory storage
77
+ - Never use `SharedPreferences` for tokens, PII, or credentials
78
+ - Screenshot protection: Android `FLAG_SECURE` via `flutter_windowmanager`
79
+
80
+ ### M10 — Insufficient Cryptography
81
+
82
+ - Use `pointycastle` or `cryptography` package for custom crypto operations
83
+ - Avoid: MD5, SHA-1, DES, ECB mode, hardcoded IVs/keys
84
+ - Prefer: AES-256-GCM for symmetric, RSA-OAEP or ECDSA for asymmetric
85
+ - Key storage: always delegate to platform Keychain/Keystore, never store in app data
86
+ - Random number generation: use `Random.secure()` for security-sensitive values
87
+
88
+ ## Platform-Specific Security
89
+
90
+ ### iOS
91
+
92
+ - Keychain with Secure Enclave: `IOSOptions(useSecureEnclave: true)` for high-value data
93
+ - ATS enforcement: never add `NSAllowsArbitraryLoads` exception for production
94
+ - Jailbreak detection: `flutter_jailbreak_detection` package
95
+
96
+ ### Android
97
+
98
+ - Keystore-backed encryption via `EncryptedSharedPreferences`
99
+ - Network security config: pin certificates, block cleartext
100
+ - Root detection: `flutter_jailbreak_detection` or `safe_device`
101
+ - `allowBackup=false` in AndroidManifest.xml
102
+
103
+ ### Web
104
+
105
+ - CSP headers: configure on the server hosting Flutter web app
106
+ - Avoid storing sensitive data in localStorage or sessionStorage
107
+ - Use HttpOnly, Secure, SameSite cookies for authentication tokens
108
+ - XSS prevention: sanitize all user-generated content before rendering
109
+
110
+ ## Package Recommendations
111
+
112
+ | Category | Package | Notes |
113
+ |----------|---------|-------|
114
+ | Secure Storage | `flutter_secure_storage` | Keychain/Keystore, v10+; Web: localStorage (XSS risk) |
115
+ | OAuth2 / PKCE | `flutter_appauth` | PKCE-based auth flows |
116
+ | Biometrics | `local_auth` | Fingerprint, Face ID |
117
+ | HTTP (pinning) | `dio` | Custom `SecurityContext` for certificate pinning |
118
+ | Crypto | `cryptography` | AES-GCM, RSA-OAEP, ECDSA |
119
+ | Integrity check | `flutter_jailbreak_detection` | Root/jailbreak detection |
120
+ | Screenshot protect | `flutter_windowmanager` | Android `FLAG_SECURE` |
@@ -0,0 +1,29 @@
1
+ # Java 21 Guide
2
+
3
+ metadata:
4
+ name: java21
5
+ description: Java 21 language reference and modern feature documentation
6
+
7
+ source:
8
+ type: external
9
+ origin: docs.oracle.com
10
+ urls:
11
+ - https://docs.oracle.com/en/java/javase/21/
12
+ - https://openjdk.org/projects/loom/
13
+ - https://openjdk.org/jeps/440
14
+ - https://openjdk.org/jeps/441
15
+ - https://openjdk.org/jeps/444
16
+ - https://google.github.io/styleguide/javaguide.html
17
+ last_fetched: "2026-03-11"
18
+
19
+ documents:
20
+ - name: modern-java21
21
+ path: ./modern-java21.md
22
+ description: Java 21 modern features (Virtual Threads, Pattern Matching, Records, Sealed Classes)
23
+
24
+ - name: java-style-guide
25
+ path: ./java-style-guide.md
26
+ description: Google Java Style Guide conventions
27
+
28
+ used_by:
29
+ - lang-java21-expert
@@ -0,0 +1,248 @@
1
+ # Java Style Guide
2
+
3
+ > Source: https://google.github.io/styleguide/javaguide.html
4
+
5
+ ## File Structure
6
+
7
+ ```
8
+ Source file:
9
+ 1. License/copyright (if any)
10
+ 2. Package statement
11
+ 3. Import statements
12
+ 4. Exactly one top-level class
13
+ ```
14
+
15
+ ### Import Ordering
16
+
17
+ ```java
18
+ // 1. Static imports (all together)
19
+ import static org.junit.Assert.assertEquals;
20
+
21
+ // 2. Non-static imports (all together, no subgroups)
22
+ import com.example.Foo;
23
+ import java.util.List;
24
+ import org.springframework.boot.SpringApplication;
25
+ ```
26
+
27
+ No wildcard imports except `static` test imports.
28
+
29
+ ---
30
+
31
+ ## Naming Conventions
32
+
33
+ | Element | Style | Example |
34
+ |---------|-------|---------|
35
+ | Packages | `lowercase` | `com.example.network` |
36
+ | Classes | `UpperCamelCase` | `OrderProcessor` |
37
+ | Records | `UpperCamelCase` | `UserRecord` |
38
+ | Methods | `lowerCamelCase` | `processOrder()` |
39
+ | Local vars | `lowerCamelCase` | `itemCount` |
40
+ | Constants | `UPPER_SNAKE_CASE` | `MAX_RETRIES` |
41
+ | Type params | Single letter or `UpperCamelCase + T` | `T`, `E`, `RequestT` |
42
+
43
+ ### Acronyms
44
+
45
+ Treat acronyms as words: `XmlParser`, not `XMLParser`. Exception: well-known 2-letter ones like `IO`.
46
+
47
+ ---
48
+
49
+ ## Formatting
50
+
51
+ ### Indentation
52
+
53
+ - 2 spaces (not tabs) for block indentation
54
+ - 4 spaces for line continuation
55
+
56
+ ```java
57
+ // Block indentation: 2 spaces
58
+ if (condition) {
59
+ doSomething();
60
+ }
61
+
62
+ // Line continuation: 4 spaces
63
+ String result = longMethodName(
64
+ argument1,
65
+ argument2);
66
+ ```
67
+
68
+ ### Braces
69
+
70
+ Always use braces, even for single-statement bodies:
71
+
72
+ ```java
73
+ // Correct
74
+ if (condition) {
75
+ doSomething();
76
+ }
77
+
78
+ // Wrong (no braces)
79
+ if (condition)
80
+ doSomething();
81
+ ```
82
+
83
+ ### Column Limit
84
+
85
+ 100 characters per line. Wrap when exceeding.
86
+
87
+ ### Blank Lines
88
+
89
+ ```java
90
+ class MyClass {
91
+ private int field; // field
92
+ // one blank line
93
+ public MyClass() { } // constructor
94
+ // one blank line
95
+ public void method() { } // method
96
+ }
97
+ ```
98
+
99
+ ---
100
+
101
+ ## Class Structure
102
+
103
+ ```java
104
+ public class MyClass {
105
+ // 1. Static fields
106
+ private static final Logger log = LoggerFactory.getLogger(MyClass.class);
107
+
108
+ // 2. Instance fields
109
+ private final String name;
110
+
111
+ // 3. Constructors
112
+ public MyClass(String name) {
113
+ this.name = name;
114
+ }
115
+
116
+ // 4. Static factory methods (if applicable)
117
+ public static MyClass of(String name) {
118
+ return new MyClass(name);
119
+ }
120
+
121
+ // 5. Instance methods (public → package → protected → private)
122
+ public String getName() { return name; }
123
+
124
+ private void helper() { }
125
+
126
+ // 6. Inner classes/interfaces (last)
127
+ }
128
+ ```
129
+
130
+ ---
131
+
132
+ ## Programming Practices
133
+
134
+ ### Annotations
135
+
136
+ ```java
137
+ // One annotation per line for class/method
138
+ @Override
139
+ @Nullable
140
+ public String format(String input) { }
141
+
142
+ // Multiple short annotations on one line for field is OK
143
+ @Nullable @Deprecated String field;
144
+ ```
145
+
146
+ ### Numeric Literals
147
+
148
+ ```java
149
+ long big = 1_000_000L;
150
+ double pi = 3.14_159;
151
+ int hex = 0xFF_EC_D1_8C;
152
+ ```
153
+
154
+ ### Switch Expressions (prefer over statements)
155
+
156
+ ```java
157
+ // Prefer switch expression
158
+ int days = switch (month) {
159
+ case JANUARY, MARCH, MAY, JULY, AUGUST, OCTOBER, DECEMBER -> 31;
160
+ case APRIL, JUNE, SEPTEMBER, NOVEMBER -> 30;
161
+ case FEBRUARY -> 28;
162
+ };
163
+ ```
164
+
165
+ ### Avoid Long Methods
166
+
167
+ Keep methods short and focused. Extract helpers for blocks exceeding ~20 lines.
168
+
169
+ ---
170
+
171
+ ## Javadoc
172
+
173
+ ### Required for
174
+
175
+ - Every `public` class, interface, enum, record
176
+ - Every `public` or `protected` method (unless trivially obvious)
177
+
178
+ ### Format
179
+
180
+ ```java
181
+ /**
182
+ * Returns the user associated with the given ID.
183
+ *
184
+ * <p>This method performs a database lookup. It is safe to call
185
+ * from multiple threads.
186
+ *
187
+ * @param id the user identifier (must be positive)
188
+ * @return the user, or empty if not found
189
+ * @throws IllegalArgumentException if {@code id <= 0}
190
+ */
191
+ public Optional<User> findById(long id) { }
192
+ ```
193
+
194
+ ### Inline Tags
195
+
196
+ ```java
197
+ /**
198
+ * See {@link UserRepository} for persistence details.
199
+ * Use {@code null} to reset the state.
200
+ */
201
+ ```
202
+
203
+ ### Prohibited: Non-Javadoc Comments for API
204
+
205
+ ```java
206
+ // Wrong: plain comment for public method
207
+ // Returns the user by id
208
+ public Optional<User> findById(long id) { }
209
+
210
+ // Correct: Javadoc
211
+ /** Returns the user by id, or empty if not found. */
212
+ public Optional<User> findById(long id) { }
213
+ ```
214
+
215
+ ---
216
+
217
+ ## Common Antipatterns to Avoid
218
+
219
+ ```java
220
+ // ❌ Raw types
221
+ List list = new ArrayList();
222
+ // ✓
223
+ List<String> list = new ArrayList<>();
224
+
225
+ // ❌ String concatenation in loop
226
+ String s = "";
227
+ for (String item : items) s += item;
228
+ // ✓
229
+ StringBuilder sb = new StringBuilder();
230
+ for (String item : items) sb.append(item);
231
+ String s = sb.toString();
232
+
233
+ // ❌ Return null for collections
234
+ public List<String> getItems() { return null; }
235
+ // ✓
236
+ public List<String> getItems() { return Collections.emptyList(); }
237
+
238
+ // ❌ Catch Exception broadly
239
+ try { process(); } catch (Exception e) { }
240
+ // ✓
241
+ try { process(); } catch (IOException e) { log.error("IO error", e); }
242
+
243
+ // ❌ Mutable public field
244
+ public String name;
245
+ // ✓
246
+ private String name;
247
+ public String getName() { return name; }
248
+ ```
@@ -0,0 +1,303 @@
1
+ # Modern Java 21 Features
2
+
3
+ > Sources: https://openjdk.org/jeps/ (JEP 431, 440, 441, 444)
4
+
5
+ ## Virtual Threads (JEP 444)
6
+
7
+ Virtual Threads are lightweight threads managed by the JVM, enabling millions of concurrent tasks without thread pool tuning.
8
+
9
+ ### Key Properties
10
+
11
+ | Property | Platform Thread | Virtual Thread |
12
+ |----------|----------------|----------------|
13
+ | Creation cost | High (OS thread) | Low (JVM-managed) |
14
+ | Memory footprint | ~1MB per thread | ~few KB |
15
+ | Blocking behavior | Blocks OS thread | Unmounts carrier thread |
16
+ | Pooling | Needed | Not recommended |
17
+
18
+ ### Usage
19
+
20
+ ```java
21
+ // Virtual Thread executor (preferred for I/O-bound tasks)
22
+ try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
23
+ List<Future<String>> futures = IntStream.range(0, 10_000)
24
+ .mapToObj(i -> executor.submit(() -> fetchData(i)))
25
+ .toList();
26
+ // all 10,000 tasks run concurrently
27
+ }
28
+
29
+ // Direct creation
30
+ Thread.ofVirtual().name("vt-worker").start(() -> processRequest());
31
+
32
+ // Factory for thread pools
33
+ ThreadFactory factory = Thread.ofVirtual().name("worker-", 0).factory();
34
+ ```
35
+
36
+ ### Structured Concurrency (JEP 453, Preview)
37
+
38
+ ```java
39
+ try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
40
+ Future<String> user = scope.fork(() -> fetchUser(id));
41
+ Future<String> orders = scope.fork(() -> fetchOrders(id));
42
+
43
+ scope.join().throwIfFailed();
44
+
45
+ return new UserProfile(user.get(), orders.get());
46
+ }
47
+ ```
48
+
49
+ ### Pinning Avoidance
50
+
51
+ Virtual Threads are **pinned** (cannot unmount) inside `synchronized` blocks. Prefer `ReentrantLock`:
52
+
53
+ ```java
54
+ // Avoid (causes pinning)
55
+ synchronized (lock) {
56
+ callBlockingIO();
57
+ }
58
+
59
+ // Prefer
60
+ private final ReentrantLock lock = new ReentrantLock();
61
+ lock.lock();
62
+ try {
63
+ callBlockingIO();
64
+ } finally {
65
+ lock.unlock();
66
+ }
67
+ ```
68
+
69
+ ---
70
+
71
+ ## Pattern Matching for instanceof (JEP 394)
72
+
73
+ ```java
74
+ // Before Java 16
75
+ if (obj instanceof String) {
76
+ String s = (String) obj;
77
+ return s.length();
78
+ }
79
+
80
+ // Java 21
81
+ if (obj instanceof String s) {
82
+ return s.length();
83
+ }
84
+
85
+ // With guard
86
+ if (obj instanceof String s && !s.isEmpty()) {
87
+ return s.toUpperCase();
88
+ }
89
+ ```
90
+
91
+ ---
92
+
93
+ ## Pattern Matching for switch (JEP 441)
94
+
95
+ ```java
96
+ // Type patterns
97
+ String format = switch (obj) {
98
+ case Integer i -> String.format("int %d", i);
99
+ case Double d -> String.format("double %.2f", d);
100
+ case String s -> String.format("String '%s'", s);
101
+ case null -> "null value";
102
+ default -> obj.toString();
103
+ };
104
+
105
+ // Guarded patterns (when clause)
106
+ String classify = switch (number) {
107
+ case Integer i when i < 0 -> "negative";
108
+ case Integer i when i == 0 -> "zero";
109
+ case Integer i -> "positive";
110
+ default -> "non-integer";
111
+ };
112
+ ```
113
+
114
+ ---
115
+
116
+ ## Record Classes (JEP 395)
117
+
118
+ Records are immutable data carriers with auto-generated `equals`, `hashCode`, `toString`, and accessors.
119
+
120
+ ```java
121
+ // Basic record
122
+ record Point(int x, int y) {}
123
+
124
+ Point p = new Point(3, 4);
125
+ int x = p.x(); // accessor (not getX())
126
+ System.out.println(p); // Point[x=3, y=4]
127
+
128
+ // Compact constructor (validation)
129
+ record Range(int min, int max) {
130
+ Range {
131
+ if (min > max)
132
+ throw new IllegalArgumentException(
133
+ "min %d > max %d".formatted(min, max));
134
+ }
135
+ }
136
+
137
+ // Custom methods
138
+ record Circle(double radius) {
139
+ static final double PI = Math.PI;
140
+
141
+ double area() { return PI * radius * radius; }
142
+
143
+ Circle scale(double factor) { return new Circle(radius * factor); }
144
+ }
145
+
146
+ // Implementing interface
147
+ interface Describable { String describe(); }
148
+ record Color(int r, int g, int b) implements Describable {
149
+ public String describe() {
150
+ return "rgb(%d,%d,%d)".formatted(r, g, b);
151
+ }
152
+ }
153
+ ```
154
+
155
+ ### When to Use Records vs Classes
156
+
157
+ | Use Record | Use Class |
158
+ |------------|-----------|
159
+ | Pure data containers | Entities with mutable state |
160
+ | DTOs, value objects | Domain objects with lifecycle |
161
+ | API response types | Services, repositories |
162
+ | Config/settings | Mutable builders |
163
+
164
+ ---
165
+
166
+ ## Record Patterns (JEP 440)
167
+
168
+ Deconstruct records directly in `instanceof` and `switch`:
169
+
170
+ ```java
171
+ // instanceof deconstruction
172
+ if (obj instanceof Point(int x, int y)) {
173
+ System.out.println("x=" + x + ", y=" + y);
174
+ }
175
+
176
+ // switch deconstruction
177
+ String describe = switch (shape) {
178
+ case Circle(double r) -> "circle r=%.2f".formatted(r);
179
+ case Rectangle(double w, double h) -> "rect %.1fx%.1f".formatted(w, h);
180
+ default -> "unknown";
181
+ };
182
+
183
+ // Nested patterns
184
+ record ColoredPoint(Point point, Color color) {}
185
+
186
+ if (obj instanceof ColoredPoint(Point(int x, int y), Color(int r, int g, int b))) {
187
+ System.out.printf("Colored point at (%d,%d) with rgb(%d,%d,%d)%n",
188
+ x, y, r, g, b);
189
+ }
190
+ ```
191
+
192
+ ---
193
+
194
+ ## Sealed Classes (JEP 409)
195
+
196
+ Sealed classes restrict which classes can implement/extend them, enabling exhaustive pattern matching.
197
+
198
+ ```java
199
+ // Sealed interface with records
200
+ sealed interface Shape permits Circle, Rectangle, Triangle {}
201
+
202
+ record Circle(double radius) implements Shape {}
203
+ record Rectangle(double width, double height) implements Shape {}
204
+ record Triangle(double base, double height) implements Shape {}
205
+
206
+ // Exhaustive switch — no default needed
207
+ double area = switch (shape) {
208
+ case Circle(double r) -> Math.PI * r * r;
209
+ case Rectangle(double w, double h) -> w * h;
210
+ case Triangle(double b, double h) -> 0.5 * b * h;
211
+ };
212
+
213
+ // Sealed class hierarchy (non-record)
214
+ sealed class Vehicle permits Car, Truck, Motorcycle {}
215
+ final class Car extends Vehicle { }
216
+ non-sealed class Truck extends Vehicle { } // allows further subclassing
217
+ ```
218
+
219
+ ### Benefits
220
+
221
+ - Compiler enforces exhaustive handling in `switch`
222
+ - Clear closed type hierarchy in domain model
223
+ - Better than `enum` when subtypes carry different data
224
+
225
+ ---
226
+
227
+ ## Sequenced Collections (JEP 431)
228
+
229
+ New interfaces: `SequencedCollection`, `SequencedSet`, `SequencedMap`.
230
+
231
+ ```java
232
+ // SequencedCollection
233
+ List<String> list = new ArrayList<>(List.of("a", "b", "c"));
234
+ String first = list.getFirst(); // "a"
235
+ String last = list.getLast(); // "c"
236
+ list.addFirst("z"); // ["z", "a", "b", "c"]
237
+ list.addLast("end"); // ["z", "a", "b", "c", "end"]
238
+ list.removeFirst(); // ["a", "b", "c", "end"]
239
+
240
+ // Reversed view (live, backed by original)
241
+ List<String> reversed = list.reversed();
242
+
243
+ // SequencedMap
244
+ LinkedHashMap<String, Integer> map = new LinkedHashMap<>();
245
+ map.put("one", 1);
246
+ map.put("two", 2);
247
+ map.put("three", 3);
248
+
249
+ Map.Entry<String, Integer> first = map.firstEntry(); // "one"=1
250
+ Map.Entry<String, Integer> last = map.lastEntry(); // "three"=3
251
+ map.putFirst("zero", 0); // inserts at front
252
+ SequencedMap<String, Integer> rev = map.reversed();
253
+ ```
254
+
255
+ ---
256
+
257
+ ## Migration from Legacy Java
258
+
259
+ ### Replace instanceof chains
260
+
261
+ ```java
262
+ // Legacy (avoid)
263
+ if (obj instanceof String) {
264
+ return ((String) obj).length();
265
+ } else if (obj instanceof Integer) {
266
+ return ((Integer) obj).intValue();
267
+ }
268
+
269
+ // Modern
270
+ return switch (obj) {
271
+ case String s -> s.length();
272
+ case Integer i -> i;
273
+ default -> -1;
274
+ };
275
+ ```
276
+
277
+ ### Replace POJOs with Records
278
+
279
+ ```java
280
+ // Legacy POJO (avoid for pure data)
281
+ public class Point {
282
+ private final int x, y;
283
+ public Point(int x, int y) { this.x = x; this.y = y; }
284
+ public int getX() { return x; }
285
+ public int getY() { return y; }
286
+ @Override public boolean equals(Object o) { ... }
287
+ @Override public int hashCode() { ... }
288
+ @Override public String toString() { ... }
289
+ }
290
+
291
+ // Modern Record
292
+ record Point(int x, int y) {}
293
+ ```
294
+
295
+ ### Replace thread pools for I/O with Virtual Threads
296
+
297
+ ```java
298
+ // Legacy (avoid for I/O-bound)
299
+ ExecutorService pool = Executors.newFixedThreadPool(200);
300
+
301
+ // Modern
302
+ ExecutorService pool = Executors.newVirtualThreadPerTaskExecutor();
303
+ ```
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.30.9",
2
+ "version": "0.31.1",
3
3
  "lastUpdated": "2026-03-09T00:00:00.000Z",
4
4
  "components": [
5
5
  {
@@ -24,7 +24,7 @@
24
24
  "name": "guides",
25
25
  "path": "guides",
26
26
  "description": "Reference documentation",
27
- "files": 24
27
+ "files": 25
28
28
  },
29
29
  {
30
30
  "name": "hooks",
@@ -1,9 +0,0 @@
1
- <claude-mem-context>
2
- # Recent Activity
3
-
4
- ### Feb 5, 2026
5
-
6
- | ID | Time | T | Title | Read |
7
- |----|------|---|-------|------|
8
- | #8 | 8:07 PM | 🔵 | Skill Definition Structure | ~626 |
9
- </claude-mem-context>