# Build and publish an App

An App is an independently authored user-facing bundle opened by the desktop
AppHost from Home or while an Environment is active. It uses an App session and must not mount
`AlAmrWidget`, receive an Environment Runtime token, or inspect the host scene.

## Outcome

At the end you will have:

- an App revision published with one immutable bundle inventory;
- the exact published revision enabled for Runtime use by an administrator;
- a verified archive, entry document, and every inventoried file;
- a proven launch of the exact revision by an independent consumer principal.

Publication alone never makes an App available. A separate administrator
enables the exact revision; see [App availability](/docs/publish/app-availability).

## Supported variants

| Variant             | Declaration                         | Notes                                                                |
| ------------------- | ----------------------------------- | -------------------------------------------------------------------- |
| Compact             | `"modes": ["compact"]`              | Mandatory mobile-width product surface; every App supports it        |
| Compact + Workspace | `"modes": ["compact", "workspace"]` | Adds a large desktop Widget surface with scene inset, not fullscreen |

An App backend is optional; `@al-amr/backend` is a verification/helper library
for server code, not a service every App must run. Notifications are optional
and work from the open App without a backend; delegated background delivery is
a further reviewed declaration.

## Build and publication prerequisites

Every copyable command below uses the complete pinned
`npx @al-amr/cli@0.1.0-alpha.7` invocation. This version is available for the
human/CLI journey; the official Agent Context Pack still requires promotion.

- the exact public CLI version and integrity advertised on the [Start page](/start). The generated
  `package.json` records the selected package manager; use that exact manager
  for subsequent project commands;
- an Al-Amr developer account and access to the target Registry;
- the Al-Amr desktop client for local preview and consumer launch proof. The App
  frontend needs no domain, TLS certificate, callback URL, or hosting account.

## Exact steps

### 1. Scaffold and run

```sh
npx @al-amr/cli@0.1.0-alpha.7 create app my-app --yes --json
cd my-app
pnpm install
pnpm build
npx @al-amr/cli@0.1.0-alpha.7 dev --json
# Run the `open` command returned in nextActions.
```

The scaffold contains `al-amr.app.json`, a bundle entry,
`createEmbeddedAppClient`, a required Compact layout, and no backend or
requested capability by default. For every iteration, build, run `alamr dev
--json`, and execute its `open` next action; the development link closes any
older loose preview and opens the new bytes with explicit local-preview authority.

### 2. Connect to the desktop AppHost

The starter defaults to `https://registry.al-amr.com` and writes the Registry
selected during creation to `.env.example`. Configure a different issuer from
the App deployment, not from the parent page:

```ts
import { createEmbeddedAppClient } from "@al-amr/sdk";

const client = createEmbeddedAppClient({
  appId: manifest.appId,
  registryBaseUrl: import.meta.env.VITE_REGISTRY_URL,
});

const session = await client.connect();
```

The SDK keeps its verifier and App token in memory. Use
`session.displayMode` or `client.snapshot.hostSession.displayMode` to select
Compact or Workspace composition. Check
`client.snapshot.hostSession.grantedCapabilities` before using an optional
feature.

### 3. Design Compact, then optionally Workspace

Compact is mandatory and must remain usable without horizontal scrolling and
without assuming hover. Add Workspace only when the product benefits from a
wide desktop composition:

```json
{
  "display": {
    "modes": ["compact", "workspace"],
    "preferredMode": "workspace",
    "background": "none"
  }
}
```

Switching modes no longer reloads the App: subscribe with
`client.subscribePresentation(...)` and re-compose. Save durable state in your
backend anyway — a revision change or a recovered fault still relaunches you —
and use a bounded exit handler for dirty drafts; the host deadline is one second
and owns the confirmation UI:

```ts
client.setBeforeExitHandler(async () => {
  if (!draft.dirty) return { disposition: "allow" };
  return (await saveDraft())
    ? { disposition: "allow" }
    : { disposition: "confirm", message: "Discard the unsaved draft?" };
});
```

### 4. Request only needed capabilities

Capability requests are exact reviewed product declarations:

```json
{
  "capabilities": {
    "required": [
      {
        "id": "platform.environment.identity.read@1",
        "versionRange": "^1.0.0"
      },
      {
        "id": "host.spatial.context.read@1",
        "versionRange": "^1.0.0"
      }
    ],
    "optional": [
      {
        "id": "host.spatial.locations.read@1",
        "versionRange": "^1.0.0"
      }
    ]
  }
}
```

A required denial prevents launch. An optional denial must leave a useful
reduced experience. Dependencies such as Environment identity for spatial
context must be declared at the same or stronger level. Registry shows
disclosures and records consent before launch. For spatial methods and
Environment adapter requirements, follow
[App Host Services](/docs/architecture/app-host-services). Never infer Zone or
location from URLs and never store host coordinates as portable identity.

### 5. Add notifications if the product needs them

Declare every event type:

```json
{
  "notifications": {
    "eventTypes": [
      {
        "type": "task.completed",
        "label": "Task completed",
        "policy": {
          "family": "generic",
          "subject": {
            "mode": "per_occurrence",
            "revision": "event_identity"
          },
          "effects": ["raise"],
          "preferenceKey": "task.completed",
          "pulse": "none",
          "presentation": { "kind": "source" }
        }
      }
    ],
    "backgroundDelivery": "none"
  }
}
```

Also request `platform.notifications.publish.self@1`, then signal the immutable
source fact from the open App:

```ts
await client.signalNotificationOccurrence({
  eventId: "task-job_42-completed",
  eventType: "task.completed",
  occurredAt: completedAt,
  effect: "raise",
  content: {
    kind: "source",
    title: "Export complete",
    action: { kind: "open_app" },
  },
});
```

Keep `eventId` and `occurredAt` unchanged when retrying. This works without an
App backend, but only while the App session is active. For offline or scheduled
delivery, declare delegated background delivery, request both notification
capabilities, create the user delegation from the App, and commit a durable
outbox item that retries `workload.signal(...)` through `@al-amr/backend`.
Follow [Platform notifications](/docs/architecture/notifications); never send a
raw user ID to your backend. `publishNotification(...)` remains an additive
legacy method for immutable callers, not the authoring path for a new App.

### 6. Validate, link, build, and test the immutable revision

```sh
npx @al-amr/cli@0.1.0-alpha.7 validate --json
npx @al-amr/cli@0.1.0-alpha.7 login --device --json
npx @al-amr/cli@0.1.0-alpha.7 link --yes --json
npx @al-amr/cli@0.1.0-alpha.7 build --json
npx @al-amr/cli@0.1.0-alpha.7 test --yes --json
```

`validate` applies the same executable schema as Registry, including mandatory
Compact mode, preferred-mode membership, capability dependencies, notification
declarations, and background-delivery requirements.

`alamr build` runs the project's real production build after Registry identity
has been synchronized. `alamr test` inventories, packs, uploads, binds, and
checks those exact bytes in one non-interactive workflow. It creates a fresh
immutable App revision when the build generation changes, so code-only releases
never collide with older bytes. The inventory is derived during `alamr test`;
there is no current local `.al-amr/app-build.json` authoring file.

### 7. Submit the tested bundle

```sh
npx @al-amr/cli@0.1.0-alpha.7 publish --yes --json
```

`publish` submits the exact revision and build digest that passed `alamr test`.
It does not rebuild, upload different bytes, or contact a publisher host.
Changed bytes require another build and test, which creates or selects the
matching immutable generation.

### 8. Enable the exact published revision and prove an independent launch

After human review and publication, a Registry administrator explicitly enables
the exact active revision — through the Admin Panel App page or the equivalent
public CLI workflow:

```sh
npx @al-amr/cli@0.1.0-alpha.7 admin apps list --json
npx @al-amr/cli@0.1.0-alpha.7 admin apps enable app_example rev_example_1 \
  --reason "Approved for platform-wide Runtime use" --json
```

In v0.x this availability is global: the enabled App is offered to every
compatible Environment. Environment-specific availability is not implemented.
A new App revision is never enabled implicitly; after it is reviewed and
published, an administrator must enable that exact revision.

Finally, launch the enabled App from the Widget of a compatible Environment
with an account that does not own the Project. The authoring Journey fails with
`ALAMR_APP_LAUNCH_MISSING` until that launch is proven, and with
`ALAMR_APP_CONSUMER_PRINCIPAL_NOT_INDEPENDENT` when the consumer principal is
the publisher owner.

## Files and public contracts

- `al-amr.app.json` — the App manifest; schema in the
  [manifest reference](/reference/manifests);
- `createEmbeddedAppClient` from `@al-amr/sdk` — the only supported Widget
  connection surface; see the [SDK reference](/reference/sdk);
- `client.authorizationHeader()` — the credential your App backend introspects
  through Registry before keying durable records by the verified
  `appActorSub`.

## Human gates

| Gate                                    | Actor                                    | What is approved                                             |
| --------------------------------------- | ---------------------------------------- | ------------------------------------------------------------ |
| `alamr login` browser or device handoff | The human account owner                  | The exact displayed device code and URL                      |
| `alamr link`                            | The Project owner                        | Binding this directory to the exact Registry Project         |
| `alamr publish --yes`                   | The Project owner                        | Submission of the exact snapshot and build digests           |
| Review decision                         | An independent human reviewer            | The frozen evidence; owner and submitter cannot self-review  |
| Publication transition                  | An independent publication administrator | The exact approved digests; the reviewer cannot publish      |
| Availability enable                     | A Registry administrator                 | Enabling the exact published revision with a recorded reason |

## Expected structured outputs

| Command                              | Success evidence                                                                            |
| ------------------------------------ | ------------------------------------------------------------------------------------------- |
| `alamr validate --json`              | Process code `0`, `ok: true`, and a valid manifest message                                  |
| `alamr build --json`                 | The project build completed after Registry identity synchronization                         |
| `alamr test --yes --json`            | Publication checks completed with the bound `buildDigest`, submission ID, and check results |
| `alamr publish --yes --json`         | `Publication submission sent for review.`                                                   |
| `alamr admin apps enable ... --json` | The availability record: `appId`, `revisionId`, `enabled: true`, and `updatedAt`            |
| `alamr status --json`                | The authoritative Registry submission state and allowed next actions                        |

## Stable errors and remediation

| Code                          | Meaning                                                       | Retryable | Remediation                                                                    |
| ----------------------------- | ------------------------------------------------------------- | --------- | ------------------------------------------------------------------------------ |
| `ALAMR_USAGE`                 | Invalid arguments or options                                  | No        | Run `alamr --help` and correct the invocation                                  |
| `ALAMR_AUTH_REQUIRED`         | Missing or expired credential                                 | No        | Run `alamr login` or supply a scoped Project token                             |
| `ALAMR_NETWORK_ERROR`         | Registry unreachable                                          | Yes       | Check DNS/TLS/proxy and Registry health, then retry                            |
| `app_build_artifact_required` | The App revision has no immutable build binding               | No        | Run a fresh build and `alamr test --yes --json`                                |
| `app_build_snapshot_changed`  | The submission names a different build digest                 | No        | Never bind different bytes to a submitted revision; create a new revision      |
| `app_build_artifact_invalid`  | The bound inventory no longer recomputes to its digest        | No        | Create a new App revision; a bound inventory is never edited in place          |
| `app_contract_incompatible`   | Manifest Contracts range rejects the current platform         | No        | Rebuild a new revision with the promoted Contracts declaration                 |
| `app_revision_not_found`      | Enable or publish named a missing revision                    | No        | Confirm the exact `appId` and `revisionId` with `alamr admin apps list --json` |
| `ALAMR_APP_LAUNCH_MISSING`    | No independent consumer launch proof for the enabled revision | Yes       | Launch the exact enabled revision from a compatible Environment Widget         |

The full index of stable codes is in [Troubleshooting](/docs/errors/troubleshooting).

## Definition of done

- Compact works as a complete mobile-width product; Workspace, when declared,
  is responsive to in-place presentation changes, and the Journey proves it
  (`ALAMR_APP_WORKSPACE_MODE_MISSING` otherwise).
- Required and optional capabilities match real behavior, and every Host
  Service call has a denied/unavailable state.
- The App product view never accepts or persists a parent Runtime token, and
  durable records use verified App-pairwise identity.
- Final publication, enable, and rollback select only verified held bundle bytes.
- An independent consumer principal launched the exact enabled revision.
- Privacy and canonical documentation describe all requested disclosures.

## Cleanup and recovery

- Any manifest, frontend, or byte change requires a new App revision and a new
  build/test cycle; never bind different bytes to an already
  submitted revision.
- A rejection leaves an immutable decision and history. If the exact revision,
  manifest, and frozen build bytes are unchanged, rerun `alamr test` and
  `alamr publish`; Registry can reopen that matching submission at `draft`
  without erasing the prior decision. Any content change requires a new App
  revision and submission.
- `alamr rollback app_revision <revisionId> --reason <text>` accepts only an
  eligible still-published revision with immutable build evidence and
  re-verifies its held bundle before activation.
- Historical manifest-only App revisions remain readable but cannot be newly
  submitted, published, enabled, or selected as a rollback destination.
- An administrator can withdraw Runtime availability with
  `alamr admin apps disable app_example rev_example_1 --reason <text> --json`.

Recovery procedures for every publication state are in
[Recovery](/docs/publish/recovery), and the full state machine is in
[Publication lifecycle](/docs/publish/publication-lifecycle). Read
[Apps](/docs/product/apps) and [Trust and security](/docs/security) before
publication.
