FrontierOS SDK · Browser JavaScript
Build an app. Give it a skill.
The SDK connects a sandboxed browser mini-app to Gotchi Local. Your JavaScript runs in an isolated frame; a permission-checked bridge provides app-owned storage and Watcher display/input. Local keeps its login cookie, device transport and privileged APIs outside that frame.
Run the Tally example
Tally counts completed tasks, saves its count across restarts and registers a callable tally.add skill. Its browser and Watcher buttons use the same handler. You can use it without a device.
- Use the Gotchi Local source version that includes the Mini apps runtime, and set a password in its web interface.
- Extract the ZIP and run
python3 install.pyfrom itsexample-sdkfolder. Python 3.10+ bundles the JavaScript and installs it in~/.gotchi/mini-apps/tally. - Restart Local, reload
http://127.0.0.1:8088, sign in and open Mini apps → Tally. - Click Add one, then reopen the app and confirm its count persists. With a linked Watcher, open Tally in its launcher and press or tap its Add one button.
The SDK download does not update an older Local installation or firmware. Use the updated Local source; Watcher rendering needs remote-UI-capable firmware and an active Local connection.
If your Local launcher has no Mini apps entry, that installation does not contain the required runtime. Restarting it or downloading this ZIP will not add the runtime; update Local from the project source first. Publishing these Hub docs also does not update Local’s download or your device.
Change the source
| File | Purpose |
|---|---|
| manifest.json | Identity, version, Local target and declared capabilities. |
| index.html | Browser interface and script bundle markers. |
| app.js | App logic, skill handler and Watcher scene. |
| frontier-sdk.js | Reusable browser client and scene helpers. |
| install.py | Local bundling and installation without dependencies. |
Create a callable skill
const sdk = await FrontierOS.connect();
sdk.registerSkill("tally.add", "Add to your tally", async ({ delta = 1 }) => {
if (!Number.isInteger(delta) || delta < 1 || delta > 100) {
throw new Error("delta must be an integer from 1 to 100");
}
return { count: await sdk.storage.increment("count", delta) };
});
const result = await sdk.invokeSkill("tally.add", { delta: 1 });Skills are named handlers inside the sandbox. Validate arguments before acting and return a JSON-compatible result. Calls through the SDK run sequentially; atomic storage increments prevent concurrent additions from overwriting each other. The Local host can explicitly invoke registered skills, and your app can call them directly.
Automatic voice-agent tool selection is not integrated. Registering a skill does not change the agent’s tool policy or grant new capabilities.
Make it yours
Change the manifest’s ID and name, the scene’s app ID and the skill namespace. Edit the HTML and JavaScript, then run python3 install.py --replace to replace installed source while retaining its stored data.
Verify your changes
node --test test_sdk.mjs
python3 -m unittest -v test_install.pyThese checks cover SDK connection, persistence calls, skills and installer boundaries. Local has separate permission and scene-validation tests. Run your modified app in Local before sharing it; a Hub listing draft does not upload or install your source.