Files
zeekay aa258b0988 Add the iOS lane: hanzo-templates had zero of them
The catalogue shipped 71 web templates and one EMPTY `mobile` repo, so
"build an app" had no starting point on the platform people actually
ship to. This is the iOS lane — Expo/React Native and Flutter for
cross-platform, SwiftUI for native.

The constraint that shaped every file here: an iOS archive needs macOS +
Xcode + a signing identity, and our arc fleet has none. hanzoai has 519
registered runners and every one reports `os: linux`; luxfi has 151, same
story; zooai has none. The only macOS builds in the org today
(hanzoai/world build-desktop.yml) run on GitHub-HOSTED macos-14, which is
exactly what the house CI rule says not to do.

So `hanzo.yml` declares only what a Linux arc runner can genuinely
execute — typecheck + web bundle for Expo, analyze + test + web for
Flutter, `swiftc -parse` for SwiftUI — and the macOS archive lives in a
separate `workflow_dispatch`-only `ios.yml`. A job pinned to a label no
runner advertises would sit queued forever if it fired on push; parking
it is honest, a permanently-yellow check is not. The README of every
template states the gap and the one command that closes it.

Same reasoning on the demos. Expo and Flutter both have a real web
target, so `<slug>.hanzo.app` serves the SAME source the simulator runs.
SwiftUI has no web target, so those two templates ship with no demo link
rather than a screenshot pretending to be one.

Upstreams are permissive only and recorded per template: expo/expo
templates (MIT), flutter/samples (BSD-3-Clause), XcodeGen (MIT).

Second measured gap, found while wiring this up: `hanzo-templates` is not in
arcd's `orgs:` list either (hanzoai, luxfi, zooai, parsdao, zenlm), so the
Linux jobs would queue with no runner too. Both gaps are one installer
re-run, no code change; both are spelled out in every README rather than
left to be discovered on the first red build.

Third gap, found by probing rather than assuming, and FIXED here: every
run in this org died as `startup_failure` with no logs and no annotation.
A bare `runs-on: [self-hosted, linux]` probe queued fine while the same
job importing hanzoai/ci failed identically at @v1 and at a pinned SHA —
so it was never the tag. The org defaulted GITHUB_TOKEN to `read`, and
the reusable declares `permissions: packages: write`; a caller cannot
exceed the org maximum, so GitHub kills the run before creating a job.
hanzo-templates now defaults to `write` like hanzoai/luxfi/zooai, and
runs reach `queued` — the honest state, waiting on gap 2.
2026-07-27 23:25:25 -07:00

3.2 KiB

Hanzo Flutter

Material 3 starter — NavigationBar, search, detail route, widget tests.

Live demo — https://flutter.hanzo.app — the same app, compiled to WebAssembly by flutter build web. Not a mock-up.

What you get

NavigationBar over an IndexedStack so each tab keeps its own scroll position, a SliverAppBar.large feed, a SearchBar filter and two widget tests that actually drive the UI.

Run it

flutter pub get
flutter run             # -d ios for the simulator
flutter test
flutter build web --release

Building for iOS — read this first

Our runner fleet cannot produce an iOS build today. Two separate gaps, both measured rather than assumed:

  1. No macOS runner exists. An archive / IPA needs macOS + Xcode + a signing identity. Every runner registered to hanzoai (519 of them) reports os: linux; luxfi has 151, same; zooai has none. The only macOS builds in the org today (hanzoai/world build-desktop.yml) run on GitHub-hosted macos-14, which is what the house CI rule exists to avoid.
  2. hanzo-templates is not in the arcd org list. arcd serves hanzoai, luxfi, zooai, parsdao, zenlm. Until this org is added, even the Linux jobs in hanzo.yml sit queued with no runner to claim them.

A third gap turned up while wiring this and is already fixed: this org defaulted GITHUB_TOKEN to read, and hanzoai/ci declares permissions: packages: write. A caller cannot be granted more than the org maximum, so every run died as startup_failure before a job was even created — no logs, no annotation, nothing to read. The org now defaults to write, the same as hanzoai, and runs reach queued. If you fork these into another org and see startup_failure with an empty log, check /orgs/<org>/actions/permissions/workflow first.

So hanzo.yml declares only what a Linux arc runner could run, and the macOS archive sits in a separate workflow_dispatch-only .github/workflows/ios.yml — a job pinned to a label nothing advertises would queue forever if it fired on push.

Both gaps close with the installer, no code change:

# (2) serve this org — re-run on any existing arcd host
~/work/hanzo/arc/scripts/install-arcd.sh \
  --labels self-hosted,linux,amd64 \
  --orgs hanzoai,luxfi,zooai,parsdao,zenlm,hanzo-templates

# (1) add the macOS lane — on an Apple Silicon Mac, once
xcode-select --install && sudo xcodebuild -license accept
~/work/hanzo/arc/scripts/install-arcd.sh \
  --labels self-hosted,macos,arm64,xcode \
  --orgs hanzoai,luxfi,zooai,parsdao,zenlm,hanzo-templates

Then runs-on: [self-hosted, macos, arm64, xcode] resolves and ios.yml archives + exports the IPA. Signing material comes from KMS (kms.hanzo.ai), never from a checked-in .p12.

CI

hanzo.yml + a seven-line .github/workflows/cicd.yml importing hanzoai/ci. On every push a Linux arc runner runs:

  • analyze — flutter analyze
  • test — flutter test
  • web-bundle — flutter build web --release

.github/workflows/ios.yml holds the macOS archive job and is workflow_dispatch only — see above.

Upstream

Derived from flutter/samples (BSD-3-Clause). This template is MIT; the upstream licence travels with the code it came from.