@openwop/openwop-conformance 1.6.1 → 1.10.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 (159) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +2 -2
  3. package/api/asyncapi.yaml +57 -0
  4. package/api/openapi.yaml +250 -0
  5. package/coverage.md +14 -0
  6. package/fixtures/conformance-run-duration-breach.json +33 -0
  7. package/fixtures.md +19 -0
  8. package/package.json +1 -1
  9. package/schemas/README.md +10 -0
  10. package/schemas/agent-inventory-response.schema.json +90 -0
  11. package/schemas/ai-envelope.schema.json +28 -0
  12. package/schemas/artifact-type-pack-manifest.schema.json +160 -0
  13. package/schemas/capabilities.schema.json +171 -4
  14. package/schemas/chat-card-pack-manifest.schema.json +158 -0
  15. package/schemas/envelopes/media.audio.schema.json +38 -0
  16. package/schemas/envelopes/media.file.schema.json +37 -0
  17. package/schemas/envelopes/media.image.schema.json +33 -0
  18. package/schemas/heartbeat-evaluated.schema.json +14 -0
  19. package/schemas/heartbeat-state-changed.schema.json +14 -0
  20. package/schemas/node-pack-manifest.schema.json +16 -1
  21. package/schemas/run-event-payloads.schema.json +96 -5
  22. package/schemas/run-event.schema.json +4 -0
  23. package/schemas/workflow-definition.schema.json +5 -0
  24. package/schemas/workspace-file-create.schema.json +20 -0
  25. package/schemas/workspace-file.schema.json +39 -0
  26. package/src/lib/agentLoop.ts +44 -0
  27. package/src/lib/agentRuntime.ts +45 -0
  28. package/src/lib/artifactTypes.ts +96 -0
  29. package/src/lib/cardPacks.ts +52 -0
  30. package/src/lib/discovery-capabilities.ts +50 -0
  31. package/src/lib/distillation.ts +38 -0
  32. package/src/lib/feedback.ts +3 -3
  33. package/src/lib/heartbeat.ts +31 -0
  34. package/src/lib/memoryAttribution.ts +48 -0
  35. package/src/lib/subRunAttestation.ts +35 -0
  36. package/src/lib/toolHooks.ts +33 -0
  37. package/src/scenarios/agent-loop-iteration-monotonic.test.ts +33 -0
  38. package/src/scenarios/agent-loop-stateful-resume.test.ts +28 -0
  39. package/src/scenarios/agent-loop-version5-shape.test.ts +41 -0
  40. package/src/scenarios/agent-loop-workspace-snapshot.test.ts +33 -0
  41. package/src/scenarios/agent-manifest-runtime.test.ts +85 -0
  42. package/src/scenarios/ai-envelope-shape.test.ts +14 -18
  43. package/src/scenarios/aiEnvelope.capBreached.test.ts +2 -1
  44. package/src/scenarios/aiEnvelope.schemaDrift.test.ts +2 -1
  45. package/src/scenarios/aiEnvelope.universalKinds.test.ts +2 -1
  46. package/src/scenarios/approval-gate-flow.test.ts +4 -6
  47. package/src/scenarios/artifact-schema-compile-bounded.test.ts +126 -0
  48. package/src/scenarios/artifact-type-pack-install.test.ts +78 -0
  49. package/src/scenarios/artifact-type-pack-manifest-validation.test.ts +140 -0
  50. package/src/scenarios/artifact-type-store-without-render.test.ts +54 -0
  51. package/src/scenarios/audit-log-integrity.test.ts +3 -2
  52. package/src/scenarios/auth-api-key-rotation.test.ts +2 -1
  53. package/src/scenarios/auth-mtls.test.ts +2 -1
  54. package/src/scenarios/auth-oauth2-client-credentials.test.ts +2 -1
  55. package/src/scenarios/auth-oidc-user-bearer.test.ts +2 -1
  56. package/src/scenarios/auth-saml-profile.test.ts +2 -1
  57. package/src/scenarios/auth-scim-profile.test.ts +2 -1
  58. package/src/scenarios/authorization-fail-closed.test.ts +2 -1
  59. package/src/scenarios/authorization-roles-shape.test.ts +2 -1
  60. package/src/scenarios/byok-auth-modes.test.ts +141 -0
  61. package/src/scenarios/chat-card-pack-execution.test.ts +56 -0
  62. package/src/scenarios/chat-card-pack-manifest-validation.test.ts +128 -0
  63. package/src/scenarios/commitment-fired.test.ts +83 -0
  64. package/src/scenarios/credential-payload-redaction.test.ts +2 -1
  65. package/src/scenarios/credentials-capability-shape.test.ts +2 -1
  66. package/src/scenarios/cross-engine-append-ordering.test.ts +2 -1
  67. package/src/scenarios/cross-host-ancestry-endpoint.test.ts +3 -2
  68. package/src/scenarios/cross-host-causation-shape.test.ts +3 -2
  69. package/src/scenarios/deadletter-capability-shape.test.ts +2 -1
  70. package/src/scenarios/deadletter-retry-exhaustion.test.ts +2 -1
  71. package/src/scenarios/distillation-index-roundtrip.test.ts +35 -0
  72. package/src/scenarios/distillation-secret-carryforward.test.ts +35 -0
  73. package/src/scenarios/distillation-shape.test.ts +41 -0
  74. package/src/scenarios/distillation-stable-archive.test.ts +37 -0
  75. package/src/scenarios/distillation-token-budget.test.ts +45 -0
  76. package/src/scenarios/envelope-completion-distinguishes-truncation.test.ts +4 -3
  77. package/src/scenarios/envelope-reasoning-secret-redaction.test.ts +5 -4
  78. package/src/scenarios/envelope-reasoning-shape.test.ts +3 -2
  79. package/src/scenarios/envelope-refusal-shape.test.ts +3 -2
  80. package/src/scenarios/envelope-rendering-hint.test.ts +95 -0
  81. package/src/scenarios/envelope-retry-attempted.test.ts +2 -1
  82. package/src/scenarios/envelope-tier-one-subset-static.test.ts +3 -2
  83. package/src/scenarios/exec-not-protocol-tier.test.ts +137 -0
  84. package/src/scenarios/experimental-tier-shape.test.ts +5 -4
  85. package/src/scenarios/fs-path-traversal.test.ts +2 -1
  86. package/src/scenarios/heartbeat-capability-shape.test.ts +35 -0
  87. package/src/scenarios/heartbeat-fires-once-per-tick.test.ts +28 -0
  88. package/src/scenarios/heartbeat-idempotent-no-spam.test.ts +43 -0
  89. package/src/scenarios/heartbeat-runtime-bound.test.ts +30 -0
  90. package/src/scenarios/http-client-ssrf.test.ts +10 -13
  91. package/src/scenarios/mcp-toolcall-redaction.test.ts +3 -2
  92. package/src/scenarios/media-url-inline-cap.test.ts +167 -0
  93. package/src/scenarios/memory-attribution-emits-on-write.test.ts +54 -0
  94. package/src/scenarios/memory-attribution-no-content.test.ts +45 -0
  95. package/src/scenarios/memory-attribution-replay-stable.test.ts +60 -0
  96. package/src/scenarios/memory-attribution-shape.test.ts +28 -0
  97. package/src/scenarios/memory-attribution-tenant-scoped.test.ts +44 -0
  98. package/src/scenarios/memory-compaction-event-emitted.test.ts +2 -1
  99. package/src/scenarios/memory-compaction-provenance-tag.test.ts +2 -1
  100. package/src/scenarios/memory-compaction-sr1-carry-forward.test.ts +2 -1
  101. package/src/scenarios/memory-consolidation-idempotent.test.ts +77 -0
  102. package/src/scenarios/memory-consolidation-shape.test.ts +90 -0
  103. package/src/scenarios/model-capability-substituted.test.ts +2 -1
  104. package/src/scenarios/multi-agent-confidence-escalation.test.ts +5 -4
  105. package/src/scenarios/multi-agent-handoff-state-machine.test.ts +6 -5
  106. package/src/scenarios/multi-agent-memory-lifecycle.test.ts +4 -3
  107. package/src/scenarios/multi-region-idempotency.test.ts +10 -10
  108. package/src/scenarios/oauth-capability-shape.test.ts +2 -1
  109. package/src/scenarios/oauth-connector-redaction.test.ts +2 -1
  110. package/src/scenarios/pause-resume.test.ts +3 -3
  111. package/src/scenarios/production-backpressure.test.ts +2 -2
  112. package/src/scenarios/production-retention-expiry.test.ts +2 -2
  113. package/src/scenarios/prompt-all-four-kinds-events.test.ts +2 -1
  114. package/src/scenarios/prompt-composed-secret-redaction.test.ts +2 -1
  115. package/src/scenarios/prompt-composed-trust-marker.test.ts +2 -1
  116. package/src/scenarios/prompt-end-to-end-events.test.ts +2 -1
  117. package/src/scenarios/prompt-list-and-fetch.test.ts +2 -1
  118. package/src/scenarios/prompt-mutable-lifecycle.test.ts +2 -1
  119. package/src/scenarios/prompt-mutation-workspace-membership-enforced.test.ts +2 -1
  120. package/src/scenarios/prompt-pack-install.test.ts +2 -1
  121. package/src/scenarios/prompt-read-workspace-membership-enforced.test.ts +2 -1
  122. package/src/scenarios/prompt-render-deterministic.test.ts +2 -1
  123. package/src/scenarios/prompt-resolution-chain-agent-intrinsic.test.ts +2 -1
  124. package/src/scenarios/prompt-resolution-chain-fallback-cascade.test.ts +2 -1
  125. package/src/scenarios/prompt-resolution-chain-node-wins.test.ts +2 -1
  126. package/src/scenarios/prompt-template-shape.test.ts +2 -1
  127. package/src/scenarios/provider-usage.test.ts +2 -1
  128. package/src/scenarios/replay-divergence-at-refusal.test.ts +4 -3
  129. package/src/scenarios/replay-fork-arbitrary.test.ts +3 -1
  130. package/src/scenarios/replay-llm-cache-key-portable.test.ts +2 -1
  131. package/src/scenarios/replayDeterminism.test.ts +3 -1
  132. package/src/scenarios/run-execution-bounds-shape.test.ts +133 -0
  133. package/src/scenarios/sandbox-memory-cap.test.ts +2 -1
  134. package/src/scenarios/sandbox-mvp-behavior.test.ts +2 -1
  135. package/src/scenarios/sandbox-no-host-fs-escape.test.ts +2 -1
  136. package/src/scenarios/sandbox-timeout-cap.test.ts +2 -1
  137. package/src/scenarios/scheduling-capability-shape.test.ts +2 -1
  138. package/src/scenarios/scheduling-cron-fires-once.test.ts +2 -1
  139. package/src/scenarios/secret-leakage-otel-attribute.test.ts +7 -6
  140. package/src/scenarios/spec-corpus-validity.test.ts +1 -1
  141. package/src/scenarios/subrun-approval-fail-closed.test.ts +33 -0
  142. package/src/scenarios/subrun-approval-gate.test.ts +35 -0
  143. package/src/scenarios/subrun-attestation-shape.test.ts +30 -0
  144. package/src/scenarios/subrun-checksum-stable.test.ts +43 -0
  145. package/src/scenarios/tool-hooks-authorization-fail-closed.test.ts +39 -0
  146. package/src/scenarios/tool-hooks-content-free.test.ts +40 -0
  147. package/src/scenarios/tool-hooks-rate-limit.test.ts +32 -0
  148. package/src/scenarios/tool-hooks-secret-redaction.test.ts +34 -0
  149. package/src/scenarios/tool-hooks-shape.test.ts +34 -0
  150. package/src/scenarios/wasm-pack-abi-version-rejection.test.ts +3 -10
  151. package/src/scenarios/wasm-pack-invoke-completed.test.ts +2 -2
  152. package/src/scenarios/wasm-pack-invoke-suspended.test.ts +2 -2
  153. package/src/scenarios/wasm-pack-load.test.ts +2 -2
  154. package/src/scenarios/wasm-pack-memory-cap.test.ts +3 -6
  155. package/src/scenarios/wasm-pack-replay-determinism.test.ts +2 -2
  156. package/src/scenarios/workflow-primary-output-annotation.test.ts +142 -0
  157. package/src/scenarios/workspace-behavior.test.ts +134 -0
  158. package/src/scenarios/workspace-capability-shape.test.ts +73 -0
  159. package/src/scenarios/workspace-cross-tenant-isolation.test.ts +84 -0
package/fixtures.md CHANGED
@@ -358,6 +358,25 @@ Both items are tracked as v1.x conformance expansion work.
358
358
 
359
359
  ---
360
360
 
361
+ ## `conformance-run-duration-breach` (RFC 0058 — wall-clock run timeout)
362
+
363
+ > **Status: RFC 0058 `Draft`.** Exercises the `run-duration` `cap.breached` kind. Soft-skips until a host advertises `capabilities.limits.maxRunDurationMs` AND enforces the wall-clock bound; gated in `run-execution-bounds-shape.test.ts` via `isFixtureAdvertised`.
364
+
365
+ - **Purpose**: verify that `RunOptions.configurable.runTimeoutMs` (clamped to `Capabilities.limits.maxRunDurationMs`) terminates a run that overruns its deadline, emitting `cap.breached {kind: 'run-duration'}` + terminal `failed` with `error.code = 'run_timeout'` per `run-options.md` §runTimeoutMs + `capabilities.md` §"Engine-enforced limits".
366
+ - **Topology**: single `core.delay` node that sleeps `input.delayMs` (default `30000`) — far longer than the small `runTimeoutMs` the test supplies.
367
+ - **Inputs**: `delayMs` (number, default `30000`).
368
+ - **Conformance test driver**:
369
+ 1. POST `/v1/runs` with `{workflowId: "conformance-run-duration-breach", configurable: {runTimeoutMs: 1000}}`.
370
+ 2. Poll until terminal.
371
+ 3. **Assert** terminal status is `failed`.
372
+ 4. **Assert** `RunSnapshot.error.code === "run_timeout"`.
373
+ 5. **Assert** the event log contains a `cap.breached` event with `payload: {kind: "run-duration", limit: 1000, observed: <elapsedMs > 1000>}` — `observed` recorded in the event, not recomputed at replay (`replay.md`).
374
+ - **Negative path**: same fixture with `runTimeoutMs` above the (short) `delayMs`, or no override, completes normally.
375
+
376
+ This fixture is unblocked when a host exposes a wall-clock deadline enforcer advertising `capabilities.limits.maxRunDurationMs`. Tracked as v1.x conformance expansion work (RFC 0058 acceptance criteria).
377
+
378
+ ---
379
+
361
380
  ## `openwop-smoke-byok-roundtrip` (BYOK end-to-end smoke fixture)
362
381
 
363
382
  > **Status: included in the v1.0 conformance baseline.** Server-side `conformance.secret.echo` support is exercised by `src/scenarios/byok-roundtrip.test.ts`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openwop/openwop-conformance",
3
- "version": "1.6.1",
3
+ "version": "1.10.0",
4
4
  "description": "Production-ready black-box conformance suite for OpenWOP v1.0 compliant servers.",
5
5
  "repository": {
6
6
  "type": "git",
package/schemas/README.md CHANGED
@@ -4,18 +4,26 @@
4
4
 
5
5
  | Schema | Source spec | Coverage |
6
6
  |---|---|---|
7
+ | `agent-inventory-response.schema.json` | `node-packs.md` + RFC 0072 | RFC 0072 §A — read projection of installed manifest agents (`GET /v1/agents` body + `$defs.AgentInventoryEntry`); no system prompt / handoff schemas / credentials (SR-1) |
7
8
  | `agent-manifest.schema.json` | `node-packs.md` + agent-pack RFCs | Agent manifest entries distributed alongside node-pack manifests |
8
9
  | `agent-ref.schema.json` | `agent-memory.md` + agent-identity RFC | Multi-Agent Shift Phase 1 — slim runtime AgentRef projection carried on `RunSnapshot.agent` / `runOrchestrator`, `WorkflowNode.agent?`, and `agent.*` event payloads |
9
10
  | `ai-envelope.schema.json` | `ai-envelope.md` | FINAL v1.1 — inbound LLM-emission envelope. Top-level shape (`type` / `schemaVersion` / `envelopeId` / `correlationId` / `payload` / `meta` / `partial`). Per-kind payload schemas under `envelopes/`. Distinct from `RunEventDoc` (outbound) and `error-envelope.schema.json` (host HTTP errors). |
11
+ | `artifact-type-pack-manifest.schema.json` | `artifact-type-packs.md` + RFC 0071 | DRAFT — manifest for `kind: "artifact-type"` registry packs. Peer to `node-pack-manifest.schema.json` (RFC 0003), `workflow-chain-pack-manifest.schema.json` (RFC 0013), and `prompt-pack-manifest.schema.json` (RFC 0028); disjoint via the `kind` discriminator. Distributes typed artifact definitions (schema + advisory rendering hint + lifecycle + export-format hints) via the same signed-tarball + Ed25519 + SRI pipeline. |
10
12
  | `envelopes/clarification.request.schema.json` | `ai-envelope.md` §"Universal kinds" | FINAL v1.1 — payload for the universal `clarification.request` kind; engine lifts to `kind: "clarification"` `InterruptPayload`. |
11
13
  | `envelopes/schema.request.schema.json` | `ai-envelope.md` §"Universal kinds" | FINAL v1.1 — LLM asks the engine for a kind's JSON Schema. Counts against `Capabilities.limits.schemaRounds`. |
12
14
  | `envelopes/schema.response.schema.json` | `ai-envelope.md` §"Universal kinds" | FINAL v1.1 — side-channel ack for `schema.request`. Never surfaces to users. |
13
15
  | `envelopes/error.schema.json` | `ai-envelope.md` §"Universal kinds" | FINAL v1.1 — LLM's deliberate error report. Distinct from `error-envelope.schema.json` (host HTTP errors). |
16
+ | `envelopes/media.image.schema.json` | `ai-envelope.md` §"Media reference payloads" | RFC 0055 §C — optional `media.image` payload; tenant-scoped URL ref or inline base64 below `maxInlineMediaBytes`. |
17
+ | `envelopes/media.audio.schema.json` | `ai-envelope.md` §"Media reference payloads" | RFC 0055 §C — optional `media.audio` payload; URL ref or inline base64 + optional `durationSeconds`. |
18
+ | `envelopes/media.file.schema.json` | `ai-envelope.md` §"Media reference payloads" | RFC 0055 §C — optional `media.file` payload; downloadable asset by URL ref or inline base64 + optional `name`. |
14
19
  | `annotation.schema.json` | `RFCS/0056` + `observability.md` | RFC 0056 (`Draft`) — a non-blocking human/agent quality signal (rating / correction / label / flag) attached to a run, event, or node. A side-resource (not a replayable run-event-log entry); response of `POST/GET /v1/runs/{runId}/annotations` + payload of the `run.annotated` SSE notification. |
15
20
  | `annotation-create.schema.json` | `RFCS/0056` | RFC 0056 (`Draft`) — request body for `POST /v1/runs/{runId}/annotations` (host assigns `annotationId`/`createdAt`/`actor`; binds `target.runId` to the path). |
21
+ | `heartbeat-evaluated.schema.json` | `RFCS/0060` + `host-capabilities.md` | RFC 0060 (`Active`) — payload of the heartbeat-scoped `heartbeat.evaluated` AsyncAPI event (`{ heartbeatId, status, changed }`); emitted every tick by a host advertising `capabilities.heartbeat`. Not a run-event-log entry. |
22
+ | `heartbeat-state-changed.schema.json` | `RFCS/0060` + `host-capabilities.md` | RFC 0060 (`Active`) — payload of the `heartbeat.stateChanged` AsyncAPI event (`{ heartbeatId, from, to }`); emitted only on a predicate-state transition. Not a run-event-log entry. |
16
23
  | `audit-verify-result.schema.json` | `auth-profiles.md` §`openwop-audit-log-integrity` | Response payload from `GET /v1/audit/verify` — chain-validity verdict + checkpoints + anomalies |
17
24
  | `capabilities.schema.json` | `capabilities.md` | `/.well-known/openwop` response — protocolVersion + supportedEnvelopes + schemaVersions + limits + optional v1 discovery surface |
18
25
  | `channel-written-payload.schema.json` | `channels-and-reducers.md` §Channel write event | Payload of the `channel.written` RunEvent — write input + reducer name |
26
+ | `chat-card-pack-manifest.schema.json` | `chat-card-packs.md` + RFC 0071 | DRAFT — manifest for `kind: "card"` registry packs (RFC 0071 Phase 2). Peer to the node/workflow-chain/prompt/artifact-type pack manifests; disjoint via the `kind` discriminator. Distributes AI chat cards: a prompt template + typed input subset bound to a typed `outputArtifactType`. |
19
27
  | `conversation-event.schema.json` | `channels-and-reducers.md` + conversation RFC | Multi-turn conversation event shape for orchestrator-driven HITL flows |
20
28
  | `conversation-turn.schema.json` | `channels-and-reducers.md` + conversation RFC | Conversation turn shape for user/agent/system messages |
21
29
  | `core-conformance-mock-agent-config.schema.json` | `node-packs.md` + RFC 0023 | Config shape for the conformance-only `core.conformance.mock-agent` typeId — drives `agent.*` event emission on cue (`mockReasoning` / `mockToolCalls` / `mockHandoff` / `mockDecision` / `mockConfidence`). Hosts MUST refuse this typeId for production tenants unless `capabilities.conformance.mockAgent` is advertised. |
@@ -44,6 +52,8 @@
44
52
  | `suspend-request.schema.json` | `interrupt.md` | `InterruptPayload` with 8 `kind` discriminators (approval, clarification, external-event, custom, conversation.start, conversation.exchange, conversation.close, low-confidence) |
45
53
  | `workflow-chain-pack-manifest.schema.json` | `workflow-chain-packs.md` + RFC 0013 | Manifest for workflow-chain packs (`kind: "workflow-chain"`) — pre-configured DAG fragments expanded inline at workflow-author time. Peer to `node-pack-manifest.schema.json`; disjoint via the `kind` discriminator. |
46
54
  | `workflow-definition.schema.json` | `channels-and-reducers.md` + `node-packs.md` | DAG of nodes + edges + triggers + variables + channels |
55
+ | `workspace-file.schema.json` | `agent-workspace.md` + `RFCS/0059` | RFC 0059 — a versioned workspace file (`{path, content, version, etag, updatedAt}`); response of `GET/PUT /v1/host/workspace/files/{path}`. |
56
+ | `workspace-file-create.schema.json` | `agent-workspace.md` + `RFCS/0059` | RFC 0059 — `PUT /v1/host/workspace/files/{path}` request body (content + optional contentType; path from the URL, version/etag host-assigned). |
47
57
 
48
58
  ## Validating against the schemas
49
59
 
@@ -0,0 +1,90 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://openwop.dev/spec/v1/agent-inventory-response.schema.json",
4
+ "title": "AgentInventoryResponse",
5
+ "description": "Response body for `GET /v1/agents` (RFC 0072 §A). A read-only projection of the manifest agents a host has installed into its AgentRegistry (RFC 0003 / RFC 0070). Served only when the host advertises `capabilities.agents.manifestRuntime.supported: true`. Each entry MUST NOT carry the agent's system-prompt body, resolved handoff schemas, or any credential material (SR-1).",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["agents", "total"],
9
+ "properties": {
10
+ "agents": {
11
+ "type": "array",
12
+ "items": { "$ref": "#/$defs/AgentInventoryEntry" },
13
+ "description": "Installed manifest agents, in a stable (agentId-sorted) order."
14
+ },
15
+ "total": {
16
+ "type": "integer",
17
+ "minimum": 0,
18
+ "description": "Count of installed manifest agents (== agents.length)."
19
+ }
20
+ },
21
+ "$defs": {
22
+ "AgentInventoryEntry": {
23
+ "type": "object",
24
+ "title": "AgentInventoryEntry",
25
+ "description": "Read projection of an installed `AgentManifest` (agent-manifest.schema.json). Also the body of `GET /v1/agents/{agentId}`.",
26
+ "additionalProperties": false,
27
+ "required": ["agentId", "persona", "label", "modelClass", "packName", "packVersion", "toolAllowlist", "hasHandoffSchemas"],
28
+ "properties": {
29
+ "agentId": {
30
+ "type": "string",
31
+ "description": "The manifest agentId (matches `AgentManifest.agentId` / `AgentRef.agentId`)."
32
+ },
33
+ "persona": {
34
+ "type": "string",
35
+ "description": "Human-readable agent name from the manifest."
36
+ },
37
+ "label": {
38
+ "type": "string",
39
+ "description": "Short UI label; falls back to `persona` when the manifest omits `label`."
40
+ },
41
+ "description": {
42
+ "type": "string",
43
+ "description": "Optional one-line catalog summary from the manifest."
44
+ },
45
+ "modelClass": {
46
+ "type": "string",
47
+ "description": "The manifest's `modelClass` (see agent-manifest.schema.json)."
48
+ },
49
+ "packName": {
50
+ "type": "string",
51
+ "description": "The pack this agent was installed from."
52
+ },
53
+ "packVersion": {
54
+ "type": "string",
55
+ "description": "The installed pack version."
56
+ },
57
+ "toolAllowlist": {
58
+ "type": "array",
59
+ "items": { "type": "string" },
60
+ "description": "Tool identifiers the agent MAY invoke (RFC 0002 §A14). The host MUST enforce this at dispatch; an empty array means no tools."
61
+ },
62
+ "hasHandoffSchemas": {
63
+ "type": "boolean",
64
+ "description": "Whether the manifest declares handoff task/return schemas (the host validates dispatch payloads against them when it advertises `agents.manifestRuntime.handoffValidation`). The schemas themselves are NOT exposed here."
65
+ },
66
+ "memoryShape": {
67
+ "type": "object",
68
+ "additionalProperties": false,
69
+ "description": "The manifest's declared memory shape, when present.",
70
+ "properties": {
71
+ "scratchpad": { "type": "boolean" },
72
+ "conversation": { "type": "boolean" },
73
+ "longTerm": { "type": "boolean" }
74
+ }
75
+ },
76
+ "confidenceThreshold": {
77
+ "type": "number",
78
+ "minimum": 0,
79
+ "maximum": 1,
80
+ "description": "The manifest's `confidence.defaultThreshold`, when present (RFC 0002 §F)."
81
+ },
82
+ "degraded": {
83
+ "type": "array",
84
+ "items": { "type": "string" },
85
+ "description": "Capability keys this agent declared as `peerDependenciesMeta.optional` that this host does NOT satisfy, and which are therefore inert for this installation (RFC 0072 §C). Absent or empty means the agent runs at full declared capability here."
86
+ }
87
+ }
88
+ }
89
+ }
90
+ }
@@ -75,6 +75,34 @@
75
75
  "type": "string",
76
76
  "maxLength": 256,
77
77
  "description": "Optional human-readable label for ops dashboards (e.g., `\"Draft PRD #2\"`). Never used for routing; never persisted into event payloads in a security-relevant way. (in-flight)"
78
+ },
79
+ "rendering": {
80
+ "type": "object",
81
+ "description": "RFC 0055. Optional hint for how a consumer SHOULD render this envelope's payload. Non-normative w.r.t. payload validation; a consumer that doesn't recognize the hint (or a `display` value) MUST fall back to its default rendering (text / raw JSON). Carries no secret material (SR-1 applies as for the rest of `meta`).",
82
+ "properties": {
83
+ "display": {
84
+ "type": "string",
85
+ "enum": ["markdown", "code", "card", "image", "audio", "file"],
86
+ "description": "Renderer family the producer suggests."
87
+ },
88
+ "mimeType": {
89
+ "type": "string",
90
+ "description": "IANA media type when `display` is `image`/`audio`/`file`."
91
+ },
92
+ "lang": {
93
+ "type": "string",
94
+ "description": "Language tag when `display` is `code` (e.g. `ts`, `python`)."
95
+ },
96
+ "alt": {
97
+ "type": "string",
98
+ "description": "Text alternative for accessibility when `display` is `image`/`audio`/`file`. SHOULD be present for those families."
99
+ },
100
+ "title": {
101
+ "type": "string",
102
+ "description": "Optional caption / card header."
103
+ }
104
+ },
105
+ "additionalProperties": false
78
106
  }
79
107
  },
80
108
  "additionalProperties": false,
@@ -0,0 +1,160 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://openwop.dev/spec/v1/artifact-type-pack-manifest.schema.json",
4
+ "title": "ArtifactTypePackManifest",
5
+ "description": "Manifest for a published OpenWOP artifact-type pack — `pack.json` at the pack root with `kind: \"artifact-type\"`. Peer to `node-pack-manifest.schema.json` (RFC 0003), `workflow-chain-pack-manifest.schema.json` (RFC 0013), and `prompt-pack-manifest.schema.json` (RFC 0028); disjoint from all three via the `kind` discriminator. See `spec/v1/artifact-type-packs.md` for the canonical contract and RFC 0071 for the rationale.\n\nArtifact-type packs distribute typed artifact definitions — the JSON Schema, rendering hint, lifecycle, and export-format hints for the rich outputs workflow nodes produce — via the same signed-tarball + Ed25519 + SRI pipeline that already serves node, workflow-chain, and prompt packs. When a host installs an artifact-type pack and advertises `host.artifactTypes: { supported: true }`, it validates produced artifacts of the declared `artifactTypeId`s against their `schemaRef` before emitting `artifact.created`.",
6
+ "type": "object",
7
+ "required": ["name", "version", "kind", "engines", "artifactTypes"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "kind": {
11
+ "type": "string",
12
+ "const": "artifact-type",
13
+ "description": "Pack kind discriminator. MUST be the literal string `\"artifact-type\"`. Manifests carrying any other `kind` value validate against a different pack-manifest schema."
14
+ },
15
+ "name": {
16
+ "type": "string",
17
+ "description": "Reverse-DNS pack name per `node-packs.md` §Naming. Reserved scopes are identical (`core.*` / `vendor.<org>.*` / `community.<author>.*` / `private.<host>.*`). Mirror of `prompt-pack-manifest.schema.json#/properties/name`.",
18
+ "pattern": "^(core|vendor|community|private)\\.[a-z][a-z0-9_-]*(\\.[a-z][a-zA-Z0-9_-]*)+$",
19
+ "minLength": 1,
20
+ "maxLength": 256
21
+ },
22
+ "version": {
23
+ "type": "string",
24
+ "description": "Pack-level SemVer 2.0.0.",
25
+ "pattern": "^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?$"
26
+ },
27
+ "description": { "type": "string", "maxLength": 1024 },
28
+ "author": { "type": "string" },
29
+ "license": { "type": "string", "description": "SPDX license identifier (e.g., `Apache-2.0`, `MIT`)." },
30
+ "homepage": { "type": "string", "format": "uri" },
31
+ "repository": { "type": "string", "format": "uri" },
32
+ "keywords": {
33
+ "type": "array",
34
+ "items": { "type": "string", "maxLength": 64 },
35
+ "maxItems": 50
36
+ },
37
+ "engines": {
38
+ "type": "object",
39
+ "required": ["openwop"],
40
+ "properties": {
41
+ "openwop": {
42
+ "type": "string",
43
+ "description": "Semver range — which openwop protocol versions this pack works against. Example: `>=1.1 <2.0.0`."
44
+ }
45
+ },
46
+ "additionalProperties": true
47
+ },
48
+ "dependencies": {
49
+ "type": "object",
50
+ "additionalProperties": { "type": "string" },
51
+ "description": "Other packs this pack depends on. Map of pack name → semver range. Resolved transitively at workflow-register time."
52
+ },
53
+ "peerDependencies": {
54
+ "type": "object",
55
+ "additionalProperties": { "type": "string" },
56
+ "description": "Engine-supplied capabilities the pack consumes (e.g., `{ \"host.artifactTypes\": \"supported\" }`). Resolved against the host's advertised capabilities at register time."
57
+ },
58
+ "artifactTypes": {
59
+ "type": "array",
60
+ "minItems": 1,
61
+ "items": { "$ref": "#/$defs/ArtifactType" },
62
+ "description": "Typed artifact definitions this pack contributes. Each MUST have a unique `artifactTypeId` within the pack."
63
+ },
64
+ "signing": { "$ref": "#/$defs/Signing" }
65
+ },
66
+ "$defs": {
67
+ "ArtifactType": {
68
+ "type": "object",
69
+ "required": ["artifactTypeId", "schemaRef"],
70
+ "additionalProperties": false,
71
+ "properties": {
72
+ "artifactTypeId": {
73
+ "type": "string",
74
+ "description": "Reverse-DNS artifact-type identifier. Same pattern and reserved scopes as a pack `name`. This is the value `WorkflowNode.artifactType`, `nodes[].artifact.typeId`, and `artifact.created.artifactType` reference. Third parties MUST NOT publish under `core.*`.",
75
+ "pattern": "^(core|vendor|community|private)\\.[a-z][a-z0-9_-]*(\\.[a-z][a-zA-Z0-9_-]*)+$",
76
+ "minLength": 1,
77
+ "maxLength": 256
78
+ },
79
+ "schemaRef": {
80
+ "type": "string",
81
+ "minLength": 1,
82
+ "description": "Path inside the pack tarball to the artifact's JSON Schema (Draft 2020-12). The target schema MUST set `additionalProperties: false` at its top level and declare an `$id` under `{HostBase}/schemas/artifacts/{artifactTypeId}.schema.json`, mirroring the envelope convention in `ai-envelope.md` §\"Canonical schema location\"."
83
+ },
84
+ "schemaVersion": {
85
+ "type": "integer",
86
+ "minimum": 0,
87
+ "description": "Non-negative integer artifact-schema version, parallel to the per-kind integer in `capabilities.schemaVersions`. Absent ⇒ treated as 0. Bumped when the artifact schema changes shape. A version *declaration*, not a validation guarantee (RFC 0075 / P1-2)."
88
+ },
89
+ "validation": {
90
+ "type": "string",
91
+ "enum": ["open", "closed"],
92
+ "description": "RFC 0075. Strictness contract of the artifact's `schemaRef` schema. `closed` ⇒ closed-world (`additionalProperties: false`); a consumer MAY rely on the absence of unknown fields. `open` (recommended for AI/LLM-produced artifacts) ⇒ the schema tolerates extra fields to absorb model drift; consumers MUST ignore unknown fields per COMPATIBILITY.md §2.1. Absent ⇒ `open` (the forward-compatible default). The `additionalProperties:false` requirement on `schemaRef` was relaxed MUST → SHOULD by RFC 0075: a closed-world artifact contract contradicts the protocol's own forward-compat mandate and the first AI-native adopter cannot meet it."
93
+ },
94
+ "displayName": {
95
+ "type": "string",
96
+ "description": "Human-readable label for artifact-management UIs. Non-normative."
97
+ },
98
+ "rendering": { "$ref": "#/$defs/RenderingHint" },
99
+ "exportFormats": {
100
+ "type": "array",
101
+ "items": {
102
+ "type": "string",
103
+ "minLength": 1,
104
+ "maxLength": 64,
105
+ "pattern": "^([a-z][a-z0-9]*|vendor\\.[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*|x-[a-z][a-z0-9-]*)$"
106
+ },
107
+ "uniqueItems": true,
108
+ "description": "Export-format identifiers (hints) a renderer MAY offer. Spec-reserved core identifiers carry interoperable meaning (the lowercase file-extension / common name): `pdf`, `pptx`, `docx`, `xlsx`, `md`, `html`, `txt`, `csv`, `json`, `png`, `svg`, `jpeg`, `step`, `stl`, `dxf`. Domain-specific formats outside the core set MUST be `vendor.<org>.<format>`- or `x-<format>`-prefixed (mirrors the `requiredModelCapabilities` reserved-core + extension idiom). Advisory: this spec assigns no byte-level production semantics to any identifier — it standardizes the identifier so two hosts agree what `pptx` names, not how the bytes are produced."
109
+ },
110
+ "syncOn": {
111
+ "type": "string",
112
+ "enum": ["completion", "approval", "manual"],
113
+ "description": "When the host registers the artifact as durable. Mirrors `node-pack-manifest.schema.json#/$defs/PackNode/properties/artifact/properties/syncOn`. Default `completion`."
114
+ },
115
+ "supportsCheckpoint": {
116
+ "type": "boolean",
117
+ "description": "True if the artifact participates in checkpoint/resume. Mirrors the `PackNode.artifact.supportsCheckpoint` field."
118
+ },
119
+ "versionable": {
120
+ "type": "boolean",
121
+ "description": "True if the host SHOULD retain prior versions of the artifact. Non-normative storage hint."
122
+ },
123
+ "diffable": {
124
+ "type": "boolean",
125
+ "description": "True if the artifact's schema supports structural diffing (informs run-diff tooling per rest-endpoints.md §:diff). Non-normative."
126
+ }
127
+ }
128
+ },
129
+ "RenderingHint": {
130
+ "type": "object",
131
+ "additionalProperties": false,
132
+ "description": "Advisory rendering hint. Reuses the closed vocabulary defined in ai-envelope.md §\"Rendering hints\" (RFC 0055). Advisory only — consumers MUST degrade gracefully and MUST NOT treat this as a validation input. The `card` display value is reserved for envelopes and is excluded here (durable artifacts are not transient chat cards).",
133
+ "properties": {
134
+ "display": {
135
+ "type": "string",
136
+ "enum": ["markdown", "code", "image", "audio", "file"],
137
+ "description": "How a consumer SHOULD render the artifact when it recognizes the value."
138
+ },
139
+ "mimeType": { "type": "string", "maxLength": 255 },
140
+ "lang": { "type": "string", "maxLength": 64, "description": "Language hint for `display: code`." },
141
+ "alt": { "type": "string", "maxLength": 1024, "description": "Accessibility text for image/audio/file." },
142
+ "title": { "type": "string", "maxLength": 255 }
143
+ }
144
+ },
145
+ "Signing": {
146
+ "type": "object",
147
+ "description": "Optional signing metadata. See node-packs.md §signing.",
148
+ "additionalProperties": false,
149
+ "properties": {
150
+ "publicKeyRef": { "type": "string", "description": "Path inside the tarball to the Ed25519 public key (PEM-encoded)." },
151
+ "signatureRef": { "type": "string", "description": "Path to the detached signature over `pack.json`." },
152
+ "method": {
153
+ "type": "string",
154
+ "enum": ["manual", "sigstore"],
155
+ "description": "Signing method. `manual` uses publicKeyRef + signatureRef; `sigstore` uses a Sigstore bundle at `pack.json.sigstore`."
156
+ }
157
+ }
158
+ }
159
+ }
160
+ }