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#
- 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.
- 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.
- 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.
- 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.
- 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 (0x20to0x7e) 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(0755for 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:
| Field | Required | Meaning | ||
|---|---|---|---|---|
adcap | yes | The literal "1.0". | ||
id | yes | publisher/name, lowercase letters, digits and hyphens. MUST start with publisher.id + "/". | ||
version | yes | Semantic version 2.0.0. A pre-release suffix marks a prerelease. | ||
name, summary | yes | Display name (80 characters) and one-line summary (200). | ||
description | no | Longer description, plain text. | ||
license | yes | An SPDX expression, or LicenseRef-* for proprietary terms. | ||
publisher | yes | { id, name?, url? }. | ||
stability | no | stable (default) or experimental. Hosts label experimental capabilities. | ||
categories, keywords | no | Discovery metadata. Categories come from a fixed list; keywords are slugs. | ||
distribution | no | `{ tier: free\ | pro, access: public\ | entitled, entitlement? }` (section 12). |
compat | no | Platforms, host agents and runtimes (section 11). | ||
skills | no | Directories each containing a standard SKILL.md. | ||
tools | no | Executable tools (section 7). | ||
workflows | no | Workflow documents (section 8). | ||
knowledge | no | Searchable knowledge, local or remote (section 9). | ||
assets | no | Images, video, audio, fonts and other files shipped in the package. | ||
resources | no | Remote files referenced by hash (section 9). | ||
adapters | no | Model and inference-backend descriptions (section 10). | ||
dependencies | no | Capability id to semver range. | ||
permissions | no | Everything the capability may ask a host for (section 6). | ||
files | build | Written by the build: every file but the manifest and signature, with SHA-256 and size. | ||
x | no | Extension 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.jsonis 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-v1for packages andarcotheon-catalog-v1for 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:
| id | scope | Meaning | ||
|---|---|---|---|---|
fs:read | capability \ | workspace \ | cache | Read the capability's own files, the user's project folder, or the shared cache. |
fs:write | workspace \ | cache | Write to the project folder or a private cache directory. | |
net:connect | host name (api.example.com, *.example.com, optional :port) | Open network connections. | ||
process:spawn | program name | Start another program. | ||
env:read | variable name | Read one environment variable. | ||
gpu | none | Use the GPU. | ||
secrets | secret name | Receive 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.
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:
{
"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? }:
sourcesare HTTPS mirrors tried in order.sha256andsizepin 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#
dependenciesmaps 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.platformslistsanyoros-archvalues (linux-x64,darwin-arm64,win32-x64...).compat.agentsmaps 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.runtimesrecords 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.
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 }.publisherscarries each publisher's keys and their status. Each capability lists itslateststable version, itslatestPrereleasewhen newer, a summary for search, anddoc: { path, sha256 }pinning its package document. - A client fetches the catalogue, verifies the signature against pinned root keys, rejects a
sequencelower 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. statusfiles markyanked(do not choose automatically) orrevoked(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.