Developer documentation

Marketplace

Last reviewed 31 August 2026

QuickstartCLI referencePython SDKTypeScript SDKMCPIntegrationsPoliciesActionProofEvidenceCAIN TraceConformanceTroubleshootingDeveloper portalMarketplaceFree tierBenchmarksArchitectureCAIN IdentityCAIN ControlCAIN BudgetCAIN GovernanceCAIN MemorySelf-Hosted MCPGateCAIN PrivateCAIN TrajectoryCAIN Agent SecurityCAIN Drift7-Moat ArchitectureChangelog

Marketplace and extensions

cain marketplace search redis
cain marketplace inspect acme/redis-connector
cain marketplace install acme/redis-connector

An extension is third-party code or configuration installed into the boundary

that decides whether your agent may act. That makes the install path the highest-

risk surface in the CLI, and it is built accordingly.

Read this before you install anything

CAIN does not sandbox extension code. A framework adapter or connector loaded

into your Python process runs with your process's privileges. No manifest

declaration changes that, and this page is not going to imply otherwise.

What is real: signature verification, permission disclosure, refusing scopes that

can never be safe, compatibility checks, and a lockfile that records exactly what

you accepted and why. Those are about *knowing what you ran and being able to

prove it later*. Isolating extension code is on the roadmap and is listed as

not-yet-done.

What install checks, in order

1. fetch metadata — nothing on disk yet

2. validate the manifest

3. check compatibility with your CAIN version and deployment capabilities

4. verify the signature — before any bytes are written

5. show permissions and require a grant

6. resolve dependencies, checked the same way

7. write the lockfile

Nothing touches your filesystem before step 4. Verifying after unpacking means

untrusted contents have already landed, which is where path traversal lives.

Refused outright, no flag overrides

quota:override, tenant:switch, admin, credentials:write)

request is a permission nobody reviewed

Requires an explicit flag

situationflagwhy
signature not verified--allow-unsignedrecorded in the lockfile as a waiver
update adds a dangerous scope--accept-new-scopesthe supply-chain case
permissions, non-interactive--grantCI must not accept permissions by default
paid extension--accept-price

Permissions

Sixteen coarse scopes, each with a one-line meaning. Deliberately coarse: a

fifty-scope model is one nobody reads, and an unread prompt is not consent.

Dangerous scopes are shown in full and separately. The combination worth

questioning is any read scope plus network:outbound — that is an exfiltration

path by construction. Legitimate for an evidence integration; a red flag for a

policy bundle.

$ cain marketplace inspect acme/example
  Permissions requested:
   ! network:outbound     Make outbound network requests. Combined with any read
                          scope, this is an exfiltration path.
     policy:read          Read your policy and its version.

Code versus data

requires_execution is derived from the extension type, never read from the

manifest — "is this code or data" is exactly the question a malicious publisher

would lie about.

declarative (data)executes (code)
policy, security-ruleseverything else

Signing

A signature covers both the manifest digest and the artifact digest. That

binding matters:

All three tamper vectors are covered by tests in tests/test_marketplace.py.

Publishers: register a public key on your handle and sign releases. Unsigned

releases can be published, but every installer must pass --allow-unsigned and

carry the waiver in their lockfile — so signing is how you get adopted.

cain marketplace publish --signature "$SIG" --artifact-sha256 "$SHA"

The lockfile

cain-extensions.lock. Commit it. It records, per extension: version, manifest

digest, artifact digest, whether the signature verified, **whether an unsigned

install was waived**, which scopes were granted, and when.

That last set is deliberately the awkward part. A convenient implementation would

omit installed_unsigned; a year later, "why does this project trust this

extension" needs an answer.

A corrupt lockfile raises rather than being replaced — overwriting it would erase

the record of what the project had accepted.

Versions are immutable

Republishing a version returns 409. A mutable version is a supply-chain attack

with extra steps: anyone who verified it yesterday has no way to know it changed

today.

Yanking is supported and does not delete. A yanked version stays in the

registry so existing lockfiles remain auditable, and install treats it as a

critical finding.

Publishing

cain marketplace init --type policy
# edit cain-extension.yaml
cain marketplace publish --dry-run      # validate, publish nothing
cain marketplace publish

A publisher handle is claimed once and bound to your tenant. Nobody else can

publish under it — without that, provenance means nothing. Handles like cain

and official are reserved.

Ask for the fewest scopes you can do the job with. A long list is a reason to be

refused.

Two independent security screens

The registry scans on publish; the CLI scans again on the machine about to run the

code. Both results are shown. A registry-side scan is a claim the registry makes,

and the installer should not have to take it on faith.

Both are static screens over the manifest. Neither reads or executes the

extension's code, and neither certifies safety.

Extension types

mcp-integration · framework-adapter · policy · connector · tool ·

actionproof-module · security-rules · evidence-integration ·

deployment-plugin · sdk-extension · enterprise-integration

Revenue

Free and paid listings are both supported. Platform share 20%, publisher 80%,

applied at charge time via a Stripe destination charge.

Payouts are not enabled today. They ride the platform's Stripe Connect

integration, and Connect is not switched on for the CAIN account — an account

setting, not missing code. GET /marketplace/payouts/status reports this, and

paid listings are marked payouts_available: false.

Publish a paid extension if you want; do not price work on revenue that cannot

reach you yet.

Ratings

One rating per tenant per extension, and you cannot rate your own. Both

constraints are needed for the number to mean anything. install_count counts

distinct tenants, not repeat installs — a counter a CI pipeline can inflate is a

vanity metric, and installers use it to judge whether they are early.

Commands

cain marketplace search [query] [--type T] [--free] [--limit N]
cain marketplace inspect <publisher/name> [--version V]
cain marketplace install <publisher/name> [--grant] [--allow-unsigned]
                                          [--accept-new-scopes] [--accept-price]
cain marketplace update [name] [--check] [--allow-unsigned] [--accept-new-scopes]
cain marketplace publish [--dry-run] [--signature S] [--artifact-sha256 H]
cain marketplace init [--type T]
cain marketplace list
cain marketplace uninstall <publisher/name>

All accept --json.