SPB Git

Repository Public MIT

publishing.md 11.5 KB


# title: Publishing your first artifact description: Namespaces, the agent-registry.json manifest, limits, what blocks a release and what is only advisory. order: 20 section: Publish

# Publishing your first artifact

# Before you start

  1. 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.
  2. 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.
  3. 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.

text
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

json
{
  "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
examples no Up to 8 screenshots of the package in use. See below

Compatibility entries are your claims. They are displayed as unverified.

# The mcp block

json
{
  "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.

# The examples list

Screenshots that show the package being used in a real client. They travel inside the release archive, so they are versioned, checksummed and immutable like every other file. The artifact page shows them in an Examples section, grouped by client, right after the installation instructions.

json
{
  "examples": [
    {
      "title": "Checking a manuscript in Claude Code",
      "client": "claude-code",
      "image": "examples/claude-code-check.png",
      "alt": "Claude Code terminal: the skill lists two citations with no bibliography entry",
      "prompt": "Check the citations of paper.md with the citation-check skill.",
      "caption": "Run on the sample manuscript shipped in the package.",
      "capturedAt": "2026-11-10"
    }
  ]
}
Field Required Rules
title yes Up to 120 characters
client yes claude-code, codex, cursor or other
image yes Relative path of a file in the package. .png, .jpg, .jpeg or .webp; the content must really be that format; at most 1.5 MiB and 8192 pixels on a side; each image listed once
alt yes 1–300 characters describing what the screenshot shows, for readers who cannot see it
prompt no The prompt that was given, up to 2000 characters. Shown as plain text with a copy button
caption no Up to 500 characters
capturedAt no Date of the capture, YYYY-MM-DD

SVG, GIF and any other format are refused: only raster images whose header the registry can check are served. Images are served by the registry from the archive at /api/v1/artifacts/{namespace}/{slug}/versions/{version}/media/{path}, and only the paths listed here; the page never loads them from another site. Images inside a README are still not rendered.

Before you publish a screenshot, look at it the way a stranger would: crop out other windows, account names, e-mail addresses, home-directory paths, tokens and private file names. A release cannot be edited afterwards, only revoked. The page states that screenshots are supplied by the publisher and are not verified by the registry.

# 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)
Example screenshots 8 per release, 1.5 MiB each, 8192 px on a side

# Validate, pack, publish

bash
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

text
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/, .env and 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.
  • An examples entry whose image is missing, has an unsafe path, is not .png/.jpg/.jpeg/.webp, is not really an image of that format, is larger than 1.5 MiB, or is listed twice.
  • 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.

Files main
Menu

Theme