feat(knowledge): accept portable library_dir value forms (0.9.0)#894
Conversation
Resolve the library_dir portability collision (#798): the seam only took literal paths, so a corpus root outside the project and home directories forced a machine-specific literal into user settings — exactly what the guardrails hardcoded-path-check blocks. The seam now accepts a leading ~ (home-relative) and env-var references ${NAME} / %NAME% alongside relative and absolute literals. The youtube-digest launcher expands both forms in --work-root via the pure expandPathValue helper (unit-tested), failing loud on an unset variable or non-absolute expansion; literals pass through unchanged. Contract, README, manifest option description, and setup guidance document the forms. Env-var indirection over a ghq-derived scheme: that would couple the seam to ghq presence (the undeclared-hard-dep class #531 flags); a ghq user points the variable at the ghq path. Empirically verified: hardcoded-path patterns flag the literal machine path and pass all three portable forms. Refs: #798, #531 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: ee68a177-59bc-40c2-bb73-a66d20bd1923
…auncher Refs: #798 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: ee68a177-59bc-40c2-bb73-a66d20bd1923
|
Claude finished @kyle-sexton's task in 3m 15s —— View job PR Review: feat(knowledge): accept portable library_dir value forms (0.9.0)
|
|
Claude finished @kyle-sexton's task in 2m 46s —— View job Security Review — PR #894
FindingsSUGGESTION · Confidence: CONFIRMED — Expanded path is not normalized before the absolute-path check
This is user-controlled (the consumer sets both // after the sawForm block, before the isAbsolutePath guard:
if (sawForm) expanded = path.resolve(expanded);…or defer normalization to the caller ( Security-positive observations (no findings)
|
The CI machine-specific-paths gate flags /home/<user> and C:\Users\<user> literals even as test fixtures; exercise the same expansion behavior with path shapes outside the banned classes. Refs: #798 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: ee68a177-59bc-40c2-bb73-a66d20bd1923
|
Claude finished @kyle-sexton's task in 2m 41s —— View job PR Review: feat(knowledge): accept portable library_dir value forms (0.9.0)
SummaryThis review covers all three commits on the branch. The two new commits ( New commits since prior reviews — assessment
Correct and tight. The prior review flagged that
The change from Remaining open findings (from prior passes — not yet addressed)1. Security: expanded path not normalized —
|
|
Claude finished @kyle-sexton's task in 2m 26s —— View job Security Review — PR #894
FindingsSUGGESTION · Confidence: CONFIRMED — Expanded path accepted without
|
Prior sweep replaced only the POSIX fixture; the Windows-home fixture still tripped the machine-specific-paths gate. Refs: #798 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: ee68a177-59bc-40c2-bb73-a66d20bd1923
|
Claude finished @kyle-sexton's task in 1m 42s —— View job PR Review: feat(knowledge): accept portable library_dir value forms (0.9.0)
New commit assessment —
|
|
Claude finished @kyle-sexton's task in 2m 41s —— View job Security Review — PR #894
FindingsSUGGESTION · Confidence: CONFIRMED — Expanded path accepted without
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c770610d0b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| For a root outside the project and home directories, recommend the portable value forms from the | ||
| README's option table (`~` prefix or `${NAME}` / `%NAME%` env-var reference) instead of a literal | ||
| machine path, which guardrail hardcoded-path checks rightly block. |
There was a problem hiding this comment.
Quote env-form values before configuring library_dir
When the setup skill recommends ${NAME} as a headless library_dir value, the immediately preceding claude plugin install ... --config library_dir=<value> command will be run through the user's shell; in Bash, an unquoted library_dir=${KNOWLEDGE_CORPUS_DIR} is expanded before Claude Code sees it, so the stored option becomes the machine-specific path (or empty if unset) instead of the portable literal that run.mjs is supposed to expand/fail-loud on. Please make this guidance include literal quoting/escaping for the env-reference form (and %NAME% for cmd.exe) when using --config.
Useful? React with 👍 / 👎.
…st-corpus-durability Resolves a second version-claim collision on plugins/knowledge (0.9.0 landed via #894 for the library_dir portable-value-forms feature); re-derives this branch's bump to 0.9.1, one past main's current claim.

Resolves the
library_dirportability collision: the seam only took literal paths, so pointing it at a corpus root outside the project and home directories (the intended knowledge-corpus consolidation flow) forced a machine-specific literal into user-level settings — exactly the value class the guardrailshardcoded-path-checkblocks. The two plugins were in direct conflict for the primary supported use case.Closes #798
Decision (the issue's open scheme fork)
Env-var indirection + tilde expansion (options 1 + 2 combined). Machine variance lives in OS user env vars or under home; the stored configuration value stays portable. ghq-derived scheme (option 3) rejected as a seam mechanism: it would couple the seam to ghq presence — the same undeclared-hard-dep defect class #531 flags on #438. A ghq-convention user gets the identical outcome by pointing the env var at the ghq-derived path.
What ships
expandPathValue(new pure helper,extraction/lib/run-args.js): expands a leading~(home-relative, incl.~\on Windows) and${NAME}/%NAME%env-var references anywhere in the value. Fail-loud contract: an unset/empty referenced variable throws, and a value that used either form must expand to an absolute path; literal values pass through byte-identical (back-compat).~userforms stay literal.run.mjs): applies the expansion to--work-rootbefore building the child env — single expansion point;YOUTUBE_WORK_ROOTstays an internal launcher-to-child interface. Errors route through the existing exit-2 + usage path.printenv NAME/$env:NAME). README option table, plugin manifest option description, and setup mismatch guidance updated to match.Verification
run-args.test.js(tilde variants, both env-ref syntaxes, embedded refs, Windows-backslash substitution integrity, unset-var throw, non-absolute throw, literal passthrough). Full extraction suite: 256 passed; the 3 failing suites are the pre-existingimghashvendor module-resolution gap, identical on the base commit (249 passed there, delta = the 7 new cases).tsc --noEmitclean.plugins/guardrails/lib/path-detection:${KNOWLEDGE_CORPUS_DIR},%KNOWLEDGE_CORPUS_DIR%, and~/knowledge-corpusall scan CLEAN; the literalD:/repos/...machine path is FLAGGED.--check+--check-bump, generate-catalog--check, validate-plugin-contracts, check-changed-skills (0 failed), skill-portability lint, markdownlint.Related
library_dirindirection item.🤖 Generated with Claude Code