NAOMS for developers

← Back to overview

Build & ship · Step 3

Package

A typed manifest declares what your package needs and what it provides, so it moves as one signed unit rather than a folder of loose files someone has to trust by hand.

Packaging turns a finished package into one signed, movable unit instead of a folder of loose files. The manifest declares the package’s identity, what it needs, what it provides, and who may install it, and packaging hashes the code, its assets and its dependency pins into a signed sidecar record. NAOMS checks that hash before loading the package, so a change made after signing is caught.

What a person notices

Installing a package is one step, with no manual file copy involved. What it will be allowed to do is shown before it runs.

If a package has been altered since it was signed, the platform refuses to load it and records that refusal, rather than silently running the altered code.

A package can be removed cleanly, because everything it touches was declared up front.

What you do as a developer

Every package exports one typed manifest constant. NAOMS reads it before any of your code is allowed to run, so the manifest itself is the contract that gets enforced.

1

Declare identity

An id, a name, a version and a category. The id becomes a public contract you should never rename once you've shipped it. Other packages and the routing layer refer to it by that name.

2

Declare what it needs

Which parts of the shared history it reads or writes, with what access, and which events it records there. Anything not declared here is refused automatically when your code tries to reach for it.

3

Declare what it provides

Its callable operations and the kinds of data records it writes. One operation declaration becomes a typed method, a live message type, an agent tool, and a terminal command, all at once.

4

Declare who may install it

A minimum trust level a person needs before they're offered the install at all.

5

Sign it as one unit

Packaging computes a hash over your package's code, its declared assets, and its dependency pins, and signs that into a sidecar record alongside the manifest. The platform recomputes and checks that hash before it will load your package, so tampering after signing is caught immediately.

The manifest and the signed sidecar are two different things doing two different jobs: the manifest is what your package declares about itself; the signed sidecar is proof that what's running is what was actually signed.

A trimmed manifest shape. The field names are real; the id is a placeholder.

// A package manifest is one typed constant. The daemon reads it to decide
// what your package is allowed to do before any of its code runs.
export const MANIFEST: NaomsFeatureManifest = {
  id: "hello-package",
  name: "Hello Package",
  version: "0.1.0",
  category: "productivity",

  // What this package is allowed to read or write, and who may install it.
  capabilities: [{ name: "hello.read", trustLevel: "connected" }],
  permissions: { minTrustLevel: "connected", domainScopable: false },

  // One operation here becomes a typed method AND a live message type AND
  // an agent tool AND a terminal command -- one declaration, four surfaces.
  operations: [{
    name: "lookup",
    description: "Look something up.",
    version: 1,
    method: "ws_message",
    messageType: "hello_package.lookup",
    pattern: "send",
    returns: "HelloResult",
  }],
  chainTypes: [],
  graphTypes: [],
};

How it relates to other steps

Build

The manifest is what your handlers are checked against while you're still writing them; packaging is what turns the finished result into one signed, movable unit.

Test

Your package's tests run against the same manifest declarations, so a test can't quietly pass against access the manifest never actually granted.

Distribute

What gets uploaded to a Hive or listed on a hub is this signed unit only, never your raw source folder.