🚧 The Passport Prime SDK is in public beta. Got an idea, or want a dev unit to play with? We'd love to hear from you — hello@foundation.xyz .

What is an app on KeyOS?

An app is a Rust binary crate that runs as an isolated process under the Xous microkernel. Each app gets its own address space, its own storage scope, and its own declared permissions — all enforced by the kernel. There is no runtime escalation path.

Apps compile to the armv7a-unknown-xous-elf target, are signed with cosign2, and are installed under apps/<app-name>/ on the device.

Project layout

my-app/
├── app-config.toml              # app identity, publisher, permissions, signing
├── Cargo.toml
├── build.rs                     # Slint code generation (router, exports, i18n)
├── src/
│   └── main.rs                  # entry point
├── ui/
│   ├── app.slint                # top-level UI component
│   └── pages/                   # per-page components (multi-page-app template)
├── resources/
│   └── icon.svg                 # launcher icon
└── i18n/
    └── en.json                  # translation strings

foundation new my-app scaffolds this layout for you. Two templates ship with the SDK:

  • default-app — single-page starter
  • multi-page-app — router-based multi-screen starter

app-config.toml

This is the source of truth for your app's identity, publisher metadata, required permissions, and signing configuration. Every field maps one-to-one onto an internal AppConfig struct — no hidden defaults.

app-name = "my-app"
friendly-app-name = "My App"
launcher-app-name = "My App"
description = "Example application"
icon = "resources/icon.svg"
app-id = "0x00112233445566778899aabbccddeeff"
version = "0.1.0"
min-keyos-version = "1.0.0"
signing-identity = "Example Company"
cosign2-config = "~/.foundation/signing/my-app/cosign2.toml"

[publisher]
name = "Example Company"
contact-email = "support@example.com"
support-url = "https://example.com/support"

[permissions]
"os/settings" = ["GetDeviceName"]

Field reference

FieldRequiredNotes
app-name✅Cargo package name and build output directory name
friendly-app-name✅Display name
launcher-app-name—Falls back to friendly-app-name
description✅One-line description
icon✅Path relative to the project root; validated at build time
app-id✅0x-prefixed even-length hex; must be unique on the device
version✅Semver
min-keyos-version✅Minimum KeyOS version your app requires
signing-identity—Selects an identity under ~/.foundation/signing/<name>/
cosign2-config—Explicit path to a cosign2.toml; overrides identity resolution
[publisher]✅name, contact-email, support-url
[permissions]✅Per-service entries: "os/<service>" = ["MethodA", "MethodB"]

The UI: Slint with a curated component library

KeyOS apps use Slint for UI. The SDK exposes a stable @ui/... import surface — a curated library of Foundation-designed components, theme tokens, fonts, and icons. Your app imports from @ui and inherits a polished, on-brand starting point that you're free to fully restyle.

A minimal ui/app.slint:

import { BaseWindow } from "@ui/widgets.slint";
import { Button } from "@ui/widgets.slint";

export component AppWindow inherits BaseWindow {
    Button {
        text: "Hello, Prime";
        clicked => { debug("button pressed"); }
    }
}

Components available from @ui/...:

  • Form controls — Input, Checkbox, RadioButton, Slider, Dropdown, Switch, Pagination, SegmentedSelector
  • Navigation — Drawer, Dialog, ModalWindow, PopupMenu
  • Display — Card, Chip, Badge, Button, IconButton, Progress, QR code renderer
  • Specialized — AuthWidget, CryptoFiatField, SeedWords, PinEntry, SlideToButton, FileList
  • Theming — ColorPicker, CircularProgress, Shimmer, full design tokens

Live-preview any .slint file with foundation preview ui/app.slint.

A minimal src/main.rs

The app! macro from slint_keyos_platform wires your top-level AppWindow into the KeyOS runtime:

// SPDX-License-Identifier: Apache-2.0

use slint_keyos_platform::app;

app!("My App");

fn app_main(_cx: AppContext, ui: AppWindow) {
    log_server::init_wait(env!("CARGO_CRATE_NAME")).unwrap();
    log::set_max_level(log::LevelFilter::Info);
    log::info!("My App starting");

    // The Slint event loop runs automatically inside app!()
    // Wire up UI callbacks, spawn tasks, subscribe to IPC events here.
}

Build, simulate, preview

From inside an SDK shell (foundation develop):

foundation new my-app              # scaffold from template
cd my-app
foundation sim                     # hosted simulator (debug)
foundation preview ui/app.slint    # live Slint preview
foundation build                   # release-quality signed hardware build
foundation sideload                # build + copy to Prime + launch

See the CLI Reference for every flag.

Signing

Every app on Prime is signed. foundation build signs app.elf in place with cosign2 using a secp256k1 key.

One-time identity setup:

foundation cert gen "My Company"

This writes four files to ~/.foundation/signing/My Company/:

  • private.pem — secp256k1 private key (keep secret)
  • public.pub — compressed public key hex
  • certificate.crt — self-signed X.509 code-signing certificate
  • cosign2.toml — the config foundation build consumes

Identity resolution order at build time:

  1. cosign2-config in app-config.toml (explicit path)
  2. signing-identity in app-config.toml (name under ~/.foundation/signing/)
  3. An identity whose name matches [publisher].name
  4. The only configured identity, if exactly one exists
  5. Interactive prompt (errors in non-interactive contexts)

Prime's app launcher verifies the signature against the embedded certificate chain before starting your app. Tampered or unsigned binaries are refused.

Registering your developer certificate on Prime

🚧 Coming soon. The flow for installing a developer's public key / X.509 certificate onto Prime (so sideloaded apps built under your identity are trusted) is still being designed. Expected to live under the Apps section in Settings. Watch this space — or email hello@foundation.xyz if you're an early-access partner and need the current interim flow.

Toolchain

ComponentDetail
Rust toolchainNightly, pinned by the SDK
Target triplearmv7a-unknown-xous-elf
Build flagsRUSTFLAGS="--cfg keyos -C relocation-model=pic -C link-arg=-pie" for hardware, --cfg keyos for simulator
Signingcosign2 (secp256k1 + X.509)
Build orchestrationcargo + foundation CLI (cargo xtask for SDK maintainers)
EnvironmentNix flake (foundation develop enters it)

You don't install Rust or manage the cross-compiler manually — foundation develop hands you a shell with everything already in place.

Next