Feature-detect before using itif (window.chaaga && chaaga.filePicker) { … } — so a sub-app still opens sensibly if it's ever loaded outside the app (e.g. a plain browser tab), and so it degrades instead of throwing on a capability a given platform/OS version doesn't support.
Errors — every async method here returns a real Promise. A rejection is always a plain Error whose message is a short, stable code (e.g. permission_denied, unsupported_platform) — check e.message, not the exact wording, since the text around it isn't guaranteed to stay the same. "User cancelled/backed out" is not an error on most of these — it resolves null instead, noted per method below.

chaaga.subAppId

A plain string — this sub-app's own id. Available immediately, with no await, unlike everything else on this page.

console.log(chaaga.subAppId); // "a1b2c3"

chaaga.filePicker

Native file/photo picking.

chaaga.llm

Fetching reference data and making LLM calls, both routed natively.

const reply = await chaaga.llm.chat.completions.create({
  messages: [{ role: 'user', content: 'Say hi in five words.' }]
});
console.log(reply.content);

chaaga.screenrecording Android only

Records the whole screen via a foreground service — survives the app being backgrounded. On iOS, every method below rejects unsupported_platform (no iOS implementation yet); build the feature but say plainly it's Android-only if asked about iOS.

chaaga.wakelock

Keeps the screen on.

Automatically released when the app leaves this sub-app, so it never needs disabling "just in case" on unmount — only call disable() when the app's own UI state says the screen no longer needs to stay on (e.g. a workout finished).

chaaga.scanner

chaaga.contacts

chaaga.notifications

Local notifications — one-shot, recurring, or immediate — with tap routing back into this sub-app.

A one-shot notification (schedule()) is consumed once it fires — it drops off list() afterward. A recurring one (recurring()) keeps firing indefinitely until you cancel() it; note that after its first fire, the whenMs a recurring entry reports from list() stays at that original time rather than updating to the true next occurrence.
await chaaga.notifications.requestPermission();
await chaaga.notifications.recurring({
  id: 'water-reminder',
  title: 'Drink some water',
  body: 'Stay hydrated!',
  hour: 14,
  minute: 0
}); // every day at 14:00

chaaga.notifications.onTapped = ({ id }) => {
  console.log('tapped', id);
};

Camera & microphone

Not part of window.chaaga — use the standard navigator.mediaDevices.getUserMedia(...) as you would in any browser; the app grants the underlying OS permission automatically when the page asks.