Publish
Publishing your first artifact
Namespaces, the agent-registry.json manifest, limits, what blocks a release and what is only advisory.
Before you start
- An account and a namespace. In this first version the operator creates both. Write to contact@spboucher.ai with the namespace you would like. Self-service sign-up is planned.
- A token, if you publish from the command line or an agent. Create one in the dashboard under Tokens (you will be asked for your password again), or see Publishing from Claude Code.
- A package directory containing only what you intend to make public.
The package
A package is a directory. The registry adds one file to whatever your artifact already is: agent-registry.json at the root. It does not replace SKILL.md, package.json, pyproject.toml or an MCP configuration; those stay as they are.
citation-check/
├── agent-registry.json registry manifest (required)
├── SKILL.md required for type "skill"
├── README.md required for every type except "skill"
├── LICENSE recommended
├── CHANGELOG.md recommended
├── references/…
└── scripts/…
Create a skeleton with skills init ./citation-check --type skill --name @yourns/citation-check.
Manifest reference
{
"schemaVersion": "1.0",
"name": "@yourns/citation-check",
"version": "1.0.0",
"type": "skill",
"description": "Checks that every citation in a manuscript resolves to a reference.",
"license": "MIT",
"repository": "https://example.org/you/citation-check",
"entrypoint": "SKILL.md",
"keywords": ["academic-writing", "citations"],
"compatibility": ["claude-code", "generic-agent-skills"],
"permissions": ["filesystem:read"],
"dependencies": []
}
Unknown keys are rejected. The file is limited to 64 KiB.
| Field | Required | Rules |
|---|---|---|
schemaVersion | yes | "1.0" |
name | yes | @namespace/slug. Namespace: up to 39 lowercase letters, digits and single hyphens. Slug: up to 64, same alphabet |
version | yes | Strict semantic version, no build metadata: 1.2.0, 2.0.0-rc.1 |
type | yes | skill, mcp-server, agent, prompt-pack, workflow, connector, hook, bundle, eval-kit, template |
description | yes | 10–300 characters. Becomes the listing summary |
license | yes | SPDX identifier preferred (MIT, Apache-2.0, CC-BY-4.0, …). An unrecognised value is accepted with a note |
repository, homepage, issues | no | http(s) URLs, up to 500 characters |
entrypoint | no | Relative path that must exist in the package. For a skill it must be SKILL.md |
keywords | no | Up to 12 tags, lowercase letters, digits, hyphens, up to 32 characters each |
compatibility | no | Up to 16 entries. Each is a client id (claude-code, codex, cursor, generic-agent-skills, generic-mcp) or an object { "client", "minVersion"?, "platform"?: "any"|"macos"|"linux"|"windows", "installStrategy"?: "copy-directory"|"mcp-config"|"manual" } |
permissions | no | Any of filesystem:read, filesystem:write, network, shell, env, mcp, browser, credentials |
dependencies | no | Up to 64 entries { "name": "@ns/slug", "version": "<semver range>", "optional"?: true } |
capabilities | no | Override the derived labels: downloadable, installable, remote-endpoint, documentation-only, source-linked, executable |
mcp | for mcp-server | See below |
sourceCommit | no | Hexadecimal commit id, 7–64 characters |
Compatibility entries are your claims. They are displayed as unverified.
The mcp block
{
"type": "mcp-server",
"mcp": {
"transport": "stdio",
"command": "node",
"args": ["server.mjs"],
"env": [{ "name": "ECHO_PREFIX", "description": "Text prepended to replies", "required": false, "secret": false }],
"tools": [{ "name": "echo", "description": "Returns its input" }]
}
}
| Field | Rules |
|---|---|
transport | stdio or streamable-http |
command, args | Required for stdio. The command users run locally. Up to 32 arguments |
url | Required for streamable-http. The endpoint you operate |
env | Up to 32 variables: name (uppercase, digits, underscore), optional description, required (default true), secret |
tools | Up to 200 { name, description? } entries for display |
Never put a secret value in the manifest. Declare the variable name; users set the value locally.
Rules by type
| Type | Additional requirements |
|---|---|
skill | SKILL.md at the root with valid frontmatter; its name must equal the slug; description 1–1024 characters |
mcp-server | An mcp block and a README.md |
bundle | At least one dependency, each pinned to an exact version |
| all others | A README.md |
Limits
| Limit | Value |
|---|---|
| Archive (compressed) | 20 MiB |
| Unpacked total | 64 MiB |
| Single file | 16 MiB |
| Files | 2000 |
| Path length / depth | 240 characters / 16 levels |
| In-browser preview per file | 256 KiB (larger or binary files are listed but not previewed) |
Validate, pack, publish
skills validate ./citation-check # same checks the server runs, locally
skills publish ./citation-check --visibility public --dry-run # full report, uploads nothing
skills publish ./citation-check --visibility public
skills pack and skills publish skip .git, node_modules, .DS_Store, __pycache__, .venv, .idea, .vscode and anything matched by a .skillsignore file. Symbolic links are never followed or published. The archive is deterministic: packing the same files twice gives the same SHA-256.
The dry-run report lists the target, version, visibility, every file with its size, skipped files, declared permissions, findings, and the archive checksum. Read it. Then publish.
Making an artifact public for the first time asks for explicit confirmation. So does any later change of visibility.
What happens on the server
uploaded ──> validating ──> rejected nothing is stored or published
└──> security review ──> published
└──> quarantined ──> published (moderator approves)
└──> revoked (moderator rejects)
The archive is parsed in memory and inspected statically. It is never extracted to disk and nothing in it is executed.
Blocking: the release is refused
- Unsafe paths: absolute,
.., backslashes, control characters, case-insensitive duplicates. - Links, devices or other special entries in the archive; corrupt or oversized archives.
- Forbidden files:
.git/,node_modules/,.envand variants (except.env.example,.env.sample,.env.template),.npmrc,.netrc,.ssh/,.aws/, private keys,*.pem,*.p12,*.pfx. - Manifest errors; a manifest whose name, version or type differs from the artifact and version you are publishing to.
- Type rules above.
- A required dependency that does not exist, or has no published version satisfying the range.
- Recognisable credentials: private keys, AWS, GitHub, Anthropic, OpenAI, Slack, Google, Stripe, registry tokens, JSON Web Tokens. Remove the secret and rotate it; it has already left your machine.
The response lists each finding with a code, file and line. Secrets are never echoed back.
Advisory: published, and shown on the release page
Hidden files, executables, scripts, compiled binaries, scripts that use the network or spawn processes, sudo, hard-coded credential-looking values, undeclared network or shell permissions, an unrecognised licence, a missing LICENSE, CHANGELOG or repository link, frontmatter fields outside the open specification.
Quarantine: held for a moderator
Download-and-execute pipelines (curl … | sh), decoded-and-executed payloads, recursive deletion of home or root paths, evaluation of remotely fetched code, reads of local credential stores, text that tells an agent to override its instructions, hide behaviour from the user or transmit credentials, and bidirectional control characters. A quarantined release is invisible to the public until a moderator approves or rejects it. If your package legitimately needs one of these, explain it in the README; it speeds up review.
After publishing
- The release is immutable. To fix something, publish a new version.
- You can edit release notes and listing metadata (summary, links, keywords, visibility). Listing metadata is refreshed from the manifest each time a new latest version is published.
- You can deprecate an artifact with a reason, and revoke a version that turned out to be harmful. See Versioning.
Responsible publication
Publish only what you have the right to publish, under a licence you state. Do not include private data, other people's proprietary material or credentials. Declare the permissions your package needs. See the Acceptable use policy.