devlyn-cli 4.0.0 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -28,23 +28,42 @@ Every phase applies Subtractive-first / Goal-locked / No-workaround / Evidence,
28
28
  </harness_principles>
29
29
 
30
30
  <runtime_paths>
31
- Resolve shared scripts from this skill's installed directory, never from the project cwd. At PHASE 0, before any phase command:
32
-
33
- ```bash
34
- DEVLYN_SKILL_DIR="${CLAUDE_SKILL_DIR:-__DEVLYN_SKILL_DIR__}"
35
- if [ "$DEVLYN_SKILL_DIR" = "__DEVLYN_SKILL_DIR__" ] || [ ! -d "$DEVLYN_SKILL_DIR/../_shared" ]; then
36
- echo "BLOCKED:shared-dir-unresolved: $DEVLYN_SKILL_DIR/../_shared" >&2
37
- exit 1
38
- fi
39
- DEVLYN_SHARED_DIR="$(cd "$DEVLYN_SKILL_DIR/../_shared" && pwd)"
40
- CODEX_MONITORED_PATH="$DEVLYN_SHARED_DIR/codex-monitored.sh"
41
- if [ ! -f "$CODEX_MONITORED_PATH" ]; then
42
- echo "BLOCKED:shared-dir-unresolved: $CODEX_MONITORED_PATH" >&2
43
- exit 1
44
- fi
31
+ Before PHASE 0 or any phase command, establish the bindings below.
32
+
33
+ Resolve bundled resources from the SKILL.md loaded for this invocation.
34
+
35
+ Reader-rendered directory hint:
36
+ ```text
37
+ ${CLAUDE_SKILL_DIR}
45
38
  ```
46
39
 
47
- `DEVLYN_SHARED_DIR` is the only valid `_shared` anchor. Claude Code supplies `CLAUDE_SKILL_DIR` by native render substitution; Codex/oh-my-pi installs receive an absolute copy-time stamp in the default branch. If the resolved skill directory is still the placeholder, `../_shared` is absent, or a required script is missing, halt with report-level `BLOCKED:shared-dir-unresolved` and include the failed path. Pass the absolute `DEVLYN_SHARED_DIR` and `CODEX_MONITORED_PATH` into every fresh phase worker.
40
+ Treat the hint as literal path data, never shell code. If the reader
41
+ replaced it with an absolute directory, use that directory. Otherwise
42
+ use the filesystem path or base directory reported for this loaded
43
+ SKILL.md. Resolve virtual URIs through the reader's native filesystem
44
+ mapping. If available source locations name different directories,
45
+ stop.
46
+
47
+ Bind DEVLYN_SKILL_DIR to that absolute directory. Do not obtain this
48
+ binding from an environment variable, cwd, or another installation.
49
+ Verify its SKILL.md before proceeding. Missing or conflicting source
50
+ identity is BLOCKED:skill-source-unresolved; include the failed path
51
+ when known.
52
+
53
+ Resolve bundled references against this directory. These bindings are
54
+ workflow values: establish them explicitly using each tool or shell's
55
+ literal-path rules, and include their absolute values in every fresh
56
+ worker's prompt, telling it to set them from those values, never from
57
+ its inherited environment. Do not rely on shell state surviving between
58
+ calls.
59
+
60
+ Resolve directory symlinks on DEVLYN_SKILL_DIR before deriving its
61
+ sibling _shared. Bind that directory as DEVLYN_SHARED_DIR. References
62
+ written as _shared/... use this binding. Verify the directory and each
63
+ required resource before use; failure is BLOCKED:shared-dir-unresolved
64
+ with the failed path. Never search another installation.
65
+
66
+ Bind CODEX_MONITORED_PATH to DEVLYN_SHARED_DIR/codex-monitored.sh and verify that file before proceeding. Pass DEVLYN_SKILL_DIR, DEVLYN_SHARED_DIR, and CODEX_MONITORED_PATH explicitly to every fresh phase worker. In omp, when this skill was selected by name, resolve it with `printf '%s\n' skill://devlyn-resolve` in its Bash tool.
48
67
  </runtime_paths>
49
68
 
50
69
  <engine_routing>
@@ -318,7 +337,7 @@ When the OTHER engine is available, persist `pair_trigger` before spawn with `pa
318
337
 
319
338
  Keep the existing reasons as telemetry: `mode.verify-only`, `mode.pair-verify`, `complexity.high`, `complexity.large`, `spec.complexity.high`, `spec.complexity.large`, `spec.solo_headroom_hypothesis`, `risk.high`, `risk_probes.enabled`, `risk_probes.present`, `coverage.failed`, `mechanical.warning`, and `judge.warning`. Append the outcome-dependent reasons only after both judges return. Eligible schema-v3 state must include `pair.default`; all other applicable reasons remain completeness-checked. Malformed risk or trigger state BLOCKs VERIFY.
320
339
 
321
- Pair-mode JUDGE: spawn a second Agent with the OTHER engine's adapter; the second judge is a bounded adversarial complement, not a duplicate broad audit. The primary judge owns broad coverage; pair-JUDGE reviews the two highest-risk explicit `## Verification` bullets that cross state mutation, all-or-nothing rollback, ordering, idempotency, auth, or error-priority clauses. It must not read `.claude/skills`, `.codex/skills`, `CLAUDE.md`, `AGENTS.md`, or other harness docs unless the orchestrator pasted a specific excerpt into the prompt. It may use only the spec, diff, implementation files, tests, and sealed MECHANICAL evidence. It performs at most two targeted reviews before first output; inspection remains read-only. When the spec names exact keys, row shapes, JSON object shape, or an exact error body, pair-JUDGE compares the sealed parsed key sets/deep equality so aliased keys, missing keys, and extra keys are verdict-binding failures. For priority/stateful specs, trace code order for an earlier input entity that would succeed under input-order processing, a later higher-priority entity that consumes or blocks the critical resource, and a failure/blocked/rollback edge that determines a later entity's state. Scope qualifiers are binding: pair-JUDGE must not reinterpret `inside a warehouse`, `per resource`, or line-scoped rules as global rules. When both priority ordering and rollback/blocked-interval behavior appear in the spec, this dominance-loss review comes first: trace whether the earlier lower-priority entity loses because the later higher-priority entity is processed first, whether a failed/blocked middle entity leaves later state intact, and whether the sealed evidence covers complete accepted/scheduled and rejected output ordering. Missing executable coverage is a verdict-binding coverage finding; JUDGE does not invent or run the missing scenario. Pair-JUDGE output: emit JSONL findings then a bare terminal verdict line, or emit only `PASS` when clean. `_shared/judge-output-parser.py` is the single acceptance rule for pair output: JSONL findings, then a `# SUMMARY {json}` line or a bare verdict line (`PASS` alone when clean); it ignores bare code-fence lines and unwraps the registered Codex JSON envelope including its narrated-preamble recovery (iter-0082), and binds a whole-message NDJSON capture only through its uniquely attested terminal `end_turn` assistant message (iter-0106); every other non-empty line blocks the pair source. Both judgments merge with the rule "any HIGH/CRITICAL finding is verdict-binding; any MEDIUM with literal `verdict_binding: true` is also binding, regardless of confidence." Demonstrated applicable mandatory-clause violations, including unmet new requirements and incorrect customer documentation, must use one of those binding forms. Apply the canonical VERIFY clause/evidence and advisory boundaries; impact, rarity or pre-existing origin alone does not excuse an applicable violation. Cross-model disagreement on advisory lower-severity findings is logged but does not change the verdict. A primary JUDGE verdict-binding finding on a concurrent run does not cancel or discard the pair-JUDGE; both finding sets join the same fix round, and the merged verdict remains the worst source verdict without vote counting. `primary_judge_blocker` is parser-recognized only for archived v2.0 replay; new runs never write it. A verdict-binding MECHANICAL blocker still skips both judges and records `pair_judge: null`.
340
+ Pair-mode JUDGE: spawn a second Agent with the OTHER engine's adapter; the second judge is a bounded adversarial complement, not a duplicate broad audit. The primary judge owns broad coverage; pair-JUDGE reviews the two highest-risk explicit `## Verification` bullets that cross state mutation, all-or-nothing rollback, ordering, idempotency, auth, or error-priority clauses. It must not read `.claude/skills`, `.codex/skills`, `.agents/skills`, `CLAUDE.md`, `AGENTS.md`, or other harness docs unless the orchestrator pasted a specific excerpt into the prompt. It may use only the spec, diff, implementation files, tests, and sealed MECHANICAL evidence. It performs at most two targeted reviews before first output; inspection remains read-only. When the spec names exact keys, row shapes, JSON object shape, or an exact error body, pair-JUDGE compares the sealed parsed key sets/deep equality so aliased keys, missing keys, and extra keys are verdict-binding failures. For priority/stateful specs, trace code order for an earlier input entity that would succeed under input-order processing, a later higher-priority entity that consumes or blocks the critical resource, and a failure/blocked/rollback edge that determines a later entity's state. Scope qualifiers are binding: pair-JUDGE must not reinterpret `inside a warehouse`, `per resource`, or line-scoped rules as global rules. When both priority ordering and rollback/blocked-interval behavior appear in the spec, this dominance-loss review comes first: trace whether the earlier lower-priority entity loses because the later higher-priority entity is processed first, whether a failed/blocked middle entity leaves later state intact, and whether the sealed evidence covers complete accepted/scheduled and rejected output ordering. Missing executable coverage is a verdict-binding coverage finding; JUDGE does not invent or run the missing scenario. Pair-JUDGE output: emit JSONL findings then a bare terminal verdict line, or emit only `PASS` when clean. `_shared/judge-output-parser.py` is the single acceptance rule for pair output: JSONL findings, then a `# SUMMARY {json}` line or a bare verdict line (`PASS` alone when clean); it ignores bare code-fence lines and unwraps the registered Codex JSON envelope including its narrated-preamble recovery (iter-0082), and binds a whole-message NDJSON capture only through its uniquely attested terminal `end_turn` assistant message (iter-0106); every other non-empty line blocks the pair source. Both judgments merge with the rule "any HIGH/CRITICAL finding is verdict-binding; any MEDIUM with literal `verdict_binding: true` is also binding, regardless of confidence." Demonstrated applicable mandatory-clause violations, including unmet new requirements and incorrect customer documentation, must use one of those binding forms. Apply the canonical VERIFY clause/evidence and advisory boundaries; impact, rarity or pre-existing origin alone does not excuse an applicable violation. Cross-model disagreement on advisory lower-severity findings is logged but does not change the verdict. A primary JUDGE verdict-binding finding on a concurrent run does not cancel or discard the pair-JUDGE; both finding sets join the same fix round, and the merged verdict remains the worst source verdict without vote counting. `primary_judge_blocker` is parser-recognized only for archived v2.0 replay; new runs never write it. A verdict-binding MECHANICAL blocker still skips both judges and records `pair_judge: null`.
322
341
 
323
342
  If the OTHER engine is unavailable, only unconfigured automatic VERIFY records
324
343
  `auto_pair_other_engine_unavailable` and continues solo. Explicit `--pair-verify`,
@@ -24,7 +24,7 @@ second planner, critic essay, or debate participant. Your output is JSONL only.
24
24
  <forbidden_input>
25
25
  Do not read `spec.expected.json`, `.devlyn/spec-verify.json`,
26
26
  `BENCH_FIXTURE_DIR`, benchmark fixture/verifier paths, `.devlyn/*.findings.jsonl`,
27
- `.claude/skills`, `.codex/skills`, `CLAUDE.md`, `AGENTS.md`, or other harness
27
+ `.claude/skills`, `.codex/skills`, `.agents/skills`, `CLAUDE.md`, `AGENTS.md`, or other harness
28
28
  docs unless the orchestrator pasted a specific excerpt into the prompt.
29
29
  </forbidden_input>
30
30
 
@@ -187,7 +187,7 @@ When eligible and the orchestrator spawns a second VERIFY agent with the OTHER e
187
187
  state mutation, all-or-nothing rollback, ordering, idempotency, auth, or
188
188
  error-priority clauses. The primary judge owns broad coverage; the pair judge
189
189
  is a bounded adversarial complement. Do not read `.claude/skills`,
190
- `.codex/skills`, `CLAUDE.md`, `AGENTS.md`, or other harness docs unless the
190
+ `.codex/skills`, `.agents/skills`, `CLAUDE.md`, `AGENTS.md`, or other harness docs unless the
191
191
  orchestrator pasted a specific excerpt into the prompt. Use only the spec,
192
192
  diff, implementation files, tests, and sealed MECHANICAL evidence. Complete at
193
193
  most two targeted reviews before first output; inspection remains read-only.
@@ -7,8 +7,15 @@ authorized by the task scope; no additional approval ceremony is required.
7
7
 
8
8
  ## Allocate before work
9
9
 
10
- Use the installed `_shared/task-complete.py` from the anchor checkout,
11
- before committing owner inputs or starting direct/full work:
10
+ Use the caller's DEVLYN_SHARED_DIR. When this reference is opened
11
+ directly, derive that binding from ../../_shared relative to this
12
+ reference's reader-supplied containing directory, resolving directory
13
+ symlinks first. Missing source identity is
14
+ BLOCKED:skill-source-unresolved; a missing task-complete.py is
15
+ BLOCKED:shared-dir-unresolved. Never select another installation.
16
+
17
+ Run the bound task-complete.py before committing owner inputs or
18
+ starting direct/full work:
12
19
 
13
20
  ```sh
14
21
  python3 "$DEVLYN_SHARED_DIR/task-complete.py" allocate --repo . \
@@ -30,13 +30,19 @@ The setup produces a dual-auth system: session cookies for browser users and API
30
30
 
31
31
  Read these when each step directs you to them:
32
32
 
33
- - `${CLAUDE_SKILL_DIR}/references/schema.md` — Complete Drizzle schema (auth, org, API key tables)
34
- - `${CLAUDE_SKILL_DIR}/references/middleware.md` — Auth middleware, tenant context, types, error handler
35
- - `${CLAUDE_SKILL_DIR}/references/api-keys.md` — Key generation, CRUD routes, security patterns
36
- - `${CLAUDE_SKILL_DIR}/references/config-and-entry.md` — Env config, error types, entry point wiring
37
- - `${CLAUDE_SKILL_DIR}/references/testing.md` — Test preload, seed factory, integration patterns
38
- - `${CLAUDE_SKILL_DIR}/references/proxy-setup.md` — Reverse proxy architecture, forwarding headers, OAuth callback routing
39
- - `${CLAUDE_SKILL_DIR}/references/proxy-gotchas.md` — Proxy-specific troubleshooting (redirect_uri_mismatch, state_mismatch, cookie prefix issues)
33
+ Resolve the bundled references/... paths below against the directory
34
+ containing the SKILL.md loaded for this invocation, using its opened
35
+ path, reader-reported base directory, or native URI mapping. Never
36
+ resolve them against cwd or another installation. Missing source
37
+ identity is BLOCKED:skill-source-unresolved.
38
+
39
+ - `references/schema.md` — Complete Drizzle schema (auth, org, API key tables)
40
+ - `references/middleware.md` — Auth middleware, tenant context, types, error handler
41
+ - `references/api-keys.md` — Key generation, CRUD routes, security patterns
42
+ - `references/config-and-entry.md` — Env config, error types, entry point wiring
43
+ - `references/testing.md` — Test preload, seed factory, integration patterns
44
+ - `references/proxy-setup.md` — Reverse proxy architecture, forwarding headers, OAuth callback routing
45
+ - `references/proxy-gotchas.md` — Proxy-specific troubleshooting (redirect_uri_mismatch, state_mismatch, cookie prefix issues)
40
46
 
41
47
  ## Handling Input
42
48
 
@@ -86,7 +92,7 @@ Generate the auth secret immediately (do not use a placeholder):
86
92
  bunx @better-auth/cli@latest secret
87
93
  ```
88
94
 
89
- Read `${CLAUDE_SKILL_DIR}/references/config-and-entry.md` for the complete Zod config implementation. Key env vars:
95
+ Read `references/config-and-entry.md` for the complete Zod config implementation. Key env vars:
90
96
 
91
97
  | Variable | Required | Purpose |
92
98
  |----------|----------|---------|
@@ -104,7 +110,7 @@ Read `${CLAUDE_SKILL_DIR}/references/config-and-entry.md` for the complete Zod c
104
110
  **Entry:** Config validated at startup.
105
111
  **Exit:** Migration applied, tables created in PostgreSQL.
106
112
 
107
- Read `${CLAUDE_SKILL_DIR}/references/schema.md` for the complete schema. Key decisions:
113
+ Read `references/schema.md` for the complete schema. Key decisions:
108
114
 
109
115
  - Use **plural table names** (`users`, `sessions`) — mapped to Better Auth's singular models in Step 3
110
116
  - Use **UUIDs** for all primary keys
@@ -284,7 +290,7 @@ authRoutes.on(["POST", "GET"], "/*", (c) => auth.handler(c.req.raw));
284
290
  **Entry:** Auth routes mounted.
285
291
  **Exit:** `src/middleware/auth.ts` validates API keys and session cookies.
286
292
 
287
- Read `${CLAUDE_SKILL_DIR}/references/middleware.md` for the complete implementation. The middleware:
293
+ Read `references/middleware.md` for the complete implementation. The middleware:
288
294
  - Detects API keys via `Authorization: Bearer pyx_...` prefix
289
295
  - Validates via SHA-256 hash lookup + revocation + expiration checks
290
296
  - Falls back to Better Auth session cookie validation
@@ -299,7 +305,7 @@ Read `${CLAUDE_SKILL_DIR}/references/middleware.md` for the complete implementat
299
305
  **Entry:** Auth middleware populates `AuthContext` on the request.
300
306
  **Exit:** `src/middleware/tenant-context.ts` resolves org and plan.
301
307
 
302
- Read `${CLAUDE_SKILL_DIR}/references/middleware.md` for the implementation. Key behaviors:
308
+ Read `references/middleware.md` for the implementation. Key behaviors:
303
309
  - API key auth: org already resolved from the key's project, just fetches plan
304
310
  - Session auth: looks up user's most recent org membership
305
311
  - Uses distinct error code `no_organization` (not generic `forbidden`) so the frontend can show "Create your first organization" instead of "Access denied"
@@ -311,7 +317,7 @@ Read `${CLAUDE_SKILL_DIR}/references/middleware.md` for the implementation. Key
311
317
  **Entry:** Middleware needs error classes to throw.
312
318
  **Exit:** `src/lib/errors.ts` with `AppError` hierarchy, `src/middleware/error-handler.ts`.
313
319
 
314
- Read `${CLAUDE_SKILL_DIR}/references/config-and-entry.md` for the complete error hierarchy and handler. Every error has a distinct `code` field for frontend differentiation:
320
+ Read `references/config-and-entry.md` for the complete error hierarchy and handler. Every error has a distinct `code` field for frontend differentiation:
315
321
 
316
322
  | Error Class | Code | Status |
317
323
  |-------------|------|--------|
@@ -328,7 +334,7 @@ Read `${CLAUDE_SKILL_DIR}/references/config-and-entry.md` for the complete error
328
334
  **Entry:** All middleware and routes implemented.
329
335
  **Exit:** `src/index.ts` with correct middleware ordering.
330
336
 
331
- Read `${CLAUDE_SKILL_DIR}/references/config-and-entry.md` for the complete entry point. The middleware order is:
337
+ Read `references/config-and-entry.md` for the complete entry point. The middleware order is:
332
338
 
333
339
  1. **Request ID** — first, so error handler can include it in responses
334
340
  2. **Security Headers** — HSTS (production), X-Frame-Options
@@ -348,7 +354,7 @@ CORS before auth routes is non-negotiable. If registered after, preflight OPTION
348
354
  **Entry:** Application fully functional.
349
355
  **Exit:** Test preload, seed factory, integration app, cleanup utilities.
350
356
 
351
- Read `${CLAUDE_SKILL_DIR}/references/testing.md` for the complete test setup. Essential components:
357
+ Read `references/testing.md` for the complete test setup. Essential components:
352
358
 
353
359
  1. **Test preload** (`bunfig.toml` + `setup.ts`) — clears `RESEND_API_KEY`, bridges `TEST_DATABASE_URL`
354
360
  2. **Seed factory** (`seedTestData()`) — creates full tenant hierarchy with unique slugs
@@ -413,7 +419,7 @@ If any item fails, fix the root cause before proceeding.
413
419
 
414
420
  ## API Key System
415
421
 
416
- For the complete custom API key implementation (generation, validation, CRUD routes), read `${CLAUDE_SKILL_DIR}/references/api-keys.md`.
422
+ For the complete custom API key implementation (generation, validation, CRUD routes), read `references/api-keys.md`.
417
423
 
418
424
  Summary:
419
425
  - **Format**: `pyx_` prefix + 32 random bytes base62-encoded (~50 chars)
@@ -447,7 +453,7 @@ Always append a unique suffix (UUID slice or timestamp) to prevent collisions.
447
453
 
448
454
  ## Proxy Architecture (Steps 12-14)
449
455
 
450
- These steps apply when the frontend is a separate application that proxies auth requests to the backend. Read `${CLAUDE_SKILL_DIR}/references/proxy-setup.md` for the complete guide with code examples.
456
+ These steps apply when the frontend is a separate application that proxies auth requests to the backend. Read `references/proxy-setup.md` for the complete guide with code examples.
451
457
 
452
458
  ### Step 12: Configure Dynamic baseURL on Backend
453
459
 
@@ -499,7 +505,7 @@ socialProviders: {
499
505
  **Entry:** Backend uses `allowedHosts` with `trustedProxyHeaders`.
500
506
  **Exit:** Frontend proxies auth requests and OAuth callbacks correctly.
501
507
 
502
- The frontend proxy must do three things. Read `${CLAUDE_SKILL_DIR}/references/proxy-setup.md` for complete code.
508
+ The frontend proxy must do three things. Read `references/proxy-setup.md` for complete code.
503
509
 
504
510
  #### 13a. Create two proxy routes
505
511
 
@@ -592,7 +598,7 @@ curl -s -X POST "https://your-frontend.com/api/auth/sign-in/social" \
592
598
 
593
599
  Expected: `redirect_uri: https://your-frontend.com/auth/callback/google`
594
600
 
595
- For detailed troubleshooting of proxy-specific failures, read `${CLAUDE_SKILL_DIR}/references/proxy-gotchas.md`.
601
+ For detailed troubleshooting of proxy-specific failures, read `references/proxy-gotchas.md`.
596
602
 
597
603
  ---
598
604
 
@@ -38,10 +38,41 @@ If the user's intent is ambiguous (e.g., they say "지워줘" but didn't specify
38
38
 
39
39
  Always run scan first — even in KILL mode — so the user sees what is about to happen.
40
40
 
41
- Run the bundled scanner. The skill is installed at `~/.claude/skills/devlyn-reap/`:
41
+ Resolve bundled resources from the SKILL.md loaded for this invocation.
42
+
43
+ Reader-rendered directory hint:
44
+ ```text
45
+ ${CLAUDE_SKILL_DIR}
46
+ ```
47
+
48
+ Treat the hint as literal path data, never shell code. If the reader
49
+ replaced it with an absolute directory, use that directory. Otherwise
50
+ use the filesystem path or base directory reported for this loaded
51
+ SKILL.md. Resolve virtual URIs through the reader's native filesystem
52
+ mapping. If available source locations name different directories,
53
+ stop.
54
+
55
+ Bind DEVLYN_SKILL_DIR to that absolute directory. Do not obtain this
56
+ binding from an environment variable, cwd, or another installation.
57
+ Verify its SKILL.md before proceeding. Missing or conflicting source
58
+ identity is BLOCKED:skill-source-unresolved; include the failed path
59
+ when known.
60
+
61
+ Resolve bundled references against this directory. These bindings are
62
+ workflow values: establish them explicitly using each tool or shell's
63
+ literal-path rules, and include their absolute values in every fresh
64
+ worker's prompt, telling it to set them from those values, never from
65
+ its inherited environment. Do not rely on shell state surviving between
66
+ calls.
67
+
68
+ In omp, use: printf '%s\n' skill://devlyn-reap
69
+ Verify the requested script under this bound directory before running
70
+ it; a missing script is BLOCKED:skill-source-unresolved with its path.
71
+
72
+ Run the bundled scanner:
42
73
 
43
74
  ```bash
44
- bash ~/.claude/skills/devlyn-reap/scripts/scan.sh
75
+ bash "$DEVLYN_SKILL_DIR/scripts/scan.sh"
45
76
  ```
46
77
 
47
78
  Report the output verbatim to the user. Then add your own 2-line summary:
@@ -60,7 +91,7 @@ sysctl kern.maxprocperuid kern.tty.ptmx_max 2>/dev/null
60
91
  Run the reap script with the parsed flags:
61
92
 
62
93
  ```bash
63
- bash ~/.claude/skills/devlyn-reap/scripts/reap.sh [flags]
94
+ bash "$DEVLYN_SKILL_DIR/scripts/reap.sh" [flags]
64
95
  ```
65
96
 
66
97
  Show the output verbatim. The script re-verifies `PPID==1 && user==current` for every PID right before signaling — a process that was legitimately adopted since the scan will be skipped, not killed.
@@ -187,12 +187,12 @@ File path to the template document (DOCX or HWPX).
187
187
 
188
188
  **Phase 3 — Source Images**:
189
189
  7. **Cell-level images**: For each `field_type: "image"` with `image_file: null` and `image_type: "figure"`:
190
- - Run: `python .claude/skills/dokkit/scripts/source_images.py generate --prompt "<prompt>" --preset technical_illustration --output-dir .dokkit/images/ --project-dir . --lang ko`
190
+ - Run: `python "$DEVLYN_SKILL_DIR/scripts/source_images.py" generate --prompt "<prompt>" --preset technical_illustration --output-dir .dokkit/images/ --project-dir . --lang ko`
191
191
  - Parse `__RESULT__` JSON, update `analysis.json`
192
192
  - Skip photo/signature types (require user-provided files)
193
193
  - Default `--lang ko` (Korean only). Override with user instruction if needed.
194
194
  8. **Section content images**: For each `image_opportunities` entry with `status: "pending"`:
195
- - Run: `python .claude/skills/dokkit/scripts/source_images.py generate --prompt "<generation_prompt>" --preset <preset> --output-dir .dokkit/images/ --project-dir . --lang ko`
195
+ - Run: `python "$DEVLYN_SKILL_DIR/scripts/source_images.py" generate --prompt "<generation_prompt>" --preset <preset> --output-dir .dokkit/images/ --project-dir . --lang ko`
196
196
  - On failure: set `status: "skipped"`, log reason
197
197
  - Use `--lang ko+en` if the content contains technical terms that benefit from English (e.g., architecture diagrams with API names).
198
198
  9. Report: "Sourced X/Y images"
@@ -272,8 +272,8 @@ File path to the template document (DOCX or HWPX).
272
272
  > "Analyze the template at `<path>`. Detect all fillable fields INCLUDING image fields. Map to sources. Write `analysis.json`."
273
273
 
274
274
  **Image sourcing** (inline, between agents):
275
- - **Pass A — Cell-level**: For `field_type: "image"` with `image_file: null` and `image_type: "figure"`, run `python .claude/skills/dokkit/scripts/source_images.py generate --prompt "..." --preset ... --output-dir .dokkit/images/ --project-dir . --lang ko`
276
- - **Pass B — Section content**: For `image_opportunities` with `status: "pending"`, run `python .claude/skills/dokkit/scripts/source_images.py generate --prompt "..." --preset ... --output-dir .dokkit/images/ --project-dir . --lang ko`
275
+ - **Pass A — Cell-level**: For `field_type: "image"` with `image_file: null` and `image_type: "figure"`, run `python "$DEVLYN_SKILL_DIR/scripts/source_images.py" generate --prompt "..." --preset ... --output-dir .dokkit/images/ --project-dir . --lang ko`
276
+ - **Pass B — Section content**: For `image_opportunities` with `status: "pending"`, run `python "$DEVLYN_SKILL_DIR/scripts/source_images.py" generate --prompt "..." --preset ... --output-dir .dokkit/images/ --project-dir . --lang ko`
277
277
  - Default language is `ko` (Korean only). Use `--lang ko+en` for mixed content, or `--lang en` for English-only.
278
278
 
279
279
  **Then**: Spawn the dokkit-filler agent in fill mode:
@@ -41,8 +41,8 @@ def compile_hwpx(work_dir: str, output_path: str):
41
41
 
42
42
  ### Scripts
43
43
  ```bash
44
- python .claude/skills/dokkit/scripts/compile_hwpx.py <work_dir> <output.hwpx>
45
- python .claude/skills/dokkit/scripts/export_pdf.py <input> <output.pdf>
44
+ python "$DEVLYN_SKILL_DIR/scripts/compile_hwpx.py" <work_dir> <output.hwpx>
45
+ python "$DEVLYN_SKILL_DIR/scripts/export_pdf.py" <input> <output.pdf>
46
46
  ```
47
47
 
48
48
  ## PDF Conversion
@@ -54,7 +54,7 @@ soffice --headless --convert-to pdf --outdir <output_dir> <input_file>
54
54
 
55
55
  ### Using Python Script
56
56
  ```bash
57
- python .claude/skills/dokkit/scripts/export_pdf.py <input> <output.pdf>
57
+ python "$DEVLYN_SKILL_DIR/scripts/export_pdf.py" <input> <output.pdf>
58
58
  ```
59
59
 
60
60
  ## Cross-Format Conversion
@@ -15,24 +15,24 @@ Field detection, matching strategies, and surgical XML editing rules for the dok
15
15
 
16
16
  ### DOCX Field Detection
17
17
  ```bash
18
- python .claude/skills/dokkit/scripts/detect_fields.py <document.xml>
18
+ python "$DEVLYN_SKILL_DIR/scripts/detect_fields.py" <document.xml>
19
19
  ```
20
20
  Outputs JSON array of detected fields with labels, types, and XML paths.
21
21
 
22
22
  ### HWPX Field Detection
23
23
  ```bash
24
- python .claude/skills/dokkit/scripts/detect_fields_hwpx.py <section.xml>
24
+ python "$DEVLYN_SKILL_DIR/scripts/detect_fields_hwpx.py" <section.xml>
25
25
  ```
26
26
  Same output format, adapted for HWPX XML structure.
27
27
 
28
28
  ### DOCX Validation
29
29
  ```bash
30
- python .claude/skills/dokkit/scripts/validate_docx.py <work_dir>
30
+ python "$DEVLYN_SKILL_DIR/scripts/validate_docx.py" <work_dir>
31
31
  ```
32
32
 
33
33
  ### HWPX Validation
34
34
  ```bash
35
- python .claude/skills/dokkit/scripts/validate_hwpx.py <work_dir>
35
+ python "$DEVLYN_SKILL_DIR/scripts/validate_hwpx.py" <work_dir>
36
36
  ```
37
37
 
38
38
  ## Matching Strategy
@@ -25,7 +25,7 @@ Via `/dokkit modify "use <file>"`:
25
25
 
26
26
  ### 3. AI Generation
27
27
  ```bash
28
- python .claude/skills/dokkit/scripts/source_images.py generate \
28
+ python "$DEVLYN_SKILL_DIR/scripts/source_images.py" generate \
29
29
  --prompt "인포그래픽: AI 감정 케어 플랫폼 4단계 로드맵" \
30
30
  --preset infographic \
31
31
  --output-dir .dokkit/images/ \
@@ -61,7 +61,7 @@ Use `--aspect-ratio 16:9` to override. Use `--no-enhance` to skip preset style i
61
61
 
62
62
  ### 4. Web Search
63
63
  ```bash
64
- python .claude/skills/dokkit/scripts/source_images.py search \
64
+ python "$DEVLYN_SKILL_DIR/scripts/source_images.py" search \
65
65
  --query "company logo example" \
66
66
  --output-dir .dokkit/images/
67
67
  ```
@@ -12,11 +12,11 @@ Parsing strategies and format routing for converting source documents into the d
12
12
  | HTML | Docling | `python -m docling <file> --to md` |
13
13
  | CSV | Docling | `python -m docling <file> --to md` |
14
14
  | MD | Direct copy | Read and process as-is |
15
- | XLSX | Custom | `python .claude/skills/dokkit/scripts/parse_xlsx.py` |
16
- | HWPX | Custom | `python .claude/skills/dokkit/scripts/parse_hwpx.py` |
15
+ | XLSX | Custom | `python "$DEVLYN_SKILL_DIR/scripts/parse_xlsx.py"` |
16
+ | HWPX | Custom | `python "$DEVLYN_SKILL_DIR/scripts/parse_hwpx.py"` |
17
17
  | JSON | Custom | Read, format as structured markdown |
18
18
  | TXT | Custom | Read, wrap as markdown |
19
- | PNG/JPG | Gemini Vision | `python .claude/skills/dokkit/scripts/parse_image_with_gemini.py` |
19
+ | PNG/JPG | Gemini Vision | `python "$DEVLYN_SKILL_DIR/scripts/parse_image_with_gemini.py"` |
20
20
 
21
21
  ## Docling Usage
22
22
 
@@ -1,7 +1,8 @@
1
1
  # Dokkit Pipeline Reference
2
2
 
3
3
  Detailed step-by-step procedure for the one-command document filling pipeline.
4
- Auto-loaded when `/dokkit` is invoked.
4
+ Read by the invoking skill before execution; bundled paths use the
5
+ DEVLYN_SKILL_DIR binding it passes.
5
6
 
6
7
  ## Table of Contents
7
8
 
@@ -119,7 +120,7 @@ Report: `Phase 3/6: Generated content for N fields`
119
120
  Run the python-docx assembly script (NOT raw XML surgery):
120
121
 
121
122
  ```bash
122
- python .claude/skills/dokkit/scripts/fill_docx.py \
123
+ python "$DEVLYN_SKILL_DIR/scripts/fill_docx.py" \
123
124
  <template.docx> \
124
125
  .dokkit/analysis.json \
125
126
  .dokkit/fill_content.json \
@@ -150,7 +151,7 @@ For each image field and image opportunity in `analysis.json`, run in parallel.
150
151
  **CRITICAL: Always pass `--field-id` and `--purpose`** so the image manifest tracks which image was generated for which slot. Without this, images get randomly assigned to the wrong slots.
151
152
 
152
153
  ```bash
153
- python .claude/skills/dokkit/scripts/source_images.py generate \
154
+ python "$DEVLYN_SKILL_DIR/scripts/source_images.py" generate \
154
155
  --prompt "<prompt>" \
155
156
  --preset <preset> \
156
157
  --output-dir .dokkit/images/ \
@@ -345,4 +346,4 @@ Phase 5 → quality_gates results, iterations_count
345
346
  Phase 6 → exports[] entry added
346
347
  ```
347
348
 
348
- Validate after every write: `python ${CLAUDE_SKILL_DIR}/scripts/validate_state.py .dokkit/state.json`
349
+ Validate after every write: `python "$DEVLYN_SKILL_DIR/scripts/validate_state.py" .dokkit/state.json`
@@ -13,15 +13,45 @@ description: >
13
13
  user-invocable: true
14
14
  allowed-tools: Read, Write, Edit, Bash, Glob, Grep, Agent
15
15
  argument-hint: "<template_path> <sources_folder> | improve [instruction]"
16
- context:
17
- - type: file
18
- path: ${CLAUDE_SKILL_DIR}/PIPELINE.md
19
16
  ---
20
17
 
21
18
  # Dokkit — One-Command Document Filling
22
19
 
23
20
  Source folder + template → finished document. Fully automatic, iterates until perfect.
24
21
 
22
+ Resolve bundled resources from the SKILL.md loaded for this invocation.
23
+
24
+ Reader-rendered directory hint:
25
+ ```text
26
+ ${CLAUDE_SKILL_DIR}
27
+ ```
28
+
29
+ Treat the hint as literal path data, never shell code. If the reader
30
+ replaced it with an absolute directory, use that directory. Otherwise
31
+ use the filesystem path or base directory reported for this loaded
32
+ SKILL.md. Resolve virtual URIs through the reader's native filesystem
33
+ mapping. If available source locations name different directories,
34
+ stop.
35
+
36
+ Bind DEVLYN_SKILL_DIR to that absolute directory. Do not obtain this
37
+ binding from an environment variable, cwd, or another installation.
38
+ Verify its SKILL.md before proceeding. Missing or conflicting source
39
+ identity is BLOCKED:skill-source-unresolved; include the failed path
40
+ when known.
41
+
42
+ Resolve bundled references against this directory. These bindings are
43
+ workflow values: establish them explicitly using each tool or shell's
44
+ literal-path rules, and include their absolute values in every fresh
45
+ worker's prompt, telling it to set them from those values, never from
46
+ its inherited environment. Do not rely on shell state surviving between
47
+ calls.
48
+
49
+ Read PIPELINE.md from this bound directory before executing the
50
+ workflow. Bundled Markdown, references, and scripts use this same
51
+ directory. Project data under .dokkit remains project-relative.
52
+ Pass the absolute binding and required resource paths explicitly
53
+ to every worker.
54
+
25
55
  ## Usage
26
56
 
27
57
  ```
@@ -113,7 +143,7 @@ These rules prevent the font corruption issues seen in previous versions:
113
143
 
114
144
  **Never write inline Gemini API calls for image generation.** Always use the provided script:
115
145
  ```bash
116
- python ${CLAUDE_SKILL_DIR}/scripts/source_images.py generate \
146
+ python "$DEVLYN_SKILL_DIR/scripts/source_images.py" generate \
117
147
  --prompt "<prompt>" --preset <preset> --output-dir .dokkit/images/ \
118
148
  --project-dir . --lang ko
119
149
  ```
@@ -173,7 +203,7 @@ display_h = int(actual_h * scale)
173
203
 
174
204
  | File | Purpose | Used By |
175
205
  |------|---------|---------|
176
- | `PIPELINE.md` | Detailed pipeline steps (auto-loaded) | Orchestrator |
206
+ | `PIPELINE.md` | Detailed pipeline steps (read before execution) | Orchestrator |
177
207
  | `STATE.md` | State schema and management | All agents |
178
208
  | `INGESTION.md` | Source file parsing | Ingestor |
179
209
  | `ANALYSIS.md` | Field detection, structure mapping | Analyzer |
@@ -33,7 +33,7 @@ After any mutation:
33
33
  1. Read current state.json (avoid overwriting concurrent changes)
34
34
  2. Update only the relevant fields
35
35
  3. Write the full state back
36
- 4. Validate: `python .claude/skills/dokkit/scripts/validate_state.py .dokkit/state.json`
36
+ 4. Validate: `python "$DEVLYN_SKILL_DIR/scripts/validate_state.py" .dokkit/state.json`
37
37
 
38
38
  ## State Transitions
39
39
 
@@ -113,7 +113,7 @@ Each opportunity is added to the field's `image_opportunities` array:
113
113
  - `insertion_point.strategy`: Always `"after_paragraph"` for section content
114
114
  - `insertion_point.anchor_text`: Distinctive Korean phrase from the paragraph (used by filler to locate insertion point)
115
115
  - `generation_prompt`: English prompt for AI image generation
116
- - `preset`: Maps to `.claude/skills/dokkit/scripts/source_images.py` preset parameter
116
+ - `preset`: Maps to the bundled `scripts/source_images.py` preset parameter
117
117
  - `content_type`: One of `flowchart`, `diagram`, `data`, `concept`, `infographic`
118
118
  - `rationale`: Brief explanation of why an image helps here
119
119
  - `dimensions`: Default size — filler may adjust based on content_type
@@ -46,7 +46,6 @@ Complete catalog of YAML frontmatter fields for Claude Code skill files (`SKILL.
46
46
  | `argument-hint` | string | none | Placeholder shown to user (e.g., `"[file path]"`) |
47
47
  | `user-invocable` | boolean | `true` | Whether users can trigger via `/skill-name` |
48
48
  | `disable-model-invocation` | boolean | `false` | If `true`, Claude cannot proactively trigger the skill |
49
- | `context` | list | none | Files to inject into context when skill activates |
50
49
  | `agent` | object | none | Run skill as a subagent with its own context |
51
50
  | `model` | string | inherited | Override model (`opus`, `sonnet`, `haiku`) |
52
51
  | `hooks` | object | none | Shell commands to run on skill lifecycle events |
@@ -62,20 +61,15 @@ allowed-tools: Read, Bash(npm test *), Bash(npx *)
62
61
 
63
62
  Wildcard `*` matches any arguments. Without a glob, Bash runs any command.
64
63
 
65
- ### `context` Field
64
+ ### Supporting files
66
65
 
67
- Inject files into the skill's context automatically:
66
+ Read supporting files explicitly from the skill body:
68
67
 
69
- ```yaml
70
- context:
71
- - type: file
72
- path: ${CLAUDE_SKILL_DIR}/PATTERNS.md
73
- - type: file
74
- path: ./CLAUDE.md
68
+ ```text
69
+ Before proceeding, read PATTERNS.md relative to the directory
70
+ containing this loaded SKILL.md.
75
71
  ```
76
72
 
77
- Use `${CLAUDE_SKILL_DIR}` for paths relative to the skill directory.
78
-
79
73
  ### `agent` Field
80
74
 
81
75
  Run the skill as an isolated subagent:
@@ -102,7 +96,10 @@ hooks:
102
96
 
103
97
  ## String Substitutions
104
98
 
105
- These placeholders are replaced at runtime:
99
+ Claude Code replaces these placeholders when rendering a skill.
100
+ They are reader substitutions, not portable shell environment
101
+ variables. Portable resource references use the selected skill
102
+ directory and relative paths.
106
103
 
107
104
  | Placeholder | Replaced With |
108
105
  |---|---|
@@ -116,7 +113,7 @@ These placeholders are replaced at runtime:
116
113
  ```markdown
117
114
  Parse `$ARGUMENTS` for the file path.
118
115
  If `$1` is empty, ask the user for a target file.
119
- Read the config from `${CLAUDE_SKILL_DIR}/config.yaml`.
116
+ Read config.yaml relative to this loaded skill's directory.
120
117
  ```
121
118
 
122
119
  ---