HIP-1335: Listings — One Market for Apps, Skills, Mods, Plugins, Automations and Packs
Abstract
hanzo.market lists what organizations sell; /v1/marketplace in hanzoai/cloud is its one
store. This HIP adds two kinds to it, mod and plugin, gives every listing one manifest, one
install ledger and one permission vocabulary, and makes install mean the same thing for every
kind: the artifact is copied into the installer's own store and a ledger row says who installed
which version with which permissions. A member, or an agent the member approves, can change the
app they work in by installing a listing or by writing one.
The noun is listing (the market's own). No new word is introduced for the four kinds; each is
a value of kind.
Specification
Kinds
Six kinds carry a manifest: app, skill, mod, plugin, and two more that earn their place:
automation (a scheduled or triggered workflow, the /v1/auto object, installed as a copy the org
owns: the most-asked-for thing a business installs that is neither prose nor a connector) and pack
(a named bundle of listings, §Packs: the unit a person actually chooses). agent already is a kind;
theme is a mod with only theme keys, so it is not a seventh.
| kind | artifact | where it lives once installed | runs |
|---|---|---|---|
app | a project template, or a host that a frame may embed | the installer's projects; the embed registry of @hanzo/app | its own origin, in a frame |
skill | one SKILL.md (prose) | the org's authored skills (/v1/tool/skills) | attached to an agent; never executed |
plugin | TypeScript declaring actions against one HTTP API | the org's authored plugins (/v1/tool/plugins/authored) | compiled and run by the tool plane, credential from the installer's own connector |
mod | a theme and layout contract (@hanzo/mod ModTheme) and nothing else | the user's or org's mods | the client, through CSS custom properties |
agent, persona, mcp, tool and template keep their meaning and their install semantics.
A plugin is MCP, or a Hanzo plugin
plugin has two forms, and both are reachable the same way by an agent, as MCP tools:
- an MCP server: a remote URL, or a package/command the sandbox launches; its credential is the
installer's own, through the connection plane (
/v1/connection,/v1/provider). - a Hanzo plugin: a manifest and a backend module that runs isolated with declared permissions and no ambient network or filesystem. It may expose MCP tools itself and may carry skills and a mod.
Isolation, one runtime per kind, from what already runs (measured in hanzoai/cloud):
| kind of code | runtime | evidence |
|---|---|---|
| TypeScript/JavaScript actions | the tool plane's embedded interpreter (goja) | script/: its only impure primitive is a Go HTTP doer, the credential arrives already resolved; the one JS dependency in go.mod; 448 connectors run on it today |
| a compiled backend (Rust, Go, C) | WebAssembly (WASI) under wazero | no runtime today (go.mod has none); pure Go, no cgo (cloud gates cgo hard, see the Dockerfile's sqlite gate); deny-by-default: no preopened files, no sockets, host functions only for declared permissions. Specified, not built |
| anything else (a package, a binary, a language server) | the sandbox microVM (apps/sandbox: runc, visor, kata-clh, kata-fc) | already serves exec, dev and desktop leases and bills them |
A V8 isolate is not chosen: it needs cgo and a second JS engine beside the one that already runs.
The doer enforces network:<host>: a plugin reaches only the hosts it declared.
The catalog is curated; the rest is the long tail
Measured on 2026-10-26: the MCP shelf (/v1/tool/catalog) holds 50,589 servers; the connector
catalog 754 (448 run in-process, 734 have actions, 383 triggers); the skills catalogue 722 SKILL.md
under 116 products; the market's shop 9 public listings. The default view is a curated set of about
1,000, the plugins page's All is the rest with an unverified marker, and both install through
the same ledger and permission screen. One registry, one ranking field (rank, 0-100, higher first);
the rules are data in the registry (rank.rules), never code: official (a domain-attested
namespace: necessary, not sufficient, since 94% of the first 6,000 qualify), a working remote or
runnable install path (required), installs in our ledger, our own tool-call volume, and the upstream
repository's public star count fetched with an authenticated, cached, rate-limited read. The curated
set is the top 1,000 by rank with no category above 12%, and every entry in it must pass an install
smoke. Today's 448 runnable connectors are the floor of the set.
Mods change the running app
A mod declares the surfaces it touches from a closed list: theme (the CSS custom properties of
@hanzo/mod), layout (density, radius, sidebar order), pane (one pane beside the chat),
band (a status band), command (a slash command), hook (a handler on a tool call). It loads
without a reload through the one apply call that already reapplies a theme; the previous state is
kept and Revert restores it in one action; a mod's CSS cannot import, fetch or leave its sheet
(the validator refuses it). An agent authors a mod with mod.create, validates it, previews it for
the member, and offers it; it applies only on approval.
Packs, and Personal or Business
A pack is a listing whose manifest lists listings (contents) and defaults (permissions granted,
models, spend limit). Applying a pack is one confirmable ledger transaction: the screen shows
exactly what it installs and permits, the ledger records each row under one pack id, and Remove
reverses them together. platform.hanzo.ai opens a Customize flow at first run and from Settings:
choose Personal or Business, then a starter pack, for example Personal assistant (calendar,
mail and documents through the member's own Google connection), Developer (GitHub, Dev, MCP
tools), Business (CRM, commerce, CMS, analytics, insights, Slack agent).
One manifest
A listing carries a manifest (@hanzo/listing, Manifest; JSON Schema generated from it). Names
are flat. Required: kind, name (one lowercase path segment), version (semver), title,
summary, publisher (the org id; IAM's), permissions, artifact.
artifact is { hash, size, content? | url? }: the sha-256 of the bytes, so what the buyer
installs is what was reviewed. A listing whose bytes no longer match its hash is yanked.
One permission vocabulary
A permission is a grant, exactly as hanzoai/authz states them: a verb (read or write) on
an app (a capability name, HIP-0139) — plus four closed powers that are not paths: spend
(draw on the installer's balance), sandbox (run code in a sandbox), connector:<provider>
(use the installer's own connection to a provider), and network:<host> (reach one host). A
manifest lists what it asks; the install screen shows the list; the ledger records what was
granted. A grant given to an extension is never wider than the installer's own: it is a narrower
grant with an expiry, which is how an agent delegation is already expressed.
Nothing from the market receives a user's token. A plugin runs in the tool plane under the installer's connector; a mod has no network; an app runs in a frame on its own origin.
One install
POST /v1/marketplace/install {listing, version?, grants} for the caller's org (and user, for a
mod). Per kind:
skill: copy theSKILL.mdinto the org's authored skills (the name made unique), then activate.plugin: copy the source into the org's authored plugins and build it there; the build is the gate (compile or refuse). The plugin's credential is the installer's connector, never the publisher's.mcp: register the server URL in the org's servers.mod: record the ledger row; the client applies the theme.app: record the row; the embed registry draws it where the app's runtime exists.
Install never shares a row between tenants: the installer's store holds a copy, so a call runs in the caller's scope, which is the rule the marketplace already states for tools.
GET /v1/marketplace/installs answers the caller's ledger. Update is install of a newer version
by explicit action; remove deactivates and keeps the ledger row (removed).
Review and provenance
States: draft, review, listed, yanked. Only listed appears in the shop. The publisher is
the IAM org that owns the listing (the marketplace already proves ownership of what it lists).
Publishing a plugin or a mod requires the org admin; a reviewer (SuperAdmin) lists it.
The agent path
Four tools, over the one tool plane: market.search, market.install (always asks the member
unless the org's policy names the kind as auto; every call audited), market.update, and
mod.create (an agent writes a mod from a prompt, validates it against the manifest, offers it to
the member, and on approval publishes it to the org's private listing).
Share, list and sell: one action
Whatever a member creates on the platform is a listing's kind: agent, persona, skill, plugin,
mod, app, automation, pack, prompt, template. One Share action everywhere in the platform moves
a thing up one ladder: Private (the creator), Org (their org's members), Public link
(anyone with the link, not searchable), Listed (in the market, after review). Each step is a
ledger-visible change, reversible, and Listed is the only one that needs a reviewer.
A listing carries: a price (free, one-time, subscription, usage; in the publisher's
currency), a license (an SPDX id), the publisher's verified IAM identity, and a yank and
refund policy (a yanked listing leaves the shop and stops installing; refunds follow the plan's
terms, decided in commerce). Buying is one transaction: an install-ledger row and a Hanzo
Commerce charge to the buyer's org; the publisher sees sales and installs. The platform's
cut is one field in the registry's configuration, set by the owner, default 0; this HIP sets
no revenue share.
| part | state |
|---|---|
| Private and Listed (public flag, review), manifest, artifact hash, install by copy, ledger, remove | built (apps/marketplace) |
| Org and Public-link rungs; a Share action in each platform surface | designed |
| Price on a listing with a manifest | refused at publish and at install (402) until the charge below exists, so nothing priced installs for free |
Settlement through commerce: charge the buyer's org, pay the publisher's payout wallet (/v1/marketplace/seller/payout already binds a proved wallet; x402 settles per call and per job today), the registry-config cut | designed; to be built behind the owner-set cut and tested against commerce's sandbox before any money moves |
| Subscription and usage-based prices | designed (commerce plans) |
Out of scope
Pricing and revenue share for paid listings are the existing marketplace's (x402, per listing); this HIP sets none.