The neuralweb marketplace
The package protocol's distribution surface — publish, vet, audit, and install AI capabilities down to a single element.
Maturity: preview (70 %)
Marketplace. The marketplace registers or uploads packages, vets them in stages, serves them with integrity digests and a signed revocation feed, and is used through a CLI and an MCP registry facet.
- The marketplace is not publicly hosted; it runs as a local deployment only.
- The marketplace never assigns trust; trust stays the installing host's decision.
- Direct uploads are declarative only; packages that carry code publish through npm.
- Publisher sign-in with GitHub is not available.
Public registry not yet deployed
The marketplace is built and runnable — a self-hosted instance serves the
full API, the CLI, and the MCP subregistry facet today. What is not live is
the public deployment at registry.neuralisapp.com: it does not resolve
yet, so there is no public URL to publish to or install from. Point
NEURALWEB_REGISTRY at your own instance to use everything on this page now.
The package system is a protocol, and a protocol needs a distribution surface. neuralweb is that surface: a public marketplace where creators publish AI capabilities — whole packages, or a single skill, instruction, rule, agent, doc, workflow, team member, tool, or connector — and consumers (humans, agents, organizations, and self-hosted Neuralis instances) search, audit, and install them down to the single element.
The division of labor is deliberate. The marketplace verifies identity,
scans every published version with the platform's own validators, assigns a
vetting status, and discloses capabilities up front. What it never does is
decide trust: trust stays the installing host's decision, exactly as it
does for every other way a package reaches the platform.
Listings carry a vetting status (unscanned → scanning → scanned →
verified-publisher → signed, advancing only forward — signed is
schema-ready but not yet reachable, since the signing pipeline does not exist
yet), a risk band, and an install-channel recommendation (markdown-drop,
packages-drop, or deps-rail) — never a trust grade.
Two publishing channels
| npm registration | Direct upload | |
|---|---|---|
| What you publish | An existing npm package — the marketplace follows the npm registry and mirrors its versions | A package tree or a single element (a lone workflow, a bare skill folder, …) uploaded directly |
| Identity | The npm name, after ownership proof | @<publisher-handle>/<name>, first claim wins, npm collisions refused |
| Ownership proof | A publisher marker in the package's package.json or a DNS TXT challenge at _neuralweb.<domain> on a domain you control — registration opens both, and one verified proof for that exact package identity is enough to list | Your authenticated publisher account |
| Code allowed | Yes — compiled runtime code ships through npm and is statically analyzed | No — uploads are declarative-only by construction: contribution markdown and JSON contracts; runtime code is rejected before anything is stored |
| Element kinds accepted | All nineteen | A closed allowlist of eleven: skill instruction rule agent docs workflow team-member credential config-setting, plus tool only when it is schema-only and connector only when it is a plain URL. A skill's scripts/ still ship — what is refused is declared executable surface (a built dist/, a code runtime, any hook, any App surface, a script command, a factory- or command-bearing connector) |
| Integrity | Tarballs are fetched origin-pinned and integrity-verified while streaming | Uploads are canonically re-packed; the stored bytes' hash is the source of truth |
Both channels end in the same place: a content-addressed artifact, a version row, and a scan chain. Nothing is listed until the scanner has seen it.
Those two are the only channels open to the public. The stored vocabulary
holds two more: an internal channel — admin-only, re-verified server-side
and never a caller-supplied flag — which is the sole channel allowed to
publish first-party @neuralis/* identities or a code-bearing tree that did
not come through npm (it is how the contract examples
below are seeded), and a git channel that is schema-ready but refused at
the API today.
Six-stage vetting
Every accepted version runs a six-stage scan chain, and every stage appends verdicts to an append-only history — re-scans add rows, they never rewrite the past:
- Identity — publisher standing, ownership-proof checks (a verified proof whose subject is this exact package identity — proving one package never lists another), provenance and integrity notes, typosquat and reserved-name detection, and a reverse-scope impersonation probe. A standing or missing-proof hold short-circuits straight to stage 6; every other outcome continues down the chain.
- Static malware — five detector classes over every text file of the
extracted tree, skill scripts and
package.jsonincluded: precise secret patterns (cloud keys, private-key blocks, registry tokens; generic high-entropy assignments warn rather than fail), invisible and bidirectional Unicode, obfuscation signals, npm install-script flags, and an optional antivirus pass. Configure the antivirus and an unreachable daemon fails the scan closed — configured means coverage or no listing; leave it unconfigured and the verdict saysskipped, never a silent pass. - Contract — the full platform validator suite (manifest,
contributions, tool schemas and their
x-neuralisextension,requiresshapes, workflow templates, URI policies, and the feature audit), run exactly as the host would run it, plus a static analysis of any shipped code. This stage also extracts the capability disclosure: the features, URI policies, and tools a package would hold if installed — shown on every listing before you install, and diffed version-to-version so a permission escalation between releases is visible at a glance. Credential disclosure covers both halves: the ids named in skill frontmatter and the manifest's owncredentials[]declarations, each of which also becomes acredentialelement in its own right. A declared config setting carrying anenvFallbackadditionally raises aconfig-env-fallbackflag, so a reviewer can see that the package projects environment-variable values into admin-visible config. The scanner's vocabulary is 19 element kinds — the seventeen contribution and surface kinds pluscredentialandconfig-setting, which are declarations and never secrets. - LLM content — eight deterministic rules (pipe-to-shell installs, staged downloads, credential exfiltration, jailbreak framing, base64 blobs, mixed-script look-alike tokens, ASCII-masquerade homoglyphs, and network-call patterns) plus a declared-versus-instructed mismatch check (does the markdown instruct the agent to use environment credentials, credential ids, privileged URI schemes, or high-risk tools the contract never declared?), backed by an LLM judge for flagged content. When the judge is unavailable, flagged content fails closed; content no rule flagged never reaches the judge and still lists.
- Dynamic — reserved for sandboxed execution analysis; honest about being a stub today (verdicts say "skipped", never pretend to have run).
- Risk review — a transparent weighted score bands the outcome: list, list with a review flag, or hold. Any failing verdict holds the version before the score is even read, and a held version is never auto-listed by a re-scan — release is a moderator decision.
A version is publicly readable only while its package is active and the
version's own state is listed. Every other state — submitted, scanning,
held, hidden, delisted, revoked — is simply absent from every public
read: never rendered as "locked", and never distinguishable from names that
don't exist. A corpus of twelve fixture packages — eleven hostile (prompt
injection, invisible Unicode, undeclared credentials, a staged download, an
identity spoof, foreign URI policies, an ungated route, a publish-whitelist
miss, a missing default export, a removed surface renderer, and a two-version
sleeper) plus one benign control that must list cleanly — pins the scanner's
expected verdicts, terminal moderation state included, in CI.
Signed revocations — the kill switch
When a version is revoked, the public revocation feed gets its row
first, unconditionally — delisting mechanics follow. The feed is served as
canonical JSON at GET /api/v1/revocations, signed with ed25519; the public
key is published at /.well-known/neuralweb.json, and clients (including the
CLI) verify the signature over the raw bytes before parsing. A compromised
package can be killed platform-wide with one feed entry, and every installer
checks the feed before installing.
A feed row is exactly id, package_identity, version_raw, reason_code,
created_at — in that key order, because the order is the canonical form
the signature covers. The reason code comes from one closed list —
malware, credential-exfiltration, prompt-injection, typosquat,
ownership-dispute, publisher-request, security-other — and never free
text. Those same seven are the reason codes an abuse report is filed under.
Per-element serving: three tiers
Every element of every listed version is individually addressable and served in one of three tiers:
- Tier A — standalone bundle. A deterministic archive that is a valid
project-package drop: untar it into a project's
_packages/directory and the host discovers it. A generatedelement-manifest.jsonat the bundle root pins all seven of: the element reference (kind, id, title); the parent package (identity, version, artifact hash, npm integrity when the npm channel supplied one, catalog URL); the compatibility floors (parent range, contract floor); the capability disclosure (required features, credential ids, risk flags); every bundled file's hash; the vetting status at pack time; and the manifest's own wire version. The response carries a digest header over the exact bytes. - Tier B — document. A pure JSON envelope: the verbatim author contract plus a hash of its canonical encoding — self-verifying offline.
- Tier C — not standalone. The element needs its owning package's runtime; the refusal deep-links to the parent package instead of serving something that couldn't work.
Which kind lands where, and the URL that serves it:
| Tier | Kinds | Endpoint |
|---|---|---|
| A | skill instruction rule agent docs workflow team-member | Read: GET .../versions/{version}/elements/{kind}/{id}/content — the element's prose as plain text, one request, no download. ?path= selects one file of a multi-file element (an invalid path answers with the valid list); ?line_start=/?line_end= (1-based, inclusive) window it. CLI: neuralweb read '<identity>@<version>#<kind>/<id>'. Install: .../bundle — a gzip tarball of the origin file(s) plus a generated element-manifest.json; integrity in the Digest: sha-512= response header. |
| B | tool (schema-only) connector (URL-only) credential config-setting | GET .../versions/{version}/elements/{kind}/{id}/document — a JSON envelope whose contract is the whole artifact. (/bundle and /content refuse with 400.) |
| C | hook command resource source policy widget dock card — plus any tool whose contract carries a handler-shaped key and any connector that is not a plain mcp/http URL | /bundle answers 409 TIER_C_NOT_STANDALONE with a deep link to the parent package. Every App surface is Tier C in every asset mode, assetMode: "bundle" included. |
Reading and installing are different rails on purpose. /content is the
read rail — text in, nothing written to disk; on a windowed read the
whole-file digest rides X-Neuralweb-File-Digest (the standard Digest
header describes the response body, so it is only sent for a whole-file
read). /bundle is the install rail. /document on a Tier-A kind returns
metadata only — the host's PackageFile projection (id, path,
category, title, description, overwrite, plus
files/activation/requires/metadata when present); the body is what
/content serves.
The contract examples
The package system's three contract
examples — one per install class —
are published here as stable, versioned references: @neuralis/example-builtin
(admin-installed npm package), @example/project-package (_packages/ WASM
drop), and @neuralis-examples/example-source (synced markdown, no manifest).
First-party package source is not published, so the registry is the rail that
carries the contract in machine-readable form.
# Tier A — read a markdown contribution as plain text (no download)
neuralweb read '@neuralis/example-builtin#docs/docs.create-package'
# Tier B — read a tool contract verbatim
neuralweb info '@neuralis/example-builtin#tool/example_query'Non-goal: there is no base-package workspace to download
The registry serves published artifacts. It does not hand back a
downloadable, editable base-package workspace — the npm rail hands back the
npm tarball, never a source tree you are meant to fork. The supported
customization path is the package protocol itself: your own @yourco/*
against the same contract, admin-installed or _packages/-dropped.
The CLI consumption loop
The command-line client ships on npm as neuralweb — a thin,
dependency-light HTTP client of the public API. Eight consumer verbs, and no
others:
neuralweb search "browser automation" --kind skill
neuralweb info @acme/research-kit#skill/deep-research
neuralweb read '@acme/research-kit#skill/deep-research' # the prose, as text
neuralweb audit @acme/research-kit # scan report + capability disclosure + risk score
neuralweb download @acme/research-kit --out ./review
neuralweb verify ./review/research-kit.tgz # re-run the integrity chain offline
neuralweb revocations # the signed kill-switch feed, verified first
neuralweb install @acme/research-kit#skill/deep-research # project railFour exit codes, pinned: 0 success, 1 usage / network / API error, 2 a
verify mismatch, 3 a revoked or vetting refusal at the pre-install gate. An
HTTP failure never maps to 2 or 3 — those two are reserved for the
integrity chain and the kill switch.
Inside a Neuralis deployment the CLI package itself ships a neuralweb
skill, so an agent granted the packages.registry feature can run the same
read loop from its own shell (search / info / read / audit, plus
verify and revocations) — while download is the install rail rather
than a way to read, and installing and publishing remain operator actions.
Everything is verified end to end: bytes against the digest header, files against the bundle manifest as an exact set, contracts against their canonical hash — a single mismatched byte fails the install. Before any install, a pre-install gate checks the revocation feed and the vetting status.
Installation follows the platform's package paths:
install --channel project(the default) drops a verified Tier-A element into a project's_packages/directory, where it loads WASM-sandboxed like any other project package. The target is the directory holding the project's.neuralweb.jsonmarker, or an explicit--dest— with neither, it is a usage error, never a silent drop into the current directory. A Tier-B element is pointed atdownloadinstead (a JSON document has nothing to drop) and a Tier-C element is refused with a deep link to its parent package.install --channel builtintakes a whole package and never executes anything: it prints the host command an admin runs to install into the builtin class, with a trust notice and a host-rebuild warning — because installing builtin-class code is the platform admin's trust act, not the marketplace's. npm-channel packages get the registry-add form, internal-channel ones the tarball form; direct-upload packages are refused here outright, since declarative-only trees never join the builtin class — use the project rail.
The publisher lane lives in the same binary: neuralweb publisher login|register|verify-dns|publish|status|token|webhook covers both
channels, DNS ownership re-checks, token management, and webhook
secrets. Re-scans are a consumer-side verb:
neuralweb audit <identity>@<version> --fresh requests one with an owner
PAT and polls briefly for the fresh verdicts.
The MCP subregistry facet
The catalog is also re-served, read-only and anonymous, in the official MCP registry API shape (v0.1) — an MCP-aware client can point at neuralweb as a subregistry and list its entries alongside any other MCP registry. Three spec paths are mounted, plus one health probe that is ours rather than the spec's:
| Path | What it serves |
|---|---|
GET /api/mcp/v0.1/servers | the server list — ?cursor, ?limit, ?search, ?updated_since, ?version, ?include_deleted (forced on under updated_since, so sync clients observe deletions) |
GET /api/mcp/v0.1/servers/{serverName}/versions | that server's versions |
GET /api/mcp/v0.1/servers/{serverName}/versions/{version} | one version (latest is an alias) |
GET /api/mcp/health | liveness — not part of the spec |
The mapping is honest: neuralweb never emits install metadata that would falsely assert a runnable MCP server, and revoked entries surface as spec-conformant tombstones for sync clients. Every miss on a spec path — unknown name, hidden package, deleted version without the flag — answers one byte-identical spec-shaped 404, so the facet is no more of an existence oracle than the catalog is.
Org catalogs
An organization is a curated view of the marketplace, not a second marketplace: its members see only what the org's allowlist admits. The org catalog is the public listing floor intersected with that allowlist, so a package has to clear both — and everything that clears neither is simply absent, never rendered as locked. Deny-by-default runs on both axes: an empty allowlist shows nothing at all.
The allowlist grammar is closed, with exactly two arms — an exact package
identity (optionally narrowed to a single element and/or a semver range) or
an @scope/* wildcard covering a whole publisher scope, package-level
only. There is no bare * and no other glob form, and a pattern that fits
neither arm is rejected outright with a validation error — it is never
silently stored.
Everything under /api/v1/orgs/{org}/… — members, allowlist, tokens, and the
catalog itself — is member-scoped, and there are two ways in: a member's own
publisher credential (reads for any member, mutations only for an admin),
or an org token minted with an explicit org-admin scope for API and CI use.
The two bearer lanes never mix: an org token authenticates only on its own
org's routes and is refused wherever a publisher credential is expected, and
the reverse holds too. GET /api/v1/orgs lists the caller's own orgs and
is never a global enumeration.
Every failure arm answers identically. An anonymous caller, an unknown or
malformed org, a token belonging to a different org, a publisher who is not a
member, a member attempting a mutation — all of them get one byte-identical
404, never a 403. Being refused by an org tells you nothing about whether
it exists.
Reviews, ratings, and abuse reports
A review is POST /api/v1/packages/{identity}/reviews: an integer rating
from 1 to 5, an optional title (200 characters) and body (5 000), scoped
either to the whole package or to one of its elements. Posting again replaces
your own review and DELETE removes it; the rating aggregate is recomputed
inside the same transaction, so a listing's rating always matches the reviews
you can actually see.
Reviews are gated on verified usage: the anonymous carrier posting one must already have an install or download event recorded for that package, and the API never mints that carrier for you — no history, no review. The gate is friction rather than proof, since an anonymous id is mintable, and it is documented that way rather than sold as verification. Reviewer identity is stored only as a peppered hash and is never served: a review carries no author field at all.
POST /api/v1/packages/{identity}/report files an abuse report under one of
the seven reason codes above, with an optional 2 000-character body. A repeat
report from the same reporter is a server-side no-op and still answers an
idempotent 202. Reports feed a moderator triage queue and nothing else —
they never hide a version on their own, because an automatic hide driven by a
mintable reporter identity would be a griefing vector. Hiding, delisting, and
revoking stay moderator decisions.
Where this fits
The marketplace closes the protocol's loop. Capabilities authored anywhere — including skills and rules that follow the agentskills.io conventions other tools already produce — publish once, get vetted once, and install onto any Neuralis host through the same three paths every package already uses: builtin class, sandboxed project drop, or synced source. The marketplace adds the missing piece between authors and hosts: identity, vetting, capability disclosure, and a kill switch — while the host keeps the only decision that was ever its to make.