Conversation
Reject leading or trailing whitespace in skill directory names so local discovery and hosted runtime register the same canonical identifier. Constraint: Directory identity must remain byte-for-byte stable across discovery and hosted validation. Rejected: Trim invalid directory names | normalization would register different local and hosted identifiers. Confidence: high Scope-risk: narrow Tested: deno test --no-check --allow-all src/skill/parser.test.ts; deno fmt --check; git diff --check Not-tested: Full repository suite is delegated to the existing pre-push and PR CI gates.
The stale release version is already published and does not belong in the skill identity feature branch. Constraint: Feature pull requests do not reserve framework versions Rejected: Select another version now | publication must use a dedicated release pull request after merge Confidence: high Scope-risk: narrow Directive: Preserve canonical directory identity and keep display metadata separate Tested: version synchronization assertions and git diff check
The feature now composes with current main while retaining canonical runtime ids and separate display metadata. Constraint: Shared branch history must remain intact Rejected: Rebase and force push | shared history must not be rewritten Confidence: high Scope-risk: moderate Directive: Do not normalize canonical skill directory identity Tested: merge conflict scan and canonical whitespace regression inspection
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1938252f66
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
Pull request overview
Implements runtime-safe canonical skill identity while preserving human-readable display labels across discovery, prompt augmentation, runtime skill metadata, and tooling. This aligns the code/runtime behavior with the #9 contract by keeping callable ids stable (directory/owned id) and surfacing display labels via displayName and metadata.display_name.
Changes:
- Treats the directory (or owned/provider-safe namespaced id) as the canonical skill id/name, and derives optional
displayNamefrommetadata.display_nameor legacyfrontmatter.name. - Updates runtime/tooling prompt surfaces to show display labels without changing lookup ids, and adds id validation for unresolved selectors.
- Expands/updates unit + e2e coverage for canonical-id lookup, legacy display-name preservation, and owned/provider-safe ids.
Verification (as reported in PR description):
- Focused suite:
77 passed (41 steps), 0 failed - Pre-push hook: unit suite
2736 passed (22142 steps), 0 failed(docs coverage failure reproduced on base)
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/e2e/features/skill-capabilities.test.ts | Adds an e2e smoke test ensuring canonical-id lookup works while display labels are preserved and not accepted as ids. |
| src/skill/types.ts | Introduces SKILL_PROVIDER_SAFE_ID_REGEX and adds optional displayName to SkillMetadata. |
| src/skill/tools.ts | Improves unresolved-skill errors by validating selector shape separately from not-found, and supports provider-safe ids. |
| src/skill/skill-owner-scope.test.ts | Adds coverage for resolving owned short names (underscores) prior to plain-id validation. |
| src/skill/prompt-augmentation.ts | Renders skill manifest entries using displayName plus canonical id when available. |
| src/skill/parser.ts | Makes directory name the canonical name, preserves legacy/display metadata as displayName, and supports provider-safe canonical ids via an option. |
| src/skill/parser.test.ts | Adds tests for legacy display-name preservation, metadata precedence, and stricter canonical directory validation. |
| src/discovery/skill-discovery.test.ts | Ensures discovery keys skills by canonical directory id while preserving display metadata. |
| src/discovery/handlers/skill-handler.ts | Removes now-obsolete warning path and documents directory identity as canonical. |
| src/discovery/agent-scoped-capabilities.ts | Validates agent-scoped skill ids as provider-safe when building from directory agents. |
| src/discovery/agent-scoped-capabilities.test.ts | Adds dotted-agent owned-skill coverage and updates empty DiscoveryResult shape. |
| src/agent/runtime/skill-prompt.ts | Uses displayName for prompt labels instead of overloading name. |
| src/agent/runtime/skill-prompt.test.ts | Updates expectations and adds a regression test ensuring canonical ids do not appear as display labels. |
| src/agent/runtime/skill-metadata.ts | Adds metadata normalization, emits displayName, enforces canonical id validity, and preserves structured metadata. |
| src/agent/runtime/skill-metadata.test.ts | Adds coverage for metadata parsing, legacy display name recovery, invalid id rejection, and provider-safe owned ids. |
| src/agent/runtime/project-skill-catalog.test.ts | Validates catalog behavior for provider-safe colocated ids (dotted agent ids). |
| scripts/lint/test-typecheck-baseline.json | Removes a typecheck baseline exclusion now that the test file matches current types. |
| cli/commands/skills/validate.ts | Adds canonical-name validation against directory name prior to parsing/validation. |
| cli/commands/skills/validate.test.ts | Updates CLI tests for directory-name matching validation behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The CLI validator must validate the same canonical identity contract the runtime uses: directory identity is canonical, while legacy display-style frontmatter names remain display metadata. Constraint: Runtime parser preserves non-canonical frontmatter names as display metadata Rejected: Reject all non-canonical frontmatter names | that would make the CLI stricter than runtime loading Rejected: Treat literal dot as a skill id | default validation must describe the current skill directory Confidence: high Scope-risk: narrow Directive: Keep canonical directory identity separate from display metadata in validation paths Tested: TDD RED validate regression run, focused validate GREEN run, and focused skill identity suite
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
src/skill/tools.ts:106
load_skilltreats provider-safe owned short names (for examplex_y) as invalid when they are not found, becauseisUnresolvedSkillSelectorValid()only allowsSKILL_NAME_REGEXor provider-safe ids that include--. Owned short names are a supported selector (resolved first viaskillRegistry.resolveVisibleSkill()), so the not-found path should consider them valid and return the normal "not found" error. Also, the invalid-id message should mention both canonical ids and provider-safe owned ids/short names.
if (!isUnresolvedSkillSelectorValid(skillId)) {
throw toError(
createError({
type: "agent",
message:
`Invalid skill id "${skillId}": must be lowercase alphanumeric with hyphens, 1-64 characters`,
src/skill/types.ts:50
- The
SkillMetadata.namedoc comment says the identifier is "lowercase, hyphenated", but this PR introduces provider-safe owned skill ids (for examplea_b--x_y) that can include underscores and uppercase. Updating the comment avoids misleading API documentation.
/** Skill identifier (lowercase, hyphenated) */
name: string;
/** Optional human-readable label; never used for skill lookup/reference. */
displayName?: string;
Invalid load_skill selectors that look like owned/provider-scoped ids should describe the provider-safe owned-id grammar instead of the plain canonical skill-id grammar. The selector resolver and visibility rules remain unchanged. Constraint: Owned skill ids use the -- separator and provider-safe letters, numbers, underscores, or hyphens Rejected: Change selector resolution | the review finding is diagnostic-only Rejected: Broaden plain skill id validation | plain invalid selectors must keep the existing canonical guidance Confidence: high Scope-risk: narrow Directive: Keep owned-id diagnostics aligned with SKILL_PROVIDER_SAFE_ID_REGEX without widening runtime resolution Tested: TDD RED owned-selector diagnostic regression, focused owner-scope GREEN run, focused skill tool/owner/Task13 suite
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
src/skill/types.ts:47
SkillMetadata.nameis documented as "lowercase, hyphenated", but the PR introduces provider-safe owned skill ids (for examplea_b--x_y) that legitimately include underscores. The comment should describe the broader contract to avoid confusing API consumers.
/** Skill identifier (lowercase, hyphenated) */
src/skill/parser.ts:85
validateSkillMetadatatreats its second argument as the canonical skill id (and validates it directly), but the parameter is still nameddirectoryName, which is misleading (callers can pass computed ids like provider-safe owned ids). Renaming it (and updating the JSDoc) would make the contract clearer and reduce confusion for future callers.
export function validateSkillMetadata(
frontmatter: Record<string, unknown>,
directoryName: string,
options: { providerSafeName?: boolean } = {},
): SkillMetadata {
Current main adds selector allowlist authorization and generic non-disclosing load_skill failures, while this branch owns canonical/display skill identity and provider-owned invalid-ID diagnostics. The merge keeps the shared selector helper imports, preserves provider-safe owned id validation, and makes load_skill enforce allowlists before missing or invalid-id diagnostics. Constraint: PR #3171 must remain a normal merge-based update with no rebase, no force push, and no release behavior. Rejected: Prefer one conflict side wholesale | that would drop either main's selector non-disclosure behavior or PR #3171's provider-owned diagnostic contract. Confidence: high Scope-risk: moderate Directive: Do not weaken selector allowlist errors or owned-skill invalid-ID diagnostics without updating the paired runtime and skill tool tests. Tested: git diff --check Tested: focused combined Deno tests for skill metadata, skill tools, owner scope, runtime load_skill, and hosted runtime essential tools (82 passed, 0 failed) Tested: deno check src/agent/runtime/skill-metadata.ts src/skill/tools.ts
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (3)
src/skill/tools.ts:138
isUnresolvedSkillSelectorValidonly treats provider-safe ids as valid when they contain the owned-skill--separator. That makes provider-safe owned short-name selectors (for examplex_y) reportInvalid skill idwhen they are missing, even though underscores are used for owned short names (seeskill-owner-scope.test.tswithshortName: "x_y"). Consider treating any provider-safe selector as syntactically valid so missing owned short names fall through to the existing "Skill not found" path.
return true;
}
return skillId.includes("--") && SKILL_PROVIDER_SAFE_ID_REGEX.test(skillId);
}
src/skill/types.ts:48
SkillMetadata.nameis documented as "lowercase, hyphenated", butvalidateSkillMetadata(..., { providerSafeName: true })now allows provider-safe owned ids (for examplea_b--x_y) which can include underscores and uppercase. Updating the comment to reflect both canonical local ids and provider-safe owned ids will keep the type docs accurate.
/** Skill identifier (lowercase, hyphenated) */
name: string;
src/skill/types.ts:18
- The comment for
SKILL_PROVIDER_SAFE_ID_REGEXsays it is an "owned skill id: sanitized namespace + short name", but the regex itself is a general provider-safe identifier check and does not enforce a namespace separator or segment structure. Updating the comment to match what the regex actually validates will avoid confusion for future callers.
This issue also appears on line 47 of the same file.
/** Provider-safe owned skill id: sanitized namespace + short name, max 64 chars */
export const SKILL_PROVIDER_SAFE_ID_REGEX = /^[A-Za-z0-9_-]{1,64}$/;
Summary
Ready for human review. Current-head CI is green.
Implements the Code/runtime side of #9:
nameequal to the canonical id/folder identitydisplayName/metadata.display_nameThis pull request is feature-only. Publish it later through a dedicated release pull request based on the then-current main branch.
Review remediation
Current review-fix commit:
f976217cc94eb99da4b2b5bce8eb7c36c57b7f28- keeps CLI validation aligned with runtime identity2e9aa7b2d54e7e41d550b35565b02853e066f097- clarifies owned skill selector diagnosticsResolved review findings:
.now resolves before taking the directory basename, soveryfront skills validatevalidates against the actual current skill directory name.#9 contract / runtime evidence
The runtime contract is explicit:
SKILL_NAME_REGEXfor local skills, provider-safe ids where owner/provider scope applies)buildRuntimeSkillDefinitionreturnsnameas canonical id and optionaldisplayNamefrommetadata.display_nameor legacy display-style frontmatterCurrent branch state
Base:
mainata57e8c41ef8b40b64843adfc4a4861a540c4caafHead:
issue-9/skill-display-runtime-identity-code-20260729-review-readyat2e9aa7b2d54e7e41d550b35565b02853e066f097Local remediation commits:
84e0d2dd2d5129c82bd2bf6a6ae3ad950e64d356- removes stale release ownership and restores both version files to current-main0.1.11751938252f66209029c3d2ee35205576f3948b6ea1- normal two-parent merge from currentorigin/mainf976217cc94eb99da4b2b5bce8eb7c36c57b7f28- fixes the twoskills validatereview findings2e9aa7b2d54e7e41d550b35565b02853e066f097- fixes the remaining owned-selector diagnostic review findingVerification
TDD red regression run:
VF_DISABLE_LRU_INTERVAL=1 DENO_TESTING=1 NODE_ENV=production deno test --no-check --allow-all cli/commands/skills/validate.test.tsResult: failed before the implementation with the two expected regressions:
Skill name "code-review" does not match directory name "."Invalid skill name "Process Email": must be lowercase alphanumeric with hyphens, 1-64 charactersFocused CLI validate green run:
VF_DISABLE_LRU_INTERVAL=1 DENO_TESTING=1 NODE_ENV=production deno test --no-check --allow-all cli/commands/skills/validate.test.tsResult:
1 passed (7 steps), 0 failed.Focused skill identity suite:
VF_DISABLE_LRU_INTERVAL=1 DENO_TESTING=1 NODE_ENV=production deno test --no-check --allow-all \ cli/commands/skills/validate.test.ts \ src/agent/runtime/project-skill-catalog.test.ts \ src/agent/runtime/skill-metadata.test.ts \ src/agent/runtime/skill-prompt.test.ts \ src/discovery/agent-scoped-capabilities.test.ts \ src/discovery/skill-discovery.test.ts \ src/skill/parser.test.ts \ src/skill/skill-owner-scope.test.ts \ tests/e2e/features/skill-capabilities.test.tsResult:
77 passed (43 steps), 0 failed.Owned selector diagnostic TDD red run:
VF_DISABLE_LRU_INTERVAL=1 DENO_TESTING=1 NODE_ENV=production deno test --no-check --allow-all src/skill/skill-owner-scope.test.tsResult: failed before the implementation because
writer--Bad Namereceived the canonical-only message:must be lowercase alphanumeric with hyphens, 1-64 characters.Owned selector diagnostic green run:
VF_DISABLE_LRU_INTERVAL=1 DENO_TESTING=1 NODE_ENV=production deno test --no-check --allow-all src/skill/skill-owner-scope.test.tsResult:
13 passed, 0 failed.Focused skill tool/owner/Task 13 suite:
VF_DISABLE_LRU_INTERVAL=1 DENO_TESTING=1 NODE_ENV=production deno test --no-check --allow-all \ src/skill/tools.test.ts \ src/skill/skill-owner-scope.test.ts \ cli/commands/skills/validate.test.ts \ src/agent/runtime/project-skill-catalog.test.ts \ src/agent/runtime/skill-metadata.test.ts \ src/agent/runtime/skill-prompt.test.ts \ src/discovery/agent-scoped-capabilities.test.ts \ src/discovery/skill-discovery.test.ts \ src/skill/parser.test.ts \ tests/e2e/features/skill-capabilities.test.tsResult:
79 passed (56 steps), 0 failed.Required script hook:
Result: failed at
deno task docs:validatebecause currentorigin/mainis missing./release-assetsAPI reference coverage:@exampleinsrc/release-assets/index.tsdocs/api-reference/veryfront/release-assets.mdBaseline reproduction on exact
origin/maina57e8c41ef8b40b64843adfc4a4861a540c4caafreproduced the samerelease-assetsdocs failure.scripts/docs/docs-coverage.test.tsalso failed on both branch andorigin/mainwith missingrelease-assets.Later hidden stages after the docs failure:
deno run --allow-read scripts/docs/validate-guides.tspasseddeno run --allow-read scripts/docs/validate-public-docs.tspasseddeno test --no-check --allow-read tests/docs/guide-contracts.test.ts tests/docs/guide-content.test.tspassed,2 passed (82 steps), 0 faileddeno test --no-check --allow-all tests/docs/guide-examples.test.ts tests/docs/guide-code-examples.test.tspassed,45 passed (87 steps), 0 faileddeno run -A scripts/lint/check-doc-links.tspassed,All 712 doc links OKdeno task typecheckpassedExact hook Playwright stage:
npx playwright test --config=tests/e2e/playwright.config.tsResult: failed on both branch and exact
origin/mainbecausetests/e2e/playwright.config.tsdoes not exist.Canonical Playwright substitute:
Result: failed on both branch and exact
origin/mainwith duplicate local Playwright package loading (Requiring @playwright/test second time). This is a local infrastructure baseline, so current-head CI is the equivalent gate for the Playwright coverage.Normal guarded push:
1938252f66209029c3d2ee35205576f3948b6ea1f976217cc94eb99da4b2b5bce8eb7c36c57b7f28git push origin HEAD:issue-9/skill-display-runtime-identity-code-20260729-review-readyused no force and no bypass2736 passed (22144 steps), 0 failed2737 passed (22144 steps), 0 failedCurrent-head CI:
gh pr checks 3171 --watch --interval 10completed on head2e9aa7b2d54e7e41d550b35565b02853e066f097.Explicit exclusions
Replacement for #3157. This pull request keeps the exact verified head and preserves Kentaro's review request.