Skip to content

feat(contracts): add component metadata v1 - #320

Draft
davida-ps wants to merge 2 commits into
davida-ps/lifecycle-semver-v1from
davida-ps/metadata-contracts-v1
Draft

feat(contracts): add component metadata v1#320
davida-ps wants to merge 2 commits into
davida-ps/lifecycle-semver-v1from
davida-ps/metadata-contracts-v1

Conversation

@davida-ps

@davida-ps davida-ps commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

User description

Summary

  • Add the normalized clawsec metadata schema for canonical core, suite, and drift-guardian packages.
  • Add a reusable component-reference schema and a closed capability registry.
  • Enforce canonical identity, one harness, bounded harness versions, role/dependency direction, maturity vocabulary, and the shared clawsec-core/v1 management protocol.
  • Model NanoClaw v2 as host-owned .claude/skills/ packages and reject v1 metadata, unsafe placement, invalid persistence, and stateful operational suites.
  • Extend the existing Python validator and packager path so canonical packages fail closed while existing packages without normalized metadata remain explicitly classified as legacy migration inputs.

Architecture alignment

This implements the bounded metadata-contracts-v1 unit from design PR #306 and is stacked on strict lifecycle SemVer PR #309.

The contract preserves the intended dependency direction:

  • core depends on neither suite nor guardian;
  • suite has exactly one same-harness core runtime dependency;
  • guardian uses core management compatibility without a suite or package runtime dependency.

maturity is a package capability claim, not the beta/RC/stable release lifecycle. stable and deprecated remain structural vocabulary only; this validator does not prove conformance, qualification, successor authorization, or catalog activation.

The fixtures use 0.1.0-rc.1 and deliberately state that they are contract fixtures, not harness-support claims. suite.recurring-advisory-verification is optional so NanoClaw v2 can truthfully omit it and later report intentionally_unsupported through the result contract.

The component reference validates identity and digest syntax only. Later result, receipt, and catalog verifiers must recompute the digest against exact skill.json bytes.

Scope boundaries

This PR does not:

  • add or change an installable skill;
  • implement advisory verification, installation, a suite, or a guardian;
  • change a workflow, release pipeline, catalog, Pages output, or public documentation;
  • tag, release, publish, or activate anything;
  • authorize stable metadata without later conformance and signed-catalog evidence.

Remote verification

The exact pushed files were copied with SCP to an operator-approved remote Linux lab checkout at base 2293a80b752325b06515244c2ee7a33118ba5367. Local and remote SHA-256 values matched for all 14 changed files.

Passed remotely:

  • npm run test:metadata-contracts — 6 valid fixtures and 42 invalid fixtures
  • every scripts/test-skill-*.mjs regression
  • full ESLint with zero warnings
  • npx tsc --noEmit
  • npm run build
  • Ruff and Bandit across utils/
  • git diff --check
  • Node, Python, and packaging reproducers for numeric versions, malformed harness blocks, and malformed SBOM structures
  • 78 additional Node/component-reference type-boundary probes and 43 Python-wrapper probes with no throws, tracebacks, or internal validator errors

Two independent read-only reviews accepted the frozen hash set after the blocking findings were corrected.

Review state

Keep this PR in draft. Do not merge it until PR #306, PR #309, the skill SemVer rules, and the shared design language are reviewed together.


Generated description

Below is a concise technical summary of the changes proposed in this PR:
Add normalized clawsec metadata v1 by introducing the package metadata schema, component-reference schema, and capability registry for canonical core, suite, and guardian packages. Extend the Node validator and Python validate_skill.py wrapper to enforce identity, dependency direction, and NanoClaw v2 host placement while classifying non-normalized packages as legacy migration inputs.

TopicDetails
Metadata contract Define the clawsec v1 contract for canonical package identity, supported capabilities, and component-reference syntax across core, suite, and drift guardian packages.
Modified files (9)
  • contracts/capability-registry.json
  • contracts/fixtures/component-metadata-v1/valid/core-nanoclaw-v2.json
  • contracts/fixtures/component-metadata-v1/valid/core-openclaw.json
  • contracts/fixtures/component-metadata-v1/valid/drift-nanoclaw-v2.json
  • contracts/fixtures/component-metadata-v1/valid/drift-picoclaw.json
  • contracts/fixtures/component-metadata-v1/valid/suite-hermes.json
  • contracts/fixtures/component-metadata-v1/valid/suite-nanoclaw-v2.json
  • contracts/schemas/component/component-ref-v1.schema.json
  • contracts/schemas/component/metadata-v1.schema.json
Latest Contributors(1)
UserCommitDate
David.a@prompt.securityfeat(contracts): add c...July 23, 2026
Validator rollout Extend the validator path to enforce the new metadata contract, reject unsafe NanoClaw v2 layouts, and keep legacy packages explicitly classified during validation and packaging.
Modified files (5)
  • package-lock.json
  • package.json
  • scripts/ci/validate_clawsec_metadata.mjs
  • scripts/test-skill-component-metadata.mjs
  • utils/validate_skill.py
Latest Contributors(2)
UserCommitDate
David.a@prompt.securityfix(contracts): allow ...July 23, 2026
github-actions[bot]chore: update NVD/GHSA...July 21, 2026
Review this PR on Baz | Customize your next review

Comment on lines +123 to +134
"provides": {
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": {
"type": "string",
"pattern": "^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)*$"
}
},
"management_protocol_provides": {
"type": "array",
"uniqueItems": true,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Role topology is unenforced

clawsec.role isn't used to constrain the dependency fields here, so suite, guardian, and core metadata can still satisfy the array syntax while violating the PR contract — should we add role-specific if/then rules for the intended dependency shape?

Severity

Want Baz to fix this for you? Activate Fixer

Other fix methods

Fix in Cursor

Prompt for AI Agents
Before applying, verify this suggestion against the current code. In
contracts/schemas/component/metadata-v1.schema.json around lines 123-159 within the
`clawsec` object (the `provides`, `management_protocol_provides`,
`management_protocol_requires`, `install_requires`, and `runtime_requires` definitions),
add role-specific validation that actually uses `clawsec.role` to constrain these
fields. Refactor the existing `clawsec.allOf` section (currently only enforcing the
guardian family/default_mode rules around lines 176-211) by adding additional `if/then`
branches: for `core`, require `management_protocol_provides` (and keep array syntax
validation); for `suite`, forbid `runtime_requires` (or require it to be absent/empty
per the PR contract); and for `guardian`, forbid `runtime_requires` as well. Make the
rules explicit using `required`/`not` so the schema can no longer accept metadata
combinations that the finding calls out.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit 8216ac5 addressed this comment by adding role-aware topology validation in validateRoleGraph, enforcing core, suite, and guardian dependency/protocol shapes. The JSON schema itself still lacks equivalent if/then rules, so schema-only consumers can accept invalid combinations.

Comment on lines +89 to +98
if (!validateMetadataSchema(skill)) {
for (const schemaError of validateMetadataSchema.errors ?? []) {
addError(
errors,
"METADATA_SCHEMA_INVALID",
schemaError.dataPath || "/",
`${schemaError.keyword}: ${schemaError.message}`,
);
}
return finish("invalid", errors, warnings);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Schema diagnostics drift between validators

validateClawsecMetadata() and validateComponentRef() both repeat the same validate*.errors loop and diagnostic shaping (schemaError.dataPath || "/", ${schemaError.keyword}: ${schemaError.message}), so any future error-format tweak has to be made twice and can drift — should we factor that into a tiny local helper?

Severity

Want Baz to fix this for you? Activate Fixer

Other fix methods

Fix in Cursor

Prompt for AI Agents
Before applying, verify this suggestion against the current code. In
scripts/ci/validate_clawsec_metadata.mjs around lines 89-99 inside
validateClawsecMetadata and around lines 215-225 inside validateComponentRef, both
validators duplicate the same AJV error-to-diagnostic loop and formatting
(`schemaError.dataPath || "/"` and ``${schemaError.keyword}: ${schemaError.message}``).
Refactor this by introducing a tiny local helper (near the two validators) that accepts
the validator failure + the error array and an error code, then loops over
`validator.errors ?? []` and calls addError with the common path/message shaping. Update
both validators to call this helper instead of inlining the loop so the
schema-to-diagnostic contract lives in one place.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant