AgentDock

Documentation

The .adcap specification, version 1.0

The normative description of the capability package, manifest, signatures, tool protocol and registry format.

This document specifies version 1.0 of .adcap, the capability package format of Arcotheon. A capability is more than a prompt: it can carry instructions, executable tools, workflows, knowledge, media and references to large remote datasets, together with the permissions it needs and a cryptographic identity.

The words MUST, MUST NOT, SHOULD and MAY are used as in RFC 2119. The reference implementation is the @arcotheon/sdk package in this repository; the machine-readable manifest schema is capability-1.json.

The format is independent of any host application. Nothing here assumes Electron, a particular agent, or a particular operating system.

1. Design rules#

  1. Nothing runs because of a download or an install. The format has no install scripts, hooks or lifecycle commands. Executable components run only when a host explicitly invokes a declared tool.
  2. Everything a capability may touch is declared. Permissions are listed in the manifest, shown to the user in plain language, and granted by the host. A tool may use only the permissions it names.
  3. Identity is content. A package is identified by the digest of its manifest, which lists the hash of every file. Changing a byte changes the identity.
  4. Large things stay out of the package. Datasets, indexes and model weights are resources: referenced by HTTPS URL, pinned by SHA-256, fetched on demand and cached.
  5. Open to other agents. Skills use the standard Agent Skills layout, so the same directory works in any agent that reads SKILL.md. Tools speak a small stdio protocol that any host can implement.

2. The package file#

A .adcap file is a gzip-compressed ustar archive.

  • Entries MUST be regular files. Directories are implied. Symbolic links, hard links, devices and PAX/GNU extension headers MUST be rejected.
  • Paths MUST be relative, use /, be printable ASCII (0x20 to 0x7e) without \, be at most 240 bytes, and contain no empty, . or .. segments. Duplicate paths MUST be rejected.
  • The first entry MUST be capability.json. SIGNATURE.json, if present, MUST be the last entry.
  • A conforming writer sorts the remaining entries by path (byte order), sets modification time, uid and gid to zero, uses mode 0644 (0755 for files marked executable) and writes a gzip header with no name, time or OS information. Two builds of the same source by the same toolchain are then byte-identical.
  • Readers MUST enforce limits on entry count and total expanded size before and while decompressing. The reference limits are 20,000 entries and 512 MiB.

Because the compressor output can differ between zlib versions, the identity of a package is not its archive hash but the manifest digest (section 4). The archive hash is recorded by registries to pin the exact bytes distributed.

3. The manifest#

capability.json is a UTF-8 JSON document validated by the JSON Schema above. Unknown top-level fields are rejected, except under x (section 3.3). Fields:

FieldRequiredMeaning
adcapyesThe literal "1.0".
idyespublisher/name, lowercase letters, digits and hyphens. MUST start with publisher.id + "/".
versionyesSemantic version 2.0.0. A pre-release suffix marks a prerelease.
name, summaryyesDisplay name (80 characters) and one-line summary (200).
descriptionnoLonger description, plain text.
licenseyesAn SPDX expression, or LicenseRef-* for proprietary terms.
publisheryes{ id, name?, url? }.
stabilitynostable (default) or experimental. Hosts label experimental capabilities.
categories, keywordsnoDiscovery metadata. Categories come from a fixed list; keywords are slugs.
distributionno`{ tier: free\pro, access: public\entitled, entitlement? }` (section 12).
compatnoPlatforms, host agents and runtimes (section 11).
skillsnoDirectories each containing a standard SKILL.md.
toolsnoExecutable tools (section 7).
workflowsnoWorkflow documents (section 8).
knowledgenoSearchable knowledge, local or remote (section 9).
assetsnoImages, video, audio, fonts and other files shipped in the package.
resourcesnoRemote files referenced by hash (section 9).
adaptersnoModel and inference-backend descriptions (section 10).
dependenciesnoCapability id to semver range.
permissionsnoEverything the capability may ask a host for (section 6).
filesbuildWritten by the build: every file but the manifest and signature, with SHA-256 and size.
xnoExtension space.

3.1 Skills#

Each skills[].path is a directory containing SKILL.md with front matter holding name and description. The name MUST be lowercase letters, digits and single hyphens, at most 64 characters, and equal the directory name. The description MUST be at most 1024 characters. Builders enforce these rules.

3.2 Semantic checks#

In addition to the schema, a manifest MUST satisfy: every tool permission is declared by the capability; every referenced resource exists; every referenced file is in the package; ids within a list are unique; semver ranges parse; entitled access names an entitlement; fs:write never targets the capability's own directory.

3.3 Extensions#

x carries vendor-specific data keyed by a vendor or publisher name. Consumers MUST ignore keys they do not understand. Nothing under x may change how permissions, integrity or execution work.

4. Identity and integrity#

Canonical JSON. Everything hashed or signed is serialised as canonical JSON: object keys sorted by UTF-16 code unit, no insignificant whitespace, strings as in JSON.stringify, and integers only (floats are not allowed in signed data).

Manifest digest. manifestSha256 is the SHA-256 of the canonical JSON of the complete manifest including files. Because files lists the hash of every other file, the digest pins the whole package.

Verification. A reader MUST, before using any file: check each entry against files (hash and size), reject unlisted and missing files, and recompute the manifest digest. Nothing is extracted or executed before this passes.

5. Signatures#

  • Algorithm: Ed25519. A key is identified by keyId = SHA-256(raw 32-byte public key) in hex; public keys are exchanged as base64.
  • SIGNATURE.json is an envelope: { payload, signatures: [{ keyId, alg: "ed25519", sig }] }, where the payload is { adcap: "1.0", id, version, manifestSha256 }.
  • The signed message is the context string, a newline, and the canonical JSON of the payload. The context is arcotheon-package-v1 for packages and arcotheon-catalog-v1 for registry catalogues, so a signature can never be replayed in the other role.
  • A verifier MUST check that the payload matches the manifest it covers, that at least one signature verifies under a key the verifier trusts for that publisher, and that the key is not revoked.
  • Trust is not in the package. A host obtains publisher keys from a registry catalogue that is itself signed by a pinned registry root key (section 13).

6. Permissions#

A permission is { id, scope?, reason }. The reason is shown to the user. Identifiers:

idscopeMeaning
fs:readcapability \workspace \cacheRead the capability's own files, the user's project folder, or the shared cache.
fs:writeworkspace \cacheWrite to the project folder or a private cache directory.
net:connecthost name (api.example.com, *.example.com, optional :port)Open network connections.
process:spawnprogram nameStart another program.
env:readvariable nameRead one environment variable.
gpunoneUse the GPU.
secretssecret nameReceive one named secret that the host chooses to provide, as an environment variable.

A capability's own directory and the directories of its dependencies are always readable by its tools and are not listed. Remote resources a tool declares are readable through the cache and are shown to the user in the resource list.

A host MUST NOT grant a tool more than the permissions the tool declares. When an update asks for permissions the user has not granted, the host MUST ask again. Enforcement strength depends on the host's sandbox; see the security document for what the reference implementation does and does not enforce.

7. Tools#

A tool is { name, description, runtime, inputSchema, outputSchema?, permissions?, resources?, timeoutMs?, platforms? }.

Runtimes. node and python run entry with the host's interpreter, honouring runtime.version. binary runs entries[platform], a native executable inside the package (the build marks it executable). wasm, mcp and http are reserved in 1.0: a host that does not implement a runtime MUST refuse the tool with a clear message, not ignore it. The reference SDK implements node, python and binary.

Wire protocol. The host starts the program and exchanges one JSON object per line on stdin and stdout.

text
host -> tool   {"type":"call","tool":"name","input":{...},"context":{
                 "capability":"pub/name","version":"1.0.0","dir":"/abs/capability/dir",
                 "workspace":"/abs/or/null","resources":{"id":"/abs/file"},
                 "dependencies":{"pub/dep":"/abs/dir"},"toolDataDir":"/abs/or/null"}}
tool -> host   {"type":"result","output":{...}}
tool -> host   {"type":"error","message":"..."}
tool -> host   {"type":"shard","reqId":1,"resource":"id","path":"shards/x.jsonl"}      (optional)
host -> tool   {"type":"shard.result","reqId":1,"path":"/abs"}  or  {"type":"shard.result","reqId":1,"error":"..."}

The host validates input against inputSchema before starting the tool and output against outputSchema (if any) afterwards, enforces timeoutMs (default 30 s) and an output size limit, and SHOULD run the process in an OS sandbox that exposes only the paths its permissions allow.

Tools never fetch their own datasets: the host materialises declared resources (verified, cached) and passes local paths. This is what lets a tool run without network access.

8. Workflows#

A workflow is a JSON document referenced from workflows:

json
{
  "adcap-workflow": "1.0", "id": "analyze-and-recommend",
  "inputs": { "properties": { "limit": { "default": 4 } } },
  "steps": [
    { "id": "analyze", "tool": "vi_analyze_image", "input": { "path": "{{inputs.path}}" } },
    { "id": "advise", "agent": "Explain {{steps.analyze.output.suggested_query}}." }
  ],
  "output": { "measurements": "{{steps.analyze.output}}" }
}

A tool step calls a tool of this capability (or capability if given). An agent step is an instruction only the host agent can carry out: a runner stops there and returns the interpolated instruction and the results so far. Templates {{path}} read from inputs and steps.<id>.output; a template that is a whole string keeps the value's type, and a key whose value is undefined is dropped. Workflows are data: they cannot execute anything except declared tools.

9. Knowledge and resources#

knowledge entries are markdown, jsonl, sqlite or index, either shipped (path) or remote (resource).

A resource is { id, kind, sources[], sha256, size, access?, license?, lazy?, format? }:

  • sources are HTTPS mirrors tried in order. sha256 and size pin the content; a host MUST reject anything else.
  • Fetched files live in a content-addressed cache and are reused across versions and capabilities.
  • access: "entitled" means the host must obtain authorisation (section 12) before fetching.
  • lazy (default true) means fetch on first use rather than at install.

Shard sets. When format is shardset, the resource is a small JSON shard map { "shards": [{ "path", "sha256", "size", "sources"? }] } (it may carry more fields, such as routing vocabulary, which hosts ignore). The map is pinned by the manifest; each shard is pinned by the map. A tool asks the host for individual shards through the shard message and the host fetches, verifies and caches only those. A shard without sources is found beside each mirror of the map. This is how a capability can reference thousands of media files or embedding shards while a user downloads only what a query needs. The trust chain is manifest, then map, then shard.

10. Adapters#

An adapter describes a model or inference backend a capability can use: { id, kind: model|inference-backend, provider, protocol, endpoint?, model?, resource? }. It is a description: the host decides whether and how to connect, endpoints never contain credentials, and an adapter that needs network access must have a matching net:connect permission.

11. Dependencies and compatibility#

  • dependencies maps ids to semver ranges. Resolution picks the highest versions satisfying all constraints and backtracks on conflict. Prereleases are considered only when requested or named exactly. Yanked versions only when pinned exactly; revoked versions never.
  • compat.platforms lists any or os-arch values (linux-x64, darwin-arm64, win32-x64...). compat.agents maps a host id to a semver range; a host that the capability does not list is incompatible when the capability ships tools, and assumed compatible for skills-only capabilities. compat.runtimes records interpreter requirements.
  • A host MUST refuse to install a version incompatible with its environment, and say why.

12. Distribution metadata#

distribution.tier (free or pro) records the product tier a host should require; the registry only records it, the host enforces it. distribution.access is public (anyone may download) or entitled (the download needs a host-issued authorisation). Catalogue metadata is always public so that capabilities can be discovered; entitled archives and resources are fetched through an authoriser the host supplies, which may return extra headers or a time-limited URL.

13. Registry format#

A registry is a static file tree, so it can live in Git, on a CDN or on any object store.

text
registry/publishers/<id>.json                 publisher and its public keys (authoritative)
registry/entries/<pub>/<name>/<version>.json  immutable version entry
registry/status/<pub>/<name>.json             mutable: deprecation, yanks, revocations
registry/v1/catalog.json                      signed catalogue (served)
registry/v1/packages/<pub>/<name>.json        all versions of one capability (served)
registry/v1/blobs/...                         optional archive mirror (served)
  • A version entry records manifestSha256, the archive's SHA-256 and size, download URLs in preference order, tier and access, compatibility, dependencies, permissions, the contents summary and the changelog. Once published an entry is immutable; republishing different content under the same version MUST fail.
  • The catalogue is a signed envelope over { registry, spec: 1, sequence, generatedAt, publishers, capabilities }. publishers carries each publisher's keys and their status. Each capability lists its latest stable version, its latestPrerelease when newer, a summary for search, and doc: { path, sha256 } pinning its package document.
  • A client fetches the catalogue, verifies the signature against pinned root keys, rejects a sequence lower than the one it has cached (rollback protection), then fetches package documents and checks each against the SHA-256 in the signed catalogue. It downloads archives from the entry's URLs and checks size and SHA-256 before keeping them.
  • status files mark yanked (do not choose automatically) or revoked (never install or run) versions and deprecate capabilities. They are folded into the package documents at build time, so a client learns of them with its next catalogue fetch.

14. Versioning of this specification#

adcap is major.minor. Minor versions only add optional fields. A reader MUST reject a manifest whose major is greater than it supports. Version 1.0 rejects unknown top-level fields, which keeps the format closed until a minor version opens a field deliberately; vendor data belongs under x.