Specification · Normative
CTXPKG v2
Status: Draft · 2026-05-22 · supersedes v1 · schema: /schema/ctxpkg-v2.schema.json
Abstract. .ctxpkg v2 is an open, graph-native package
format for portable AI-agent context. It defines a JSON container with a manifest
(identity, integrity, provenance, signature) and a typed knowledge graph
(nodes, edges, activation), three conformance levels for progressive adoption,
and deterministic graph-merge composition.
1Conventions#
The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY in this document are to be interpreted as described in RFC 2119. JSON terminology follows RFC 8259. All timestamps are ISO 8601 strings in UTC. All hashes are lowercase hex SHA-256 unless stated otherwise.
2File format#
A .ctxpkg file MUST be a single UTF-8 JSON
document with exactly two top-level members:
{
"manifest": { … }, // identity, integrity, provenance, signature
"content": { … } // the knowledge graph and auxiliary content
}
Future minor versions MAY introduce a ZIP-based container
(manifest, graph and content-addressable blobs as separate entries). Readers
SHOULD detect the container by leading bytes:
{ for JSON, PK for ZIP.
3Manifest#
3.1 Required fields
| Field | Type | Description |
|---|---|---|
schema_version | integer | 2 for v2 packages |
name | string | Package name; MAY use the scoped form @scope/name |
version | string | Semantic Versioning 2.0.0 |
description | string | Human-readable summary |
created_at | datetime | ISO 8601 creation timestamp |
integrity | object | SHA-256 hashes and byte size (§8) |
provenance | object | Producing tool, tool version, project hash |
3.2 Optional fields
| Field | Type | Description |
|---|---|---|
conformance_level | integer | 1, 2 or 3 (§5); default 1 |
scope | string | Namespace prefix, e.g. @acme |
signature | object | Ed25519 signature block (§9) |
dependencies | object | Map of scoped name → SemVer range |
optional_dependencies | object | Same shape; failures MUST NOT abort install |
conflicts | string[] | Packages that MUST NOT be co-installed |
graph_summary | object | Node/edge counts, type sets, mean activation, freshness |
compatibility | object | Min reader versions, agent hints, v1_fallback flag |
marketplace | object | Categories, badges, license — registry-facing metadata |
layers | string[] | Legacy v1 layer names for backward compatibility |
4Knowledge graph#
The graph is stored at content.context_graph and
MUST declare "format": "ctxpkg-graph-v2":
{
"format": "ctxpkg-graph-v2",
"nodes": [ … ],
"edges": [ … ]
} 4.1 Node schema
| Field | Type | Req. | Description |
|---|---|---|---|
id | string | yes | Unique within the package |
type | string | yes | Node type (§4.2) |
content | string | yes | The knowledge payload |
activation | number | no | Activation energy 0.0–1.0; default 1.0 |
category | string | no | Classification category |
source | string | no | Origin session or system |
created_at | datetime | no | Creation timestamp |
decay_half_life_days | integer | no | Temporal decay half-life |
blob_ref | string | no | Content-addressable blob reference |
file_path / line_start / line_end | — | no | Source code anchor |
confidence | number | no | 0.0–1.0 |
supersedes | string | no | ID of the node this one replaces |
4.2 Node-type taxonomy (extensible registry)
| Category | Types |
|---|---|
| Semantic | fact pattern insight convention |
| Memory | gotcha decision finding episode |
| Structure | code_symbol code_file code_module code_function code_class |
| Session | session task evidence procedure |
| Governance | policy overlay profile slo |
| Event | bus_event handoff tool_call |
| Custom | Any string — readers MUST preserve unknown types |
4.3 Edge schema
| Field | Type | Req. | Description |
|---|---|---|---|
from / to | string | yes | Node IDs within the package |
type | string | yes | Edge type (§4.4) |
weight | number | no | Default 1.0 |
coactivations | integer | no | Hebbian co-activation counter |
metadata | string | no | Free-form annotation |
4.4 Edge-type taxonomy (extensible registry)
| Category | Types |
|---|---|
| Semantic | supports contradicts supersedes elaborates |
| Causal | decided_by caused_by followed_by tested_by |
| Structural | imports calls exports contains related_to |
| Dependency | depends_on extends conflicts_with |
| Hebbian | co_activated (with weight + coactivations) |
5Conformance levels#
Three levels enable progressive adoption. A reader claiming level N MUST also satisfy all lower levels.
| Level | Name | Requirements | Typical implementers |
|---|---|---|---|
| 1 | Basic | Parse manifest + flat node list (id, type, content); verify integrity; merge nodes into agent context. Edges MAY be ignored. | Editors, CLIs, any JSON-capable tool |
| 2 | Graph | Typed nodes + edges; SemVer dependency resolution; graph-merge composition with conflict detection (§6). | Context engines, MCP servers |
| 3 | Cognitive | Activation energy honored under token budgets; Hebbian weights and co-activation counters; temporal decay; full state round-trip. | Reference implementation (lean-ctx) |
See Conformance for claim rules and the test checklist.
6Composition (graph merge)#
When multiple packages are installed, a Level 2+ reader MUST compose them deterministically:
- Union — all nodes, identity by
id; identical IDs from different packages reconcile to one node. - Edge merge — duplicate edges (same
from,to,type) merge; weights average (midpoint). - Conflict detection — nodes connected by
contradictsedges MUST surface as warnings; readers MUST NOT silently drop either side. - Activation propagation — new cross-package edges MAY raise activation of connected nodes.
- Supersedes resolution — if node X
supersedesY, Y's activation MUST be set to0.0(deactivated, not deleted).
7Scopes & namespaces#
Scoped names take the form @scope/name. Scope and name
MUST match [a-z0-9][a-z0-9_-]* (scope additionally
allows no leading underscore). Names without @ are unscoped and
SHOULD be reserved for local development. Registries
MUST enforce scope ownership for publishing.
8Integrity#
content_hash = hex( SHA256(content_json_bytes) )
sha256 = hex( SHA256(utf8("{name}:{version}:{content_hash}")) )
Both digests are encoded as lowercase hexadecimal (64 characters).
content_json_bytes are the content member serialized as
compact JSON: no insignificant whitespace, object members in the order
defined by the schema, absent optional members omitted
entirely (never null).
Readers MUST verify against the document text:
take the exact character range of the content member as it appears in
the file, remove insignificant whitespace outside string literals, hash the
resulting UTF-8 bytes, and reject the package on any mismatch. Readers
MUST NOT verify by re-serializing parsed values — number
formatting is not preserved across languages (a writer's 1.0 would
re-serialize as 1 in JavaScript and break the hash).
9Signing#
Signatures use Ed25519 (RFC 8032). The signed message is the 64 ASCII characters of the lowercase-hex digest — not the raw 32 bytes:
message = hex( SHA256(utf8("ctxpkg-sign-v1:{name}:{version}:{integrity.sha256}")) )
signature.value = hex( Ed25519-sign(message_ascii_bytes) )
The manifest's signature object carries algorithm
("ed25519"), the signer's public_key (32 bytes,
lowercase hex, 64 characters) and the signature value (64 bytes,
lowercase hex, 128 characters). Verifiers MUST check the
signature against the recomputed integrity hash — signing therefore covers
the full content transitively. Registries SHOULD require
signatures for publishing and MUST record the public key
they verified against. The test vectors pin
this construction: valid-level2-signed.ctxpkg must verify,
invalid-signature.ctxpkg must not.
10v1 compatibility#
v1 packages (five static layers) map losslessly into a v2 graph without edges:
| v1 source | v2 mapping |
|---|---|
knowledge.facts[] | nodes of type fact, activation 1.0 |
knowledge.patterns[] | nodes of type pattern, activation 1.0 |
gotchas[] | nodes of type gotcha, activation 1.0 |
graph.nodes/edges | nodes/edges with type mapping |
session | one node of type session with blob_ref |
A v2 package with compatibility.v1_fallback: true declares it is
readable as v1 (edges and activation ignored).
11Security considerations#
- Context injection. Package content steers agent behavior. Readers MUST verify integrity and SHOULD verify signatures before loading any node.
- Secret leakage. Writers SHOULD scan content for credential-shaped strings before export. Registries SHOULD reject publishes containing high-confidence secrets (the public registry rejects with HTTP 422).
- Size limits. Readers SHOULD enforce size ceilings before parsing untrusted files.
- Unknown types. Unknown node/edge types MUST be preserved on round-trip but MAY be excluded from context assembly.
12Ecosystem positioning#
| Standard | Layer | Relation |
|---|---|---|
| MCP | Tool invocation (runtime) | Complementary — .ctxpkg payloads travel over MCP unchanged |
| Agent Skills | Procedural instructions | Complementary — skills say how to act, CTXPKG says what is true |
| A2A | Agent-to-agent messaging | Complementary — packages are valid hand-off payloads |
| CTXPKG | Declarative knowledge interchange | This specification |