neutron-tools
The shared protocol and browser-utility package used by the Kernel, app frontends, the compiler, and repository tooling.
What it provides
The message-bus bridge. The exec/expose postMessage transport, typed
guards for the JSON envelopes, and the client used to route calls between
endpoints.
neutron-tools/app — the source-bound app entrypoint. This is what app
frontends should import. It exposes message-bus tools, approved canister-call
dialogs, self calls, tray/state actions, vetKeys, Agent Mode, and the connection
helpers re-exported from connections.ts. App identity comes from the live
private port rather than an app-id field supplied by the caller; raw management
actors and cycle primitives are not exposed.
import {
createMsgBusClient,
createCanisterClient,
loadNeutronCanisterId,
loadTileContext,
exposeTool,
callTool,
copyToClipboard,
onAppStateChange,
publishAppStateChange,
} from 'neutron-tools/app';
The manifest schema and validator. The closed JSON Schema (draft-07) for
neutron.json, plus the semantic validation that raw JSON Schema cannot express
— unique tile ids, safe relative asset paths, tray/background coupling.
Hashing and URL helpers, including the derivation of an app's physical Candid method names and its per-app subdomain.
The neutron-tools/repository protocol. The fixed neutron-repo-v1 link
and manifest model used for certified third-party setup links. See
Repositories.
Entrypoint map
| Entrypoint | Role |
|---|---|
neutron-tools | Protocol types, canonical ordering, app/physical names, versions, and capability catalog |
neutron-tools/app | App-side browser SDK and connection helpers |
neutron-tools/kernel | Kernel-side action exposure and port execution |
neutron-tools/app_attachments | Bounded endpoint-to-endpoint binary tool attachments |
neutron-tools/capabilities | Capability catalog, plans, wire format, and normalization |
neutron-tools/repository | Certified repository protocol and setup-link parsing |
neutron-tools/certified_asset | Bounded certified-asset reader and decoders |
neutron-tools/browser_secret_cache | Small encrypted browser-secret cache abstraction |
neutron-tools/wasm_metadata | Wasm custom-section helpers |
Shared workspace code also imports supported neutron-tools/src/*.js subpaths
for manifest schema/validation, hashing, runtime URLs, and runtime config.
Sub-entrypoints worth knowing
neutron-tools/app_attachments
Bounded binary transfer between live endpoints. A tool declares its exact
input/output attachment name, media type, required flag, and byte cap in its
descriptor; the caller transfers an ArrayBuffer over the existing
source-bound private port.
Ordinary tool JSON and progress events carry no attachment bytes. The kernel authenticates both endpoints, validates the declaration before routing, and applies global per-endpoint byte and count limits. Apps must still use app-specific media types and validate the payload after receipt.
Self calls
querySelf() and updateSelf() invoke methods the app listed in
capabilities.preapproved_self_calls with no consent dialog.
Their value type is ordinary structural data plus Uint8Array (ArrayBuffer
is accepted as an input convenience) — but only at positions the trusted live
Candid type proves to be blob / vec nat8. Binary leaves may be nested or
repeated. The SDK snapshots each buffer into an immutable copy and transfers
the copies over the private port, so caller-owned buffers stay usable.
Connections
requestConnection, listConnections, acquireConnectionCredential, and
disconnectConnection are exported from neutron-tools/app. Requests name one
manifest-declared provider; the Kernel binds the caller endpoint and keeps the
provider session outside the app frame. Returned credentials are sensitive,
short-lived application data and must not be logged or persisted.
There is no attachment-direction plan, no app-supplied field path, and no transport envelope. The manifest declaration controls consent for the method; the live interface owns the type.
vetKeys helpers
requestVetKeys, listVetKeys, getVetKeyPublicKey, deriveVetKey, and
approveVetKeyDerivation. Note the shape of the API: there is no appId, key
name, derivation-input, cycle, or management-canister parameter. deriveVetKey
reports a single-use challenge through onChallenge; that callback must
immediately call approveVetKeyDerivation from the same endpoint. This is an
automatic protocol confirmation, not a second user decision. The encrypted
result resolves only to the endpoint that started the request.
Tool descriptors
Endpoints register tools locally. Descriptors carry a name, optional title and
description, a required draft-07 inputSchema, an optional outputSchema, and
optional annotations.
exposeTool(
'notes_search',
{
title: 'Search Notes',
description: 'Search notes owned by this app.',
inputSchema: {
type: 'object',
required: ['query'],
properties: {query: {type: 'string'}},
additionalProperties: false,
},
outputSchema: {
type: 'object',
required: ['matches'],
properties: {matches: {type: 'array'}},
additionalProperties: false,
},
},
async ({query}, context) => ({matches: []}),
);
Names, metadata lengths, schema sizes, and invisible/control characters are validated. Input and output are validated twice — once at the endpoint and once at the kernel broker. Discovery always asks the live endpoint, so there is no stale kernel-side tool cache.
Reserved annotations include the closed values
"neutron:audit": "metadata_only", "neutron:control": "cancel", and
"neutron:visibility": "same_app"; the attachment entrypoint adds its bounded
"neutron:attachments" contract. Unsupported values for the closed reserved
annotations are rejected.
Design rules to notice
The SDK's shape is itself a security decision. Three patterns recur:
- No authoritative identity in payloads. You never tell the kernel who you are; it already knows from the port.
- Privileged primitives stay brokered. The app SDK exposes scoped operations rather than a management actor, cycle attachment primitive, or certificate-tree handle.
- Private actions are not tools. Clipboard writes, tray badges, connection credentials, Ethereum provider sessions, and vetKeys actions travel as private SDK actions on the same port. They are absent from tool discovery, cross-app routing, agent tool selection, and the model-visible audit.