@orderful/droid 0.48.0 → 0.50.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 (76) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +2 -1
  3. package/CHANGELOG.md +24 -0
  4. package/bun.lock +137 -3
  5. package/dist/bin/droid.js +355 -90
  6. package/dist/commands/pack.d.ts +5 -0
  7. package/dist/commands/pack.d.ts.map +1 -0
  8. package/dist/index.js +11 -0
  9. package/dist/lib/pack.d.ts +31 -0
  10. package/dist/lib/pack.d.ts.map +1 -0
  11. package/dist/lib/types.d.ts +17 -0
  12. package/dist/lib/types.d.ts.map +1 -1
  13. package/dist/tools/brain/TOOL.yaml +2 -0
  14. package/dist/tools/coach/TOOL.yaml +4 -0
  15. package/dist/tools/code-review/.claude-plugin/plugin.json +3 -2
  16. package/dist/tools/code-review/TOOL.yaml +4 -1
  17. package/dist/tools/code-review/agents/codex-context-researcher.md +99 -0
  18. package/dist/tools/code-review/skills/code-review/SKILL.md +20 -1
  19. package/dist/tools/codex/.claude-plugin/plugin.json +1 -1
  20. package/dist/tools/codex/TOOL.yaml +3 -1
  21. package/dist/tools/codex/skills/codex/SKILL.md +5 -1
  22. package/dist/tools/codex/skills/codex/scripts/normalize-frontmatter.d.ts +61 -0
  23. package/dist/tools/codex/skills/codex/scripts/normalize-frontmatter.d.ts.map +1 -0
  24. package/dist/tools/codex/skills/codex/scripts/normalize-frontmatter.ts +402 -0
  25. package/dist/tools/comments/TOOL.yaml +2 -0
  26. package/dist/tools/droid/.claude-plugin/plugin.json +1 -1
  27. package/dist/tools/droid/TOOL.yaml +3 -1
  28. package/dist/tools/droid/skills/droid/SKILL.md +48 -2
  29. package/dist/tools/droid/skills/droid/references/new-tool-workflow.md +234 -0
  30. package/dist/tools/edi-schema/TOOL.yaml +2 -0
  31. package/dist/tools/excalidraw/TOOL.yaml +2 -0
  32. package/dist/tools/meeting/TOOL.yaml +2 -0
  33. package/dist/tools/pii/TOOL.yaml +2 -0
  34. package/dist/tools/plan/TOOL.yaml +4 -0
  35. package/dist/tools/project/TOOL.yaml +2 -0
  36. package/dist/tools/release/TOOL.yaml +2 -0
  37. package/dist/tools/share/TOOL.yaml +2 -0
  38. package/dist/tools/status-update/TOOL.yaml +4 -0
  39. package/dist/tools/tech-design/TOOL.yaml +2 -0
  40. package/dist/tools/wrapup/TOOL.yaml +2 -0
  41. package/package.json +3 -1
  42. package/scripts/build.ts +3 -2
  43. package/src/bin/droid.ts +9 -0
  44. package/src/commands/pack.ts +77 -0
  45. package/src/lib/pack.test.ts +85 -0
  46. package/src/lib/pack.ts +293 -0
  47. package/src/lib/types.ts +19 -0
  48. package/src/tools/brain/TOOL.yaml +2 -0
  49. package/src/tools/coach/TOOL.yaml +4 -0
  50. package/src/tools/code-review/.claude-plugin/plugin.json +3 -2
  51. package/src/tools/code-review/TOOL.yaml +4 -1
  52. package/src/tools/code-review/agents/codex-context-researcher.md +99 -0
  53. package/src/tools/code-review/skills/code-review/SKILL.md +20 -1
  54. package/src/tools/codex/.claude-plugin/plugin.json +1 -1
  55. package/src/tools/codex/TOOL.yaml +3 -1
  56. package/src/tools/codex/skills/codex/SKILL.md +5 -1
  57. package/src/tools/codex/skills/codex/scripts/normalize-frontmatter.test.ts +331 -0
  58. package/src/tools/codex/skills/codex/scripts/normalize-frontmatter.ts +402 -0
  59. package/src/tools/comments/TOOL.yaml +2 -0
  60. package/src/tools/droid/.claude-plugin/plugin.json +1 -1
  61. package/src/tools/droid/TOOL.yaml +3 -1
  62. package/src/tools/droid/skills/droid/SKILL.md +48 -2
  63. package/src/tools/droid/skills/droid/references/new-tool-workflow.md +234 -0
  64. package/src/tools/edi-schema/TOOL.yaml +2 -0
  65. package/src/tools/excalidraw/TOOL.yaml +2 -0
  66. package/src/tools/meeting/TOOL.yaml +2 -0
  67. package/src/tools/pii/TOOL.yaml +2 -0
  68. package/src/tools/plan/TOOL.yaml +4 -0
  69. package/src/tools/project/TOOL.yaml +2 -0
  70. package/src/tools/release/TOOL.yaml +2 -0
  71. package/src/tools/share/TOOL.yaml +2 -0
  72. package/src/tools/status-update/TOOL.yaml +4 -0
  73. package/src/tools/tech-design/TOOL.yaml +2 -0
  74. package/src/tools/wrapup/TOOL.yaml +2 -0
  75. package/dist/tools/codex/skills/codex/scripts/git-scripts.test.ts +0 -364
  76. package/dist/tools/pii/skills/pii/scripts/presidio.test.ts +0 -444
@@ -0,0 +1,293 @@
1
+ import { existsSync, readdirSync, readFileSync, createWriteStream } from 'fs';
2
+ import { join } from 'path';
3
+ import archiver from 'archiver';
4
+ import { getBundledTools, getBundledToolsDir } from './tools';
5
+ import { ToolAudience, type ToolManifest } from './types';
6
+
7
+ export interface AudienceInfo {
8
+ audience: ToolAudience;
9
+ toolCount: number;
10
+ toolNames: string[];
11
+ }
12
+
13
+ export interface PackOptions {
14
+ audience: ToolAudience;
15
+ outputDir: string;
16
+ }
17
+
18
+ export interface PackResult {
19
+ success: boolean;
20
+ message: string;
21
+ outputPath?: string;
22
+ toolCount?: number;
23
+ warnings?: string[];
24
+ }
25
+
26
+ /**
27
+ * Get tools filtered by audience
28
+ * Tools with audience 'all' are always included
29
+ */
30
+ export function getToolsForAudience(
31
+ audience: ToolAudience,
32
+ ): ToolManifest[] {
33
+ const allTools = getBundledTools();
34
+
35
+ return allTools.filter((tool) => {
36
+ // Skip tools without audience metadata
37
+ if (!tool.audience || tool.audience.length === 0) {
38
+ return false;
39
+ }
40
+
41
+ // Must match the requested audience OR be audience 'all'
42
+ return (
43
+ tool.audience.includes(audience) ||
44
+ tool.audience.includes(ToolAudience.All)
45
+ );
46
+ });
47
+ }
48
+
49
+ /**
50
+ * Get audience info for all audiences that have tools
51
+ */
52
+ export function getAudienceInfo(): AudienceInfo[] {
53
+ const allTools = getBundledTools();
54
+ const audiences = Object.values(ToolAudience).filter(
55
+ (a) => a !== ToolAudience.All,
56
+ );
57
+
58
+ return audiences
59
+ .map((audience) => {
60
+ const tools = allTools.filter(
61
+ (tool) =>
62
+ tool.audience &&
63
+ (tool.audience.includes(audience) ||
64
+ tool.audience.includes(ToolAudience.All)),
65
+ );
66
+
67
+ return {
68
+ audience,
69
+ toolCount: tools.length,
70
+ toolNames: tools.map((t) => t.name),
71
+ };
72
+ })
73
+ .filter((info) => info.toolCount > 0);
74
+ }
75
+
76
+ /**
77
+ * Collect all artifact paths for a tool (skills, commands, agents)
78
+ * Returns paths relative to the zip root (installed format)
79
+ */
80
+ function collectToolArtifacts(
81
+ tool: ToolManifest,
82
+ ): Array<{ sourcePath: string; zipPath: string }> {
83
+ const artifacts: Array<{ sourcePath: string; zipPath: string }> = [];
84
+ const toolDir = join(getBundledToolsDir(), tool.name);
85
+
86
+ // Skills
87
+ for (const skill of tool.includes.skills) {
88
+ const skillDir = join(toolDir, 'skills', skill.name);
89
+ if (!existsSync(skillDir)) continue;
90
+
91
+ // SKILL.md
92
+ const skillMd = join(skillDir, 'SKILL.md');
93
+ if (existsSync(skillMd)) {
94
+ artifacts.push({
95
+ sourcePath: skillMd,
96
+ zipPath: `skills/${skill.name}/SKILL.md`,
97
+ });
98
+ }
99
+
100
+ // references/
101
+ const refsDir = join(skillDir, 'references');
102
+ if (existsSync(refsDir)) {
103
+ const refFiles = readdirSync(refsDir).filter((f) => f.endsWith('.md'));
104
+ for (const file of refFiles) {
105
+ artifacts.push({
106
+ sourcePath: join(refsDir, file),
107
+ zipPath: `skills/${skill.name}/references/${file}`,
108
+ });
109
+ }
110
+ }
111
+ }
112
+
113
+ // Commands
114
+ const commandsDir = join(toolDir, 'commands');
115
+ if (existsSync(commandsDir)) {
116
+ const commandFiles = readdirSync(commandsDir).filter(
117
+ (f) => f.endsWith('.md') && f.toLowerCase() !== 'readme.md',
118
+ );
119
+ for (const file of commandFiles) {
120
+ artifacts.push({
121
+ sourcePath: join(commandsDir, file),
122
+ zipPath: `commands/${file}`,
123
+ });
124
+ }
125
+ }
126
+
127
+ // Agents
128
+ const agentsDir = join(toolDir, 'agents');
129
+ if (existsSync(agentsDir)) {
130
+ const agentFiles = readdirSync(agentsDir).filter(
131
+ (f) => f.endsWith('.md') && f.toLowerCase() !== 'readme.md',
132
+ );
133
+ for (const file of agentFiles) {
134
+ artifacts.push({
135
+ sourcePath: join(agentsDir, file),
136
+ zipPath: `agents/${file}`,
137
+ });
138
+ }
139
+ }
140
+
141
+ return artifacts;
142
+ }
143
+
144
+ /**
145
+ * Generate CLAUDE.md content with skill registration links
146
+ */
147
+ function generateClaudeMd(tools: ToolManifest[]): string {
148
+ const skillNames: string[] = [];
149
+ for (const tool of tools) {
150
+ for (const skill of tool.includes.skills) {
151
+ skillNames.push(skill.name);
152
+ }
153
+ }
154
+
155
+ const lines = [
156
+ '# Droid Skills',
157
+ '',
158
+ 'Skills installed from a Droid pack. Each skill teaches your AI new capabilities.',
159
+ '',
160
+ ];
161
+
162
+ for (const name of skillNames) {
163
+ lines.push(`- [${name}](skills/${name}/SKILL.md)`);
164
+ }
165
+
166
+ lines.push('');
167
+ return lines.join('\n');
168
+ }
169
+
170
+ /**
171
+ * Generate README.md with install instructions
172
+ */
173
+ function generateReadme(audience: ToolAudience, tools: ToolManifest[]): string {
174
+ const lines = [
175
+ `# Droid Pack: ${audience}`,
176
+ '',
177
+ 'This pack contains AI skills, commands, and agents for Claude Desktop.',
178
+ '',
179
+ '## Installation',
180
+ '',
181
+ '1. Unzip this archive',
182
+ '2. Copy the contents into your `~/.claude/` directory:',
183
+ '',
184
+ '```bash',
185
+ '# From the directory where you unzipped:',
186
+ 'cp -r skills/ ~/.claude/skills/',
187
+ 'cp -r commands/ ~/.claude/commands/',
188
+ 'cp -r agents/ ~/.claude/agents/',
189
+ '```',
190
+ '',
191
+ '3. Append the contents of `CLAUDE.md` to your `~/.claude/CLAUDE.md`:',
192
+ '',
193
+ '```bash',
194
+ 'cat CLAUDE.md >> ~/.claude/CLAUDE.md',
195
+ '```',
196
+ '',
197
+ '## Included Tools',
198
+ '',
199
+ ];
200
+
201
+ for (const tool of tools) {
202
+ lines.push(`- **${tool.name}** (v${tool.version}) — ${tool.description}`);
203
+ }
204
+
205
+ lines.push('');
206
+ return lines.join('\n');
207
+ }
208
+
209
+ /**
210
+ * Check for missing dependencies and return warnings
211
+ */
212
+ function checkDependencies(tools: ToolManifest[]): string[] {
213
+ const warnings: string[] = [];
214
+ const toolNames = new Set(tools.map((t) => t.name));
215
+
216
+ for (const tool of tools) {
217
+ if (!tool.dependencies) continue;
218
+ for (const dep of tool.dependencies) {
219
+ if (!toolNames.has(dep)) {
220
+ warnings.push(
221
+ `Tool '${tool.name}' depends on '${dep}' which is not included in this pack`,
222
+ );
223
+ }
224
+ }
225
+ }
226
+
227
+ return warnings;
228
+ }
229
+
230
+ /**
231
+ * Build a zip pack for the given audience
232
+ */
233
+ export async function buildPack(options: PackOptions): Promise<PackResult> {
234
+ const { audience, outputDir } = options;
235
+
236
+ // Get filtered tools
237
+ const tools = getToolsForAudience(audience);
238
+
239
+ if (tools.length === 0) {
240
+ return {
241
+ success: false,
242
+ message: `No tools found for audience '${audience}'`,
243
+ };
244
+ }
245
+
246
+ // Check dependencies
247
+ const warnings = checkDependencies(tools);
248
+
249
+ // Build the zip
250
+ const filename = `droid-${audience}-pack.zip`;
251
+ const outputPath = join(outputDir, filename);
252
+
253
+ return new Promise((resolve) => {
254
+ const output = createWriteStream(outputPath);
255
+ const archive = archiver('zip', { zlib: { level: 9 } });
256
+
257
+ output.on('close', () => {
258
+ resolve({
259
+ success: true,
260
+ message: `Pack created: ${filename}`,
261
+ outputPath,
262
+ toolCount: tools.length,
263
+ warnings: warnings.length > 0 ? warnings : undefined,
264
+ });
265
+ });
266
+
267
+ archive.on('error', (err: Error) => {
268
+ resolve({
269
+ success: false,
270
+ message: `Failed to create pack: ${err.message}`,
271
+ });
272
+ });
273
+
274
+ archive.pipe(output);
275
+
276
+ // Add all tool artifacts
277
+ for (const tool of tools) {
278
+ const artifacts = collectToolArtifacts(tool);
279
+ for (const artifact of artifacts) {
280
+ const content = readFileSync(artifact.sourcePath, 'utf-8');
281
+ archive.append(content, { name: artifact.zipPath });
282
+ }
283
+ }
284
+
285
+ // Add generated CLAUDE.md
286
+ archive.append(generateClaudeMd(tools), { name: 'CLAUDE.md' });
287
+
288
+ // Add generated README.md
289
+ archive.append(generateReadme(audience, tools), { name: 'README.md' });
290
+
291
+ archive.finalize();
292
+ });
293
+ }
package/src/lib/types.ts CHANGED
@@ -219,12 +219,31 @@ export interface ToolIncludes {
219
219
  agents: string[];
220
220
  }
221
221
 
222
+ export enum ToolAudience {
223
+ All = 'all',
224
+ Engineering = 'engineering',
225
+ Product = 'product',
226
+ Design = 'design',
227
+ IntegrationDevelopers = 'integration-developers',
228
+ CustomerSupport = 'customer-support',
229
+ NetworkOperations = 'network-operations',
230
+ }
231
+
232
+ export interface ToolPrerequisite {
233
+ name: string;
234
+ description: string;
235
+ check: string;
236
+ install_hint: string;
237
+ }
238
+
222
239
  export interface ToolManifest {
223
240
  name: string;
224
241
  description: string;
225
242
  version: string;
226
243
  status?: SkillStatus;
244
+ audience?: ToolAudience[];
227
245
  includes: ToolIncludes;
228
246
  dependencies?: string[];
247
+ prerequisites?: ToolPrerequisite[];
229
248
  config_schema?: Record<string, ConfigOption>;
230
249
  }
@@ -2,6 +2,8 @@ name: brain
2
2
  description: "Your scratchpad (or brain) - a collaborative space for planning and research. Create docs with /brain plan, /brain research, or /brain review. Use @mentions for async discussion. Docs persist across sessions."
3
3
  version: 0.4.2
4
4
  status: beta
5
+ audience:
6
+ - all
5
7
 
6
8
  includes:
7
9
  skills:
@@ -2,6 +2,10 @@ name: coach
2
2
  description: "Learning-mode AI assistance - AI as coach, not crutch. Use /coach plan for co-authored planning, /coach scaffold for structure with hints, /coach review for Socratic questions."
3
3
  version: 0.3.0
4
4
  status: beta
5
+ audience:
6
+ - engineering
7
+ - product
8
+ - design
5
9
 
6
10
  includes:
7
11
  skills:
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "droid-code-review",
3
- "version": "0.2.4",
3
+ "version": "0.3.0",
4
4
  "description": "Comprehensive code review using specialized agents. Reviews PRs, staged changes, branches, or specific files with confidence scoring.",
5
5
  "author": {
6
6
  "name": "Orderful",
@@ -23,6 +23,7 @@
23
23
  "./agents/edi-standards-reviewer.md",
24
24
  "./agents/error-handling-reviewer.md",
25
25
  "./agents/test-coverage-analyzer.md",
26
- "./agents/type-reviewer.md"
26
+ "./agents/type-reviewer.md",
27
+ "./agents/codex-context-researcher.md"
27
28
  ]
28
29
  }
@@ -1,7 +1,9 @@
1
1
  name: code-review
2
2
  description: "Comprehensive code review using specialized agents. Reviews PRs, staged changes, branches, or specific files with confidence scoring."
3
- version: 0.2.4
3
+ version: 0.3.0
4
4
  status: alpha
5
+ audience:
6
+ - engineering
5
7
 
6
8
  includes:
7
9
  skills:
@@ -15,5 +17,6 @@ includes:
15
17
  - error-handling-reviewer
16
18
  - test-coverage-analyzer
17
19
  - type-reviewer
20
+ - codex-context-researcher
18
21
 
19
22
  dependencies: []
@@ -0,0 +1,99 @@
1
+ ---
2
+ name: codex-context-researcher
3
+ description: "Search codex for domain knowledge relevant to code changes. Enriches code review findings with organisational context from PRDs, tech designs, and architectural decisions."
4
+ tools:
5
+ - Read
6
+ - Grep
7
+ - Glob
8
+ - Bash
9
+ color: cyan
10
+ ---
11
+
12
+ You are a codex research agent that finds organisational domain knowledge relevant to a set of code changes. Your output enriches code review findings — you do NOT review code yourself.
13
+
14
+ ## Inputs
15
+
16
+ You will receive:
17
+
18
+ - A list of changed file paths
19
+ - A brief summary of the diff (module names, domain concepts)
20
+ - Optionally, custom instructions from the user
21
+
22
+ ## Procedure
23
+
24
+ ### Step 1: Check Codex Availability
25
+
26
+ Run: `droid config --get tools.codex`
27
+
28
+ Parse the output for `codex_repo`. If not set or the command fails, return:
29
+
30
+ ```json
31
+ {
32
+ "status": "not_configured",
33
+ "entries_searched": 0,
34
+ "entries_matched": 0,
35
+ "domain_context": "",
36
+ "sources": []
37
+ }
38
+ ```
39
+
40
+ ### Step 2: Read Index
41
+
42
+ Read `{codex_repo}/index.yaml` — this is the codex inventory. It lists every entry by category (projects, patterns, topics, domains, proposals) with names, titles, and aliases.
43
+
44
+ If the index doesn't exist or is empty, return `status: "not_configured"`.
45
+
46
+ ### Step 3: Extract Search Terms
47
+
48
+ From the changed file paths, extract terms to match against the index:
49
+
50
+ - **Module/service names** from paths (e.g., `transactionTemplate` from `src/modules/transactionTemplate/`)
51
+ - **Directory segments** that suggest feature areas (e.g., `billing`, `partnership`, `webhook`)
52
+
53
+ Do NOT hardcode domain concepts — let the index be the source of truth for what knowledge exists.
54
+
55
+ ### Step 4: Match Against Index
56
+
57
+ Match extracted terms against index entry names, titles, and aliases across all categories. Select up to **5** most relevant entries. Prioritise:
58
+
59
+ 1. Exact name/alias matches
60
+ 2. Partial matches on entry titles
61
+ 3. Related entries where extracted terms appear in the name or title
62
+
63
+ If no entries match, return `status: "no_relevant_entries"`.
64
+
65
+ ### Step 5: Read and Extract
66
+
67
+ For each matched entry, read the full content. Extract **only**:
68
+
69
+ - Key patterns and conventions
70
+ - Architectural decisions and their rationale
71
+ - Gotchas, constraints, and explicit rules
72
+ - Domain-specific validation requirements
73
+
74
+ **Skip** generic content, background sections, and anything not actionable for a code reviewer.
75
+
76
+ ### Step 6: Return Structured Output
77
+
78
+ Return a JSON block:
79
+
80
+ ```json
81
+ {
82
+ "status": "ok",
83
+ "entries_searched": 12,
84
+ "entries_matched": 3,
85
+ "domain_context": "Bullet points of reviewer-actionable domain knowledge (~300 words max)",
86
+ "sources": ["entry-name-1", "entry-name-2"]
87
+ }
88
+ ```
89
+
90
+ - `entries_searched`: total entries in index
91
+ - `entries_matched`: entries that matched search terms
92
+ - `domain_context`: concise, reviewer-actionable bullet points. Focus on what a reviewer should look for or verify. Max ~300 words
93
+ - `sources`: entry names used (for citation in the review report)
94
+
95
+ ## Important
96
+
97
+ - Do NOT review code. Your job is context retrieval only.
98
+ - Keep `domain_context` focused and actionable — reviewers will read this alongside their own findings.
99
+ - If codex isn't configured or has no relevant entries, return early with the appropriate status. Don't fabricate context.
@@ -15,6 +15,8 @@ Code-review has no configuration of its own. Optional integration with other too
15
15
 
16
16
  - **Brain skill** (optional): If installed, offers to save review results to a `/brain review` doc
17
17
  - Check with: `droid config --get tools.brain` to see if `brain_dir` is configured
18
+ - **Codex skill** (optional): If configured, enriches EDI findings with organisational domain knowledge
19
+ - Check with: `droid config --get tools.codex` to see if `codex_repo` is configured
18
20
 
19
21
  **Overrides:** This skill supports user-defined overrides. See `/droid` skill § Skill Overrides.
20
22
 
@@ -32,6 +34,7 @@ The `/code-review` command orchestrates multiple specialized agents in parallel:
32
34
  2. **test-coverage-analyzer** - Test completeness and edge cases
33
35
  3. **error-handling-reviewer** - Silent failures, missing error handling
34
36
  4. **type-reviewer** - TypeScript type design, interface contracts
37
+ 5. **codex-context-researcher** (optional) - Domain knowledge from codex for EDI enrichment
35
38
 
36
39
  Each agent returns issues with confidence scores (0-100). Issues below 80% confidence are filtered out to reduce noise.
37
40
 
@@ -117,14 +120,19 @@ For PR reviews, also fetch:
117
120
 
118
121
  ### Step 3: Parallel Agent Reviews
119
122
 
123
+ **Check codex availability** before launching agents:
124
+
125
+ Run `droid config --get tools.codex`. If `codex_repo` is configured, you will launch 5 agents. If not, launch the standard 4.
126
+
120
127
  Launch these agents in parallel using the Task tool with `run_in_background: true`:
121
128
 
122
129
  1. **edi-standards-reviewer**: EDI patterns, partnership handling, billing concerns
123
130
  2. **test-coverage-analyzer**: Test completeness and edge cases
124
131
  3. **error-handling-reviewer**: Silent failures, missing error handling
125
132
  4. **type-reviewer**: Type design, interface contracts
133
+ 5. **codex-context-researcher** (only if codex is configured): Pass changed file paths and a brief summary of the diff (module names, domain concepts extracted from paths and PR description). Do NOT pass full diff content — this agent reads codex, not code.
126
134
 
127
- Pass each agent:
135
+ Pass agents 1–4:
128
136
 
129
137
  1. The diff content
130
138
  2. The full file content for changed files (for context)
@@ -139,6 +147,17 @@ Filter out issues with confidence < 80.
139
147
 
140
148
  ### Step 5: Synthesize Report
141
149
 
150
+ **Codex enrichment** (if codex-context-researcher returned `status: "ok"` with non-empty `domain_context`):
151
+
152
+ Before compiling the EDI findings, prefix the EDI section with a "Domain Context" block:
153
+
154
+ > **Domain context** (from codex: entry-name-1, entry-name-2)
155
+ > - Bullet points from the researcher's domain_context
156
+
157
+ Use this context to strengthen or re-prioritise EDI findings. For example, if codex says "partnership billing events must always include account_id" and the EDI reviewer flagged a missing field, elevate that finding's priority.
158
+
159
+ If codex returned `status: "not_configured"` or `"no_relevant_entries"`, omit the domain context block silently.
160
+
142
161
  Compile findings into a prioritized report:
143
162
 
144
163
  **PR #123: "Add partnership billing events"** (if reviewing a PR)
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "droid-codex",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "Shared organizational knowledge - PRDs, tech designs, domains, proposals, patterns, and explored topics. Self-describing: structure and workflows defined in codex repo. Use when loading project context, searching codex, capturing decisions, or creating new entries.",
5
5
  "author": {
6
6
  "name": "Orderful",
@@ -1,7 +1,9 @@
1
1
  name: codex
2
2
  description: "Shared organizational knowledge - PRDs, tech designs, domains, proposals, patterns, and explored topics. Self-describing: structure and workflows defined in codex repo. Use when loading project context, searching codex, capturing decisions, or creating new entries."
3
- version: 0.3.1
3
+ version: 0.4.0
4
4
  status: beta
5
+ audience:
6
+ - all
5
7
 
6
8
  includes:
7
9
  skills:
@@ -145,6 +145,7 @@ The codex skill includes three git scripts. **Always use these instead of raw gi
145
145
  |--------|---------|-------------|
146
146
  | git-preamble | Ensure clean main + pull latest | Before ANY operation |
147
147
  | git-start-write | Preamble + create branch | Before write operations |
148
+ | normalize-frontmatter | Normalize YAML frontmatter format | After writing, before commit |
148
149
  | git-finish-write | Commit + PR + return to main | After write operations |
149
150
 
150
151
  ### Read Operations
@@ -159,7 +160,10 @@ The codex skill includes three git scripts. **Always use these instead of raw gi
159
160
 
160
161
  # 2. Make your changes (write files)
161
162
 
162
- # 3. Finish write (commit + PR + return to main)
163
+ # 3. Normalize frontmatter (prevents fix-frontmatter PRs)
164
+ droid config --get tools.codex | droid exec codex normalize-frontmatter --config -
165
+
166
+ # 4. Finish write (commit + PR + return to main)
163
167
  droid config --get tools.codex | droid exec codex git-finish-write --config - \
164
168
  --message "{commit message}" \
165
169
  --pr-title "{PR title}" \