---
title: "Publish an extension · intentic API"
description: "Your extension stays in your repo; a registry is a git repo of sha-pinned pointers. Add one topic and the pull request that lists you writes itself."
url: "https://intentic.dev/api/publish/"
updated: "2026-08-12"
---

Ship

# Publish & registries

Your extension stays in your repo. A registry is a git repo of pointers to other repos, so listing costs a pull request and nobody has to trust a build service.

**On this page (7 sections)**

- [The shape of it](#the-shape-of-it)
- [Install without a registry at all](#install-without-a-registry-at-all)
- [A registry is a git repo](#a-registry-is-a-git-repo)
- [Source shapes](#source-shapes)
- [Getting listed](#getting-listed)
- [What the person installing sees](#what-the-person-installing-sees)
- [Available today, and next](#available-today-and-next)

## The shape of it

intentic does not host extension code, build it, sign it, or take a cut of it. A registry entry is a **pointer to your repository at a commit**, and installing follows that pointer directly from the owner's sandbox to your git host. Three consequences worth stating plainly:

- **Publishing is a pull request.** No account, no upload or packaging step; the official registry runs both deterministic scanning and an adversarial agent audit against the exact source in that pull request.
- **You keep the code.** Your repo is the artifact. Delisting doesn't delete anything; it only removes a pointer.
- **Registries are plural.** The official one is a default, not a gate. A company can run a private registry of internal extensions and never touch ours.

## Install without a registry at all

A registry is a convenience for discovery, never a requirement. Anyone with your repo URL and a commit sha can install your extension today from **Capabilities → Add → Extension**. That's the whole distribution mechanism; the marketplace just saves people from copy-pasting shas.

It also means a private extension needs no publication path: point a sandbox at an internal repo with a token and you're done.

## A registry is a git repo

Add a `.claude-plugin/marketplace.json` to any repository and it is a registry. Mark an entry `"kind": "extension"` and it installs as a sha-pinned intentic extension.

.claude-plugin/marketplace.json

```json
{
 "name": "acme-extensions",
 "plugins": [
 {
 "name": "acme.incidents",
 "kind": "extension",
 "trust": "listed",
 "description": "Incident triage in the rail: open alerts, acknowledge, jump to the failing run.",
 "version": "1.0.0",
 "icon": "exclamation-triangle",
 "source": { "source": "github", "repo": "acme/incidents", "sha": "9f2c1ab…" }
 },
 {
 "name": "acme.linear",
 "kind": "extension",
 "trust": "listed",
 "description": "Linear connector: the agent reads and files issues from its shell.",
 "version": "0.3.0",
 "logo": "linear",
 "source": { "source": "github", "repo": "acme/linear-connector", "sha": "4d81e07…" }
 }
 ]
}
```

The file uses Claude Code's plugin-marketplace format. `kind` and `trust` are intentic's own markers, and Claude Code ignores fields it doesn't know. So **one registry repo can serve both**: a team that already publishes agent plugins lists its intentic extensions in the same file, rather than standing up a second thing.

An entry's `name` is `publisher.name` read from your manifest, not a label the registry picks. That is the same identity the app installs under, so two publishers can both ship an `incidents` extension, and a repo that copies somebody else's manifest collides with their listing instead of shadowing it.

A second file sits beside it. `registry.generated.json` is written by the registry's nightly job and holds only facts read back off the source host: stars, and the last push date. It is separate so a nightly refresh never conflicts with an open pull request, and so a review diff shows the decision being made rather than a churn of star counts. It carries no "latest upstream commit": the approved sha is the one that runs, and advertising a newer one would invite a click that skips the review.

### Source shapes

`source` says where the code is. A bare string is a path inside the registry repo itself; the object forms point outward.

What source can be

```typescript
// A repo of its own
{ "source": "github", "repo": "acme/incidents", "sha": "9f2c1ab…" }

// Any git host
{ "source": "url", "url": "https://gitlab.com/acme/incidents.git", "sha": "9f2c1ab…" }

// A subdirectory: one repo, several extensions
{ "source": "git-subdir", "url": "https://github.com/acme/tools.git", "path": "ext/incidents", "sha": "9f2c1ab…" }
```

Give a `sha`. A branch name is accepted for plugins, but an extension install requires a full 40-character commit sha, so a registry entry without one can't be installed in a click; it makes the user go and find the sha themselves.

A registry you run can point wherever its users can clone. Admission to the official registry is narrower: executable sources must be public HTTPS repositories on GitHub, GitLab, Codeberg or Bitbucket. That keeps both automated reviewers on one inspectable object without placing private credentials in the admission workflow.

## Getting listed

Two ways in, and they end at the same place: a pull request against the [official registry](https://intentic.dev/extensions/). There is nowhere to sign up.

1. **Add the topic.** Put `intentic-extension` on your GitHub repository, with an `intentic-extension.json` at its root. A nightly job resolves your latest commit first, checks the manifest and shipped bundle at that exact sha, and **opens the pull request for you**. That is the whole submission process. Your `logo` or `icon` is copied across with it, so the gallery card and the in-app browse row wear the mark you declared. A listing that declares neither shows its initials.
2. **Or open it yourself.** Required if your extension lives in a subdirectory or is hosted on one of the other supported public git hosts, because GitHub topic discovery cannot propose it automatically.
3. **Two independent automated checks read the exact source.** Trivy deterministically checks dependencies, committed secrets and deployment configuration. Then an intentic agent inspects the complete tree without executing author code: browser globals and egress, server/process/agent/bin/build surfaces, dependencies and shipped artifacts against source. A finding, blocked or unjudged audit, or missing evidence keeps the pull request unmergeable. A pass records both run identities against the repository, commit and optional subdirectory.

Publisher slugs are first-come and tied to proven ownership of the source repo. Because the listing key is the manifest-derived `publisher.name`, a scan that finds a repo claiming a slug somebody else already holds refuses it rather than opening a pull request that looks legitimate.

Listing is free and stays cut-free. Publishers can opt into a paid `premium` tier that draws from the creator pool, one field on your entry, and the whole economy is stated once on [Earn](https://intentic.dev/earn/).

## What the person installing sees

The install dialog renders your manifest in plain English. It lists *this extension adds a tile to your rail*, *reads your workspace logs*, *runs a background process* or *puts a tool on your agent's PATH*, one line per declared contribution, with the route allowlist spelled out underneath, at one specific commit.

Which makes the manifest a piece of writing rather than only configuration. Declare the narrowest set of routes that works and the dialog is short and reassuring; declare a broad one and it is long and alarming, whatever the code actually does. The [installer's page](https://intentic.dev/docs/extensions/) is the whole of what they are shown, and it is worth reading once from their side.

## Available today, and next

Everything in [Build an extension](https://intentic.dev/api/build/) works now: authoring, sha-pinned install from any git repo public or private, the manifest gate, per-extension settings, and the on/off switch. So does the registry: the [gallery](https://intentic.dev/extensions/), the topic scan that opens your pull request, and browsing plus one-click install straight from **Sandbox → Discover**, against the official registry or any repo you point it at. The [update lifecycle](https://intentic.dev/api/maintain/) also works now: the badges, powers diff, kept previous version, one-click revert, health watch, blocked-listing advisories, and the per-extension update policies.

Still to come: a typed npm artifact for `@intentic/extension-ui` so out-of-repo authors get the shell's components with full types.

Building something and want it listed? The [build guide](https://intentic.dev/api/build/) is the whole prerequisite. Add the topic when your first sha is pushed and the pull request writes itself.

## Related pages

- [Verification & trust](https://intentic.dev/api/verify/): what listed, verified and blocked each claim.
- [Maintain & grow](https://intentic.dev/api/maintain/): release two: updates, ranking, and the revenue cadence.
- [Install & manage extensions](https://intentic.dev/docs/extensions/): the same listing, read from the other side.

More in Ship

[Next Verification & trust →](https://intentic.dev/api/verify/)
