Templates and examples
tilo-app offers two ways to start an app, for two different needs.
A template is where you start when you know what you are building. It is
small, opinionated and yours: tilo-app new NAME --template T renders it
once, and from then on it is your code. A template carries only what every app
of its shape needs, so there is little to delete.
An example is where you go to learn one idea. It is a complete, runnable
program that does one thing well, with tests that state the rules it teaches.
You read it in examples/apps/, run it, and when it is close to what you want
you start from it with tilo-app new NAME --from-example E, which copies it
and renames it to your app.
Both follow the app HIG: every colour and size from the theme, every word from a Fluent catalog, only shared widgets, apps that start empty, and every capability an action.
Templates
| Template | Starts you with |
|---|---|
starter (default) |
One resource, one bound field, one action: the smallest correct app. |
document |
One collaborative document with a live preview, undo and a destructive clear. |
collection |
Items the user adds, edits, checks off and removes, each with its own actions. |
graph |
Serialized, live-editable screens above controls bound to the resource. |
tilo-app new --list-templates prints this list (--json for scripts). The
shapes earlier versions offered as templates (data, list, tree, workspace,
async, qr) were each teaching one widget rather than giving an app a
starting point, so they are examples now; naming one tells you which.
The starter’s generated tests exercise its public actions and live controls, Viewer refusal, persistence, and a two-participant edit. That journey checks that sync updates both replicas and the running view, history retains the peer’s authorship, and local undo/redo preserves the collaborator’s edit. It exchanges production resource documents headlessly; it does not certify network transport or sign-in on two devices.
Examples
| Example | Teaches | Web |
|---|---|---|
counter |
Resources and actions: validation, undo, confirmation, roles. | yes |
bound-controls |
Text, checkbox, number, slider and dropdown bound to fields. | yes |
virtual-list |
A sparse, virtualized list with stable keys and row controls. | yes |
data-table |
Columns over a sparse table model, cells that invoke actions. | yes |
tree-browser |
Tree navigation and an adaptive master-detail shell. | yes |
background-task |
Cancellable work off the UI thread, started through an action. | yes |
shared-checklist |
What merges when two people edit at once, and what undo takes back. | yes |
localized |
Catalogs, arguments, plurals, live language switching, pseudo-locale. | yes |
graph-screens |
Serialized screens, a Rust component mounted in one, the router. | yes |
qr-code |
A generated visual with alternative text, empty until it has input. | yes |
Inspect one example or read just its embedded source without a repository checkout or network access:
tilo-app examples shared-checklist
tilo-app examples shared-checklist --file tests/app.rs --json
tilo-app examples shared-checklist --file src/lib.rs
The named command lists that example’s files and scaffold command. With
--file, human output is the file itself; JSON carries the selected example,
file and content. Files come from the installed CLI’s embedded examples,
so the tests and code match the examples that version of new copies. Unknown
paths report the available files.
tilo-app examples prints this list (--json for scripts, with each
example’s path and whether it is web-capable). The examples that load data or
compute in the background do it through ui::background, which runs on a
thread where the target has one and on the page’s executor on the web.
The column is what the portability lint finds, not a promise: the lint records
the sites of its web rules (threads, the std clock, std files and sockets:
W1-W3 in tools/policy/app_portability_rules.toml) apart from its findings, and
every_example_is_indexed_and_portable fails when an example’s Web flag
disagrees with it. tilo-app build --platform web refuses an app that uses
one. CI builds every web-capable example for the web when one of them, or the
web build itself, changes: tools/ci/build-web-examples.sh builds the web core
once with those examples in its collection, then each example’s app module.
Where they live and how they stay correct
Examples are workspace members under examples/apps/<name>/, package
example-<name>, app id so.tilo.example.<name>. Being members means every
change to the SDK compiles, lints and tests them: CI’s affected-package
selection runs their Clippy and tests, and tilo-app check --lint --all lints
them with the apps.
Each example was generated by tilo-app new and then rewritten, and the CLI
test every_example_is_what_new_renders_for_it keeps it that way: rendering
the example under its own identity must reproduce every file in its directory
byte for byte. So its Cargo.toml, tilo-app.toml and src/main.rs are
exactly what new writes, and the files that are the example’s own are the
ones the CLI embeds and copies. an_app_from_an_example_is_renamed_and_ready
starts a standalone app from each example and runs tilo-app doctor on it.
Every example has tests (tests/app.rs, through Replica and TestApp), a
native-contract certification test, and a saved headless scenario
(tests/headless-actions.json) that tilo-app check runs with the
accessibility audit. CI runs those scenarios too, for every example its
affected-package selection tests: tools/ci/example-scenarios.sh drives each
example’s own binary through tilo-app scenario run --audit, the same stage
tilo-app check runs.
Adding an example: create it with
tilo-app new example-NAME --id so.tilo.example.NAME --directory examples/apps/NAME
(move its workspace member line under # Examples), rewrite it, and add it to
crates/dev/tilo-app-cli/src/examples.rs, examples/README.md and the table
above. The CLI tests fail until all four agree.
This page is docs/examples.md in the Tilo repository, at 29fbb80121. Changes to it are made there.