Sandboxed Skill Package Registry¶
Status: Draft proposal; not implemented or scheduled
Audience: Maintainers, deployment operators, and builders
Last updated: 2026-07-23
This proposal makes Cognition a bounded registry and runtime for executable skill packages. A builder publishes scope-bound skills and attaches their names to an Agent. Cognition stores immutable revisions, pins the revisions selected for each run, and transfers only those packages into that run's sandbox.
The design is deliberately narrower than a skills platform. Cognition does not own a marketplace, publishing interface, tenant administration, authorization policy, dependency builds, or credential brokering. Those remain builder and deployment responsibilities.
Decision summary¶
- Select one skill package backend for each Cognition deployment.
- Keep skill metadata in the Config Registry and package bytes behind a
SkillPackageStore. - Preserve
Agent.skills: list[str]; resolve each name to its current immutable revision when a run starts. - Persist a digest-pinned manifest for the run before provisioning its sandbox.
- Transfer packages through the sandbox provider's file-transfer API and execute scripts only inside the sandbox.
- Treat
/skills/as read-only. Scripts write results to a sandbox output path; Cognition collects selected results into scoped artifacts. - Keep executable custom Tool CRUD and host-executed integrations outside this runtime option.
Current state and problem¶
Today a SkillDefinition stores a path and optional SKILL.md content in the
Config Registry. The Skill API creates or replaces one mutable record, and
ConfigRegistrySkillsBackend exposes attached skills beneath
/skills/api/. create_cognition_agent routes that path through a Deep Agents
CompositeBackend while using the selected sandbox as the default backend.
This supports progressive disclosure of SKILL.md, but it does not store
sibling scripts, references, or assets as one package. A script held outside a
remote sandbox cannot be executed there until application code transfers it.
The current graph cache also identifies skills by attached names rather than
resolved package digests and can retain the backend captured when the graph was
compiled.
Deep Agents already provides the intended primitives:
- Backends route filesystem paths through state, store, filesystem, sandbox, or composite adapters.
- Skills may include scripts and supporting resources, and recommends middleware to synchronize externally stored skills into a sandbox.
- Sandboxes
distinguish agent filesystem tools from trusted application file-transfer
APIs such as
upload_files.
The proposed registry adds the missing package, revision, scope, and materialization contracts around those primitives.
Boundary: registry, not control plane¶
| Cognition owns | Builder or deployment owns |
|---|---|
| Scope-aware package CRUD | Authentication and authorization decisions |
| Immutable revisions and digests | Tenant, role, entitlement, and sharing policy |
| Agent-to-skill attachment resolution | Publishing and discovery user experience |
| Per-run manifests | Skill review and promotion workflow |
| Sandbox materialization and execution evidence | Sandbox and egress policy selection |
| Runtime isolation enforcement | External-service credentials and gateways |
Cognition accepts builder-authorized effective_scope from trusted ingress. It
does not let a model choose scope, storage locations, backend credentials, or
sandbox identity. Sharing a package across scopes is a builder operation that
publishes or projects it into each authorized scope; registry lookup does not
fall back to broader tenant records.
Proposed component model¶
C4Component
title Sandboxed skill package registry
Person(builder, "Builder application", "Authenticates users, authorizes scope, manages Agents and skills")
System_Ext(gateway, "Trusted ingress", "Authenticates requests and supplies effective_scope")
Container_Boundary(cognition, "Cognition server") {
Component(skill_api, "Skill API", "FastAPI adapter", "Accepts scope-bound package CRUD")
Component(agent_api, "Agent and Run APIs", "FastAPI adapters", "Attach skill names and start runs")
Component(registry, "SkillRegistryService", "Application service", "Validates packages and manages immutable revisions")
Component(resolver, "Run skill resolver", "Runtime service", "Resolves current revisions and persists a pinned manifest")
Component(materializer, "SkillSandboxMaterializer", "Deep Agents middleware", "Transfers and verifies packages before execution")
Component(router, "Runtime backend router", "Deep Agents CompositeBackend", "Routes skill reads and current sandbox operations")
Component(collector, "SandboxArtifactCollector", "Runtime hook", "Retrieves declared outputs after execution")
}
ContainerDb(config, "Config Registry", "Skill metadata, current pointers, Agent definitions")
ContainerDb(packages, "SkillPackageStore", "Immutable, scope-bound package contents")
ContainerDb(state, "Runtime Store", "Run manifests, events, and checkpoints")
ContainerDb(artifacts, "Artifact Store", "Scoped script outputs")
System_Ext(sandbox, "Sandbox", "Isolated filesystem and shell")
System_Ext(egress, "Builder-operated egress gateway", "Policy enforcement and credential injection")
Rel(builder, gateway, "Calls")
Rel(gateway, skill_api, "Forwards with trusted scope")
Rel(gateway, agent_api, "Forwards with trusted scope")
Rel(skill_api, registry, "Publishes and manages packages")
Rel(registry, config, "Stores metadata and revision pointers")
Rel(registry, packages, "Stores immutable contents")
Rel(agent_api, resolver, "Starts scoped run")
Rel(resolver, config, "Reads Agent and exact-scope skills")
Rel(resolver, state, "Pins manifest")
Rel(resolver, materializer, "Supplies manifest")
Rel(materializer, packages, "Fetches verified contents")
Rel(materializer, sandbox, "Uploads through provider API")
Rel(router, packages, "Reads pinned package files")
Rel(router, sandbox, "Routes filesystem and execute")
Rel(collector, sandbox, "Downloads declared outputs")
Rel(collector, artifacts, "Persists scope-bound results")
Rel(sandbox, egress, "Calls approved aliases")
Package and API contract¶
A package follows the Deep Agents skill layout:
ticket-analysis/
├── SKILL.md
├── scripts/
│ └── analyze.py
├── references/
│ └── fields.md
└── assets/
└── output-schema.json
The proposed create and update input adds files: dict[str, str]. The existing
content field remains shorthand for {"SKILL.md": content}. Existing Agent
definitions continue to attach skills by name:
{
"name": "ticket-analysis",
"files": {
"SKILL.md": "---\nname: ticket-analysis\n...",
"scripts/analyze.py": "import json\n..."
}
}
Package responses add:
| Field | Meaning |
|---|---|
revision |
Opaque immutable revision identifier |
digest |
SHA-256 digest of the canonical package |
file_count |
Number of package files |
size_bytes |
Total UTF-8 byte count |
validation_status |
Package validation result |
Package validation requires SKILL.md, valid frontmatter, safe relative POSIX
paths, unique normalized paths, and UTF-8 text. It rejects absolute paths,
./.. traversal, symlinks, unsupported encodings, and reserved runtime
paths. Binary inputs remain scoped artifacts referenced by scripts rather than
package contents.
Canonicalization sorts normalized paths and hashes each path, byte length, and UTF-8 content. A content change creates a new revision and atomically advances the skill's current pointer. Metadata-only enablement changes need not create a new package revision. Deleting a skill removes its current availability but retains revisions referenced by run manifests until retention permits garbage collection.
Registration validates and stores files but never imports, compiles, or executes scripts.
Package backend configuration¶
The deployment operator selects one backend. Agent and Skill requests cannot override it.
| Backend | Intended use | Behavior |
|---|---|---|
config_registry |
Compatibility and simple deployments | Stores package content with existing durable configuration |
s3 |
Multi-replica production deployments | Stores immutable objects in an operator-owned bucket; metadata remains in the Config Registry |
filesystem |
Explicit standalone development | Stores packages under one configured server path; never exposes that path to the agent |
Proposed settings:
COGNITION_SKILLS_BACKEND=config_registry
COGNITION_SKILLS_FILESYSTEM_ROOT=/var/lib/cognition/skills
COGNITION_SKILLS_S3_BUCKET=cognition-skills
COGNITION_SKILLS_S3_PREFIX=packages/
COGNITION_SKILLS_S3_REGION=us-east-1
Only settings for the selected adapter apply. S3 uses ambient workload identity; the proposal adds no access-key fields or secret-resolution surface.
SkillPackageStore is content-oriented rather than agent-facing. Its minimum
operations put, fetch, verify existence, and delete an immutable bundle by
trusted scope and digest. A separate read-only Deep Agents backend adapts
resolved packages to /skills/.
The CompositeBackend routes agent reads under /skills/ to that read-only
adapter and routes execute to its default sandbox. The materializer uploads
the same paths through the current sandbox backend directly—not through the
composite route—so the shell can execute the sandbox copy without granting
write access to registry storage.
Builder publication flow¶
sequenceDiagram
actor Builder
participant Gateway as Trusted ingress
participant API as Skill API
participant Registry as SkillRegistryService
participant Catalog as Config Registry
participant Store as SkillPackageStore
participant Agents as Agent API
Builder->>Gateway: Publish package
Gateway->>API: Request plus effective_scope
API->>Registry: Validate and canonicalize files
Registry->>Registry: Compute revision and digest
Registry->>Store: Put immutable scope-bound package
Store-->>Registry: Stored
Registry->>Catalog: Commit metadata and current pointer
Catalog-->>API: Revision metadata
API-->>Gateway: Package response
Gateway-->>Builder: Package response
Builder->>Gateway: Attach skill name to Agent
Gateway->>Agents: Scoped Agent update
Agents->>Catalog: Persist attachment
Catalog-->>Agents: Updated Agent
Agents-->>Gateway: Updated Agent
Gateway-->>Builder: Updated Agent
If the package write succeeds but the metadata transaction fails, the object is an unreferenced candidate for garbage collection. The current pointer changes only after package persistence succeeds.
Per-sandbox run lifecycle¶
sequenceDiagram
actor Builder
participant API as Run API
participant Resolver as Run skill resolver
participant Catalog as Config Registry
participant State as Runtime Store
participant Manager as Sandbox manager
participant Packages as SkillPackageStore
participant Sync as SkillSandboxMaterializer
participant Runtime as Agent runtime
participant Box as Sandbox
participant Agent as Deep Agent
participant Collector as SandboxArtifactCollector
participant Artifacts as Artifact Store
Builder->>API: Start run with trusted scope
API->>Resolver: Resolve Agent and skills
Resolver->>Catalog: Read exact-scope current revisions
Catalog-->>Resolver: Revision metadata
Resolver->>State: Persist digest-pinned manifest
Resolver->>Manager: Provision sandbox
Manager-->>Sync: Current sandbox handle
Sync->>Packages: Fetch manifest digests
Packages-->>Sync: Package bytes
Sync->>Box: Upload files through provider API
Sync->>Box: Verify digests and seal /skills
alt Materialization succeeds
Sync-->>Runtime: Materialization complete
Runtime->>Agent: Invoke graph with pinned manifest
Agent->>Box: Read SKILL.md and execute scripts
Box-->>Agent: Script results
Agent-->>Runtime: Run result
Runtime->>Collector: Collect declared outputs
Collector->>Box: Download output files
Box-->>Collector: Output bytes
Collector->>Artifacts: Persist with trusted scope
else Missing, invalid, or mismatched package
Sync->>State: Record failure before model execution
Sync->>Manager: Terminate sandbox
end
There is no after_agent write-back for /skills/. A run may alter its private
sandbox copy only if an adapter cannot enforce read-only files; it can never
mutate the immutable registry revision.
Multi-tenant isolation¶
flowchart TB
A["Builder request<br/>effective_scope A"] --> RA["Exact-scope registry namespace A"]
B["Builder request<br/>effective_scope B"] --> RB["Exact-scope registry namespace B"]
RA --> MA["Pinned manifest<br/>scope A + Agent revision + digests"]
RB --> MB["Pinned manifest<br/>scope B + Agent revision + digests"]
MA --> CA["Cache identity A"]
MB --> CB["Cache identity B"]
CA --> SA["Sandbox A<br/>authorized packages only"]
CB --> SB["Sandbox B<br/>authorized packages only"]
PA["Package objects<br/>scope fingerprint A"] --> SA
PB["Package objects<br/>scope fingerprint B"] --> SB
SA --> AA["Scoped artifacts A"]
SB --> AB["Scoped artifacts B"]
SA -. "no route" .-> RB
SB -. "no route" .-> RA
Package keys, manifests, cache identities, logs, and lifecycle events include a canonical scope fingerprint. The fingerprint is derived from sorted trusted scope entries; model input cannot supply or override it. Package access uses exact scope rather than hierarchical fallback.
A graph cache key includes the scope fingerprint, Agent revision, package backend identity, and ordered package digests. The compiled graph resolves the current sandbox from trusted run context so a cache hit cannot retain another session's backend handle.
General-purpose subagents inherit the parent's pinned package manifest. Custom subagents receive only their explicitly resolved authorized subset.
Sandbox-only operating model¶
Conforming Agents use Deep Agents filesystem tools and execute against the
selected sandbox. Registry Python tools, programmatic host tools, host-side web
utilities, package inspection, and host-side Model Context Protocol (MCP)
clients are not bound in this mode.
External capabilities are packaged as scripts or preinstalled command-line clients. Scripts should accept JSON files or standard input, return structured standard output or artifacts, and avoid interpolating model text into shell commands. Dependencies belong in the approved sandbox image.
Network access is denied by default or constrained by the sandbox profile. Authenticated calls use stable proxy aliases operated by the builder. The proxy receives trusted scope and correlation separately, applies policy, and injects credentials outside the sandbox. Raw provider credentials never enter the package or sandbox.
Filesystem permissions help keep /skills/ read-only, but arbitrary
execute commands are controlled by the sandbox's process, kernel, filesystem,
network, and resource boundaries—not by path validation alone.
Failures and observability¶
| Condition | Required behavior |
|---|---|
| Scope mismatch or invisible skill | Deny without revealing another scope's metadata |
| Package store unavailable | Retry within policy, then fail before model execution |
| Missing object or digest mismatch | Emit materialization failure and terminate the sandbox |
| Partial upload | Discard the sandbox; never start the graph |
| Skill updated during a run | Continue using the pinned revision |
| Cache hit | Bind the current run's sandbox and manifest |
| Egress denial | Return a structured script failure and emit an attributed event |
| Teardown failure | Emit an operational error with sandbox and run correlation |
Metrics should cover publication failures, materialization latency and bytes, digest failures, cache hits by backend, sandbox cleanup, and denied cross-scope access without placing raw scope values in high-cardinality labels.
Complexity¶
| Area | Complexity |
|---|---|
| Package models, validation, and immutable revisions | 6/10 |
| Configurable package-store abstraction | 6/10 |
| S3 and compatibility adapters | 6/10 |
| Sandbox materialization and verification | 7/10 |
| Scope-safe runtime routing and caching | 8/10 |
| Removing host-executed paths from this mode | 6/10 |
| Controlled web and external-service access | 8/10 |
| Generic builder integration | 4/10 |
| Overall | 7.5/10 — Large |
Estimated implementation effort is 5–8 Cognition engineer-weeks plus 1–2 weeks for builder integration and hosted sandbox validation.
Migration and adoption¶
- Introduce package metadata and the
SkillPackageStorebehind current Skill CRUD. Convert each existing API skill into an initial immutable revision; preservecontentand Agent skill-name attachments. - Add the
config_registryadapter and digest-pinned run manifests without changing the selected sandbox. - Add sandbox materialization, read-only package paths, dynamic backend routing, events, and negative isolation tests.
- Add S3 and explicit development filesystem adapters.
- Enable sandbox-only resolution for selected deployments, then disable incompatible host-executed extensions there.
Migration is idempotent. Existing file-managed skills must be imported into the
configured package backend or retained only in explicitly unsafe development
deployments. A backend cutover copies and verifies every live revision before
the operator changes COGNITION_SKILLS_BACKEND; rollback requires the previous
backend to remain complete until the cutover observation window closes.
Implementation requires an accepted ADR, a full architectural ROADMAP entry, and updates to the code-derived architecture. This proposal intentionally names no target release.
Acceptance criteria¶
- Agents cannot access Cognition host files, processes, environment variables, package-store credentials, or storage locations.
- Skill scripts and side effects execute only in the assigned sandbox.
- Every package operation and run manifest enforces exact trusted
effective_scope. - Runs cannot observe skill updates after their manifest is pinned.
- Cross-scope reads, cache reuse, and sandbox reuse fail closed.
- Invalid paths, missing packages, digest mismatches, and incomplete uploads prevent model execution.
- General and custom subagents receive only the packages defined by their inheritance rules.
- Unsafe filesystem storage and local execution require explicit development configuration and emit observable warnings.
- Hosted sandbox tests prove upload, execution, controlled egress, artifact retrieval, teardown, and absence of cross-run leakage.