# Publisher Workflow

This page documents the current CAP publisher path. In the prototype, publishing means compiling a local `capability.json`, running local preflight checks, and writing the package into a filesystem registry JSON file. Remote marketplace publish, publisher auth, namespace verification services, hosted artifact upload, payment metadata enforcement, and sandbox review workers are not implemented yet.

Use this workflow when you are developing a package locally or contributing a package record to a checked-in CAP registry.

## Quick Start

From the package repo:

```bash
cap init acme/my-tool
cap preview --json
cap review --run-trials --json
cap publish --local --registry registry/packages.json --json
```

From this repo during development:

```bash
node src/cap.js init acme/my-tool
node src/cap.js preview --json
node src/cap.js review --run-trials --json
node src/cap.js publish --local --registry registry/packages.json --json
```

Before committing, review the manifest and registry diff:

```bash
git diff capability.json registry/packages.json
```

## Package Shape

The local publisher expects one manifest file, `capability.json` by default. A package should have:

- a stable package id shaped like `namespace/name`
- a version string
- a short summary
- at least one task in `tasks`, `bestFor`, `best_for`, or `capabilityCard.bestFor`
- at least one declared command/bin
- at least one safe trial command
- install metadata for `local-bin` or `single-file-url`

For autonomous agent use, add:

- structured JSON output for inspection and dry-run commands
- a skill with accurate frontmatter and operating guidance
- MCP tools for repeated or state-changing use
- explicit filesystem, network, secret, env, and spend permissions
- safe trials that do not require real credentials, live writes, or payment

## Minimal Local-Bin Manifest

```json
{
  "schema": "cap-manifest.v0",
  "id": "acme/my-tool",
  "name": "My Tool",
  "version": "0.1.0",
  "kind": "local-tool",
  "summary": "Inspect and repair ExampleService config files.",
  "description": "Agent-friendly CLI for ExampleService maintenance.",
  "keywords": ["exampleservice", "config"],
  "tasks": [
    "inspect ExampleService config",
    "repair ExampleService config"
  ],
  "commands": [
    {
      "name": "my-tool",
      "path": "bin/my-tool.js",
      "safeArgs": ["--help", "doctor --json"]
    }
  ],
  "safeTrials": [
    {
      "command": "my-tool --help",
      "writes": [],
      "network": [],
      "description": "Print help without reading credentials or changing state."
    }
  ],
  "install": {
    "backend": "local-bin",
    "source": {
      "path": "."
    },
    "bins": {
      "my-tool": "bin/my-tool.js"
    }
  },
  "permissions": {
    "filesystem": ["workspace:read"],
    "network": [],
    "secrets": [],
    "env": [],
    "spend": []
  },
  "skill": "skills/my-tool/SKILL.md",
  "mcp": {
    "tools": ["my_tool_report"]
  },
  "structuredOutput": true,
  "publisher": {
    "verified": true,
    "identity": "github:acme",
    "method": "github-org"
  }
}
```

`local-bin` computes a digest from the declared bin files and publishes a registry source path relative to the registry file. If the registry lives at `registry/packages.json` and the package source is the repo root, the published source path is usually `..`.

## Single-File URL Manifest

Use `single-file-url` when the installable artifact is one executable file:

```json
{
  "schema": "cap-manifest.v0",
  "id": "acme/downloaded-tool",
  "name": "Downloaded Tool",
  "version": "1.0.0",
  "kind": "local-tool",
  "summary": "Run one downloaded executable.",
  "tasks": ["run downloaded tool"],
  "commands": [
    {
      "name": "downloaded-tool",
      "path": "downloaded-tool",
      "safeArgs": ["--help"]
    }
  ],
  "safeTrials": [
    {
      "command": "downloaded-tool --help",
      "writes": [],
      "network": []
    }
  ],
  "source": {
    "url": "https://example.com/downloaded-tool",
    "sha256": "replace-with-artifact-sha256"
  }
}
```

`single-file-url` packages must pin `source.sha256`. The local preflight does not download and execute remote artifacts for `--run-trials`; declared trial execution is currently implemented only for `local-bin`.

## Command Flow

### `cap init`

Creates `capability.json`. It infers from `package.json` when possible:

- package id, name, version, summary, keywords
- `bin` entries as commands
- a nearby `SKILL.md`
- MCP server names from `.mcp.json`
- default safe trials using `--help`

Use `--manifest <path>` for a non-default manifest file. Use `--force` to overwrite an existing file.

### `cap preview`

Compiles the manifest without writing the registry. The JSON output includes:

- normalized package metadata
- package summary
- capability card
- generated review record
- install plan
- warnings for missing skill, MCP tools, or structured output

Run this before editing registry files so you can see what CAP will publish.

### `cap review`

Runs local preflight checks. Blocking checks include:

- package id shape
- version, summary, task, safe trial, and bin presence
- safe trials starting with one of the package's declared bins
- declared local bin paths existing
- `single-file-url` packages pinning `source.url` and `source.sha256`
- MCP tool names using lower snake case
- declared skill files existing with `name` and `description` frontmatter
- executable packages having a digest

Warnings do not block publish, but they lower package quality for agents:

- no skill
- no MCP tools
- no structured output declaration
- pricing metadata present but not enforced locally

Use `--run-trials` to execute declared safe trials for `local-bin` packages. Trials run with an isolated temp `HOME`, `CAP_HOME`, and `TMPDIR`, set `CAP_REVIEW=1`, and strip common host secrets from the environment.

### `cap publish --local`

Writes the compiled package into a local registry JSON after a passing review:

```bash
cap publish --local --registry registry/packages.json
```

Publishing replaces the latest package entry for the same package id, but refuses to republish the same `id@version` unless `--force` is set. Treat published versions as immutable; bump the version for meaningful changes.

Use `--dry-run` to verify the publish result without writing:

```bash
cap publish --local --registry registry/packages.json --dry-run --json
```

## CI Checklist

A simple publisher preflight can run:

```bash
cap preview --json
cap review --run-trials --json
cap publish --local --registry registry/packages.json --dry-run --json
```

For packages in this repository, also run:

```bash
npm test
```

## Troubleshooting

- `Package id must look like "namespace/name"`: change `id` to a two-part stable name.
- `Capability card must declare at least one task`: add `tasks`, `bestFor`, or `capabilityCard.bestFor`.
- `Safe trial ... must start with one of this package's declared bins`: make the trial command begin with a declared command/bin name.
- `Declared bin path does not exist`: fix `commands[].path` or `install.bins`.
- `single-file-url packages must pin install.source.sha256`: add the artifact SHA-256.
- `Local publish commands require a filesystem registry path`: use a local `--registry` path, not an HTTP URL.
- `Remote publish is not implemented`: pass `--local`; hosted publishing is future marketplace work.
