---
title: "Publishing"
description: "Publishing turns an Indicator into a release on the OpenMarket platform: om publish sends the package (the built module, the sheet, the manifest and the one…"
order: 47
section: "functions"
---

<!-- source: docs/indicators/functions/publishing.md; generated by packages/cli/scripts/gen-indicator-docs.ts, do not edit -->

# Publishing

Publishing turns an Indicator into a release on the OpenMarket platform:
`om publish` sends the package (the built module, the sheet, the manifest
and the one source entry the manifest names) to `chart.openmarket.xyz`,
where the release is a script beside your grants, versions and buyers, and
`--script <id>` lands it on a script you already own. Every other kind (a
watch pack, a kScript (legacy) package) publishes to the registry, and
installing an Indicator is unchanged: `om install @scope/name` puts it on
any machine, the chart's Indicators tab adds it, and every consumer reads
it by metric id. Three doors open on the same release: the editor's
**Publish** popup, `om publish` on your machine, and the agent's
`package_publish`.

## Dry run, then publish

```bash
om publish ./my-sma --dry-run
om publish ./my-sma
```

The dry run validates the directory (the manifest `om-package.json`, the
sheet, the built module and the source entry) and prints exactly what
would ship (files, size, sha256, the target and, with `--script`, the
script id) without uploading; nothing needs a wallet or a login. The real
publish confirms once at the terminal (`--yes` for scripts), names the
script before you confirm when `--script` picked one, uploads under your
OpenMarket username (the scope is never chosen), and prints the release
with its script id. An Indicator release carries no cover and no price:
`--cover`, `--artwork` and a `pricing` tag are typed refusals before any
upload (the platform door has neither); a watch pack on the registry lane
keeps the cover question a first version asks.

In the editor, **Publish** opens the registry in a popup: a package name
(`/name`), a version (`MAJOR.MINOR.PATCH`), a visibility, a description
([The editor](../getting-started/the-editor.md)). From `om chat` or MCP,
`package_publish` runs with `dry_run: true` first, then the real publish
behind an approval card (`yes: true` over MCP only after your explicit
intent) ([Author with an agent](../getting-started/with-an-agent.md)).

## Rules that hold at publish

- The kind is `wrun-indicator`, read off the manifest. The module, the
  sheet and exactly ONE source file ship: the entry the manifest's `source`
  block names (`{ "language": "assemblyscript", "entry": "src/indicator.ts" }`
  is the default a scaffold needs no block for), because a buyer with
  view-source rights reads it; `src/gen/` and `src/sdk/` are regenerated on
  every build and never travel. A package built from an opaque module
  (`--wasm` with no source beside it) exports fine and is refused at
  publish.
- The scope is your username: `@local` is reserved for drafts and the
  registry rejects it, so re-author the same source under your own scope
  before publishing.
- Versions are permanent. A published version is never changed, and there
  is no yank: a wrong pin or a wrong default after publish means a bumped
  version, and the only removal is [deleting the package](#deleting-and-removal).
- An Indicator package declares no `dependencies`: it reads another package
  through a `metric` composition input in its sheet, never through a pin
  (a watch pack is the kind that pins the packages its watches read).
- A publish failure is typed: the platform door's refusal names what to
  fix in its own words, and the registry lane's codes each carry a hint
  (`missing_api_key` / `api_key_invalid` for the account key the CLI
  holds, `publish_scope_refused`, `publish_name_refused`,
  `publish_signer_refused`, `publish_not_permitted`, `publish_rejected`,
  `registry_unavailable` / `registry_unreachable`). The dry run reproduces
  every local refusal without uploading.

## The package page

`openmarket.xyz/@scope/name` is the public address of a package: it opens
the registry page, unfurls a preview card in a chat, and installs when
pasted after `om install`. `om open @scope/name` opens a fresh chart with
the package mounted at its latest published version (`@scope/name@x.y.z`
pins one), and `om packages show @scope/name` prints its sheet.

```bash
om open @you/my-sma
om packages show @you/my-sma
```

## What consumers get

```bash
om search sma --kind wrun-indicator
om install @you/my-sma
om install @you/my-sma --replace
om chart indicator add --type wrun/@you/my-sma/sma --params period=30
```

Installs verify the tarball sha256, write a `receipt.json` (source plus
verified hash) into the installed package directory, and pin exactly what
was fetched. Nothing from a package executes at install time (no install
scripts), the module runs sandboxed (no filesystem, no network, no order
capability), and alerts that reference the package pin the exact version
and hash: upgrades are explicit (`om indicator upgrade @you/my-sma`).

After publish, hosted charts mount the package by metric id: the chart
backend fetches it from the registry, so the order is publish, install,
add. Bindable packages are the exception: hosted adds carry no market
binding, so their chart surface stays the local preview.

## Visibility and access

An Indicator release's grants live beside its script on the platform. On
the registry lane (a watch pack, a kScript (legacy) package) the
`om-package.json` `visibility` field controls discovery: `public`
(default), `unlisted` (installable by exact name, hidden from search), or
`private` (entitlement-gated), and private access is owner-managed:

```bash
om access grant @you/my-sma some-account-id --label "Desk A"
om access list @you/my-sma
om access revoke @you/my-sma some-account-id
om access packages
```

Grant subjects are a bare account id, `public:retail` / `public:all`, or
`group:<label>`; `om access groups` manages member groups end to end
(create, rename, members, add, remove, renew, packages), and `om access edit`
rewrites a grant's rights or expiry in place. `om install` sends your
account key automatically when a package turns out to be private; an
account without a grant gets a clear `not_entitled` error.

## Deleting and removal

```bash
om packages delete @you/my-sma
om indicator remove @you/my-sma
```

`om packages delete` (owner only) deletes the package from the registry:
the name is gone for good, nothing can be published under it again at any
version, and every read of it answers `deleted by the author`. Installed
copies keep running and nobody is notified; holders read the words where
the package is listed (`om packages`, the `/packages` pane, the follows
list). `om indicator remove` uninstalls locally and warns when installed
alerts still reference the package's metrics, so rewire or remove those
first.

## Another registry for one command

```bash
om install @you/my-sma --registry production
```

`--registry` names the registry for one registry-lane command: an
`om install` of any kind, and an `om publish` of a kind that publishes to
the registry (a watch pack); an Indicator's publish goes to the platform
door whatever `--registry` says. The values are `production`
(`registry.openmarket.xyz`), `staging` (`registry-staging.openmarket.xyz`,
the default until launch), or the origin `OM_REGISTRY_URL` names (a
self-hosted registry or a rig); any other origin is refused before a
request goes out, because your account key only ever travels to a registry
this machine trusts. `OM_REGISTRY_URL` keeps setting the default for every
other command, and `package_publish` and `package_install` take the same
value as `registry`.
