Build an applet
Start with one useful outcome: what should the phone notice, decide or show, and how will the owner know it worked? Most applets combine existing phone features with an HTML card. They need no native build or APK installation.
1. Find just the pieces you need
Read the short builder starter, then search the compact capability index. Follow only the selected capability detail, for example v1.watches or v1.interactions, and its exact operation schema. The full catalog and endpoint reference are bulk references, not required first reads.
Choose the closest recipe: pet activity, room changes, receipt OCR, voice notes, daily briefing or device dashboard. Each separates public composition from native-only behavior and names controller work.
After the owner authorizes connection, use the paired base URL and credentials; check GET /v1/health, GET /v1/capabilities and the installed guide. Source documentation, released APK, installed support and ready-to-use access are different states. Confirm grants, switches, Android permissions/resources and unlock requirements before running. A public example grants no access.
2. Let the phone run the routine
- Watch:
POST /v1/watchesruns bounded sensing, local filtering, optional Jev/Clef decisions, tally and rules on the phone while your controller is offline. Use an explicit interval, expiry and paid-call cap. Cameramodel:noneis free image-change detection, not object or danger recognition. - Schedule:
POST /v1/scheduleruns an owner-approved manifest on the phone. Inspect and merge the existing manifest first; a new submission awaiting owner approval is not active. Android doze can delay runs. - Controller: use a controller for integrations or reasoning the phone cannot perform. Its timers, subscriptions, receipt/notebook storage and synthesized briefings stop when that process stops. A card is not a background controller; bridge actions work while the card is open without your controller, subject to the same grants.
Jev answers typed text/photo questions; Clef also handles bounded audio/video through the documented decision service. These are remote calls, require internet and share current quotas/budget. Free camera comparison may reuse an older answer until its configured freshness limit; a reused result is not new model evidence. Inspect usage and skipped checks. Read decision contracts, costs and limits before adding inference.
External devices need a supported adapter, owner-authorized enrollment, the correct agent grant and the phone on the required local network. Listing an enrolled device does not probe it or prove it online. Native Pet Monitor Auto camera selection, bounded pan search and portal are separate from a generic camera watch; do not claim the recipe inherits them.
3. Adapt a complete, attractive HTML card
Start from the complete room-change card body or editable receipt card body; these contain real styled HTML for POST /v1/interactions, not a URL for the phone to load. Follow the recipe to create the watch first and bind its returned ID, or select the authorized image ID. Templates make no capture or polling call on load. Keep their loading, empty, stale, error, paused and stopped states.
For a first authorized connection check use GET /v1/samples?id=html-connection-test. Keep its response bridge and confirm the answer. Show rich HTML adapted from existing templates for owner-visible tests. A notification being delivered is not proof that the card opened or the owner answered.
HTML runs offline, with inline styles/scripts, data images and no network access. No keys belong in the page. The posting agent's grants and switches govern each bridge call. Use the real completion contracts:
const bridge = window.Bridgit || window.Bridget;
// watchId is the real ID returned by this agent's watch creation.
const result = await bridge.act({
method: 'POST', path: '/v1/watches/' + watchId + '/pause',
body: {paused: true}
});
if (!result.ok || result.body.user_paused !== true) {
// Show the error; do not claim the watch paused.
}
// One pending answer for this card's current question view.
// Register before responding, so a fast acknowledgement is not missed.
document.addEventListener('bridgit:answered', function () {
// Bridgit saved the answer. Controller execution is still unconfirmed.
}, {once: true});
bridge.respond(JSON.stringify({action: 'archive'}));
Send the complete HTML body, retain interaction_id, inspect display, then wait with GET /v1/interactions/{id}?wait=55 or one event subscription for several cards. Read HTML responses from answer.data. An accepted action resolves to {ok,status,body}; inspect the expected state or ID, not just HTTP success. See the template, lifecycle and compatibility guide.
4. Verify, pause and stop
Test a bounded known example with the owner's authorization. Show the source timestamp, cache reuse and missing coverage. Unavailable cameras, ambiguous audio, skipped quota checks and absent pets are unknown, not negative findings. Verify the owner answer or requested state before reporting success; distinguish parser checks from real device/model results.
Pause a watch with POST /v1/watches/{id}/pause and {paused:true}; confirm user_paused. Resume with false; expiry is unchanged. To change its definition, archive needed tally/history, delete the old watch and create a replacement with a new ID. Stop with DELETE /v1/watches/{id}, confirm deleted matches the saved ID, and follow watch.ended when available. Cancelling its interaction is a separate action.
Schedule pause affects the agent's whole manifest. Remove only this recipe's actions by submitting a replacement if the manifest is shared. A local card Stop button cannot prove an external controller stopped; confirm that job separately. An in-flight capture may finish unless its actual API supports cancellation.
Stopping does not erase every record. Interaction answers, logs, configured capture storage, schedule assets, native history and controller copies have their own lifetimes. Generic watch tally has bounded retention; archive it before deleting the watch. Schedule deletion removes saved assets unless keep_assets=true. Explain what is retained and use each feature's documented deletion controls; never promise that only logs remain.
Optional: add native integration
Only change the Android app when the existing APIs cannot meet the goal or the owner specifically wants native integration. Follow the repository's current instructions and tested native patterns such as City tour; document ownership, grants, stop/cancellation and retention, then add canonical endpoint/tool descriptions and focused tests. Ordinary recipe applets do not require this step.
Build versions come from tools/allocate-apk-version.py: a locked shared high-water allocator across worktrees, not a git commit count. Preserve every allocated counter, including test allocations and deliberate gaps; never lower, restore or reuse one. Publish only through the supported release rail after its gates. Native/device tests need separate owner authorization and truthful evidence.