---
name: rastrillo-native
description: Build native companions for Rastrillo apps using shared Swift components, an Apple app scaffold and optional Go Mobile bindings.
---

# Rastrillo Native

Optional sibling of Rastrillo web. Source and review:
`https://amadan.net/rastrillo/native`. Swift product/module:
`RastrilloNative`, iOS 17+ and macOS 14+. Pin the package to a reviewed
revision and read this file from that checkout. Core Rastrillo does not
import native tooling.

Start from `examples/companion/project.yml` and `Sources/Companion.swift`.
Copy into the app; replace the local package path with the repository URL
and revision, set app-owned bundle IDs, run `xcodegen generate`. The example
checks `/api/version` only; it supplies no authenticated session. The app
owns linking, navigation, storage, signing and release policy.

## Prefer native UI

Aim for a fully native interface wherever practical. Meeting the platform's
expectations can substantially improve daily use: navigation, selection,
menus, context menus/right-click, keyboard shortcuts, accessibility, links,
windows and system sharing should behave as people already expect. Treat
those behaviours as part of the feature, not final polish. Share logic and
contracts freely; let each platform own how the feature is presented.

For a complex app, a native navigation layer around selected webview screens
can avoid duplicating a large working surface. Use that as a deliberate
boundary: keep app navigation, menus, contextual actions and link routing
native, and expose typed actions from the embedded screen. Route internal
links to native destinations and ordinary external links through the
platform's normal browser behaviour. Do not intercept text editing or
replace useful web behaviour with a less capable native imitation.

If both clients would otherwise duplicate navigation and action definitions,
consider a shared app manifest compiled into separate web and native
presentations. Share destination IDs, available commands, capabilities and
link intent; each renderer chooses platform-appropriate controls. A command
may appear in a web toolbar, a Mac menu/context menu, or an iPhone action
menu. Avoid encoding DOM trees, pixel layout or one platform's navigation
model as the common schema. See [docs/app-architecture.md](docs/app-architecture.md).
This is architectural guidance, not an existing dual-target generator;
Rastrillo's current resource manifests generate web CRUD only.

## Shared components

`@MainActor CoalescedRunner.run` serializes one refresh operation. A burst
during a pass queues one trailing pass; callers await its completion.
Trailing passes reuse the first caller's closure. Keep one runner per
operation/account, handle errors inside the closure, and never recursively
call it from the work it runs. Cancelling a waiter does not cancel shared
work. Existing consumers can keep their public API with
`public typealias CoalescedRunner = RastrilloNative.CoalescedRunner`.

Native platform integrations belong in platform adapters. Share API and
crypto contracts with the web app; replay the same golden vectors before
claiming compatible bytes. Reuse Rastrillo crypto/keyring where compatible;
do not migrate existing envelopes just to use the package. Native secure
storage, browser key storage, Web Push and APNs/FCM have different lifecycle
contracts. Never treat aviso as native push transport.

For an app with reusable Go logic, read [docs/go-mobile.md](docs/go-mobile.md).
Go Mobile is optional; the shipped Swift component does not require it.
Android bindings and UI are not supplied by this first package.

Run `make ci`: Swift tests plus unsigned iOS simulator and macOS builds.
Consumer adoption also runs that app's core tests and builds; a package
test alone cannot detect a missing Xcode dependency. Keep release/device
checks distinct from compile checks.
