AI skill
Copy a compact assistant skill for Otalan SDK setup, CLI publishing, and safe credential boundaries.
Use this page when you want an AI coding assistant to work inside an Otalan app repository.
The skill is intentionally small. It tells the assistant how to pick the right runtime package, keep keys separated, use Bun, and publish through the CLI without confusing app runtime setup with release automation.
How to use it with agents
There are three useful ways to give this skill to an AI agent.
Option 1: share the skill URL
Sharing the page URL works when the agent has web access and is allowed to read external documentation. This is the easiest path for hosted agents and IDE agents with browsing enabled.
Read and follow the Otalan AI skill at https://otalan.com/docs/tooling/ai-skill.
This is a Capacitor app.
Wire the Otalan runtime SDK, update .env.example, and prepare the CLI publish flow.
Do not add real keys. Use placeholders only.
Before you let the agent edit, ask it to confirm what it read:
Before changing files, summarize the Otalan rules you will follow and list the files you expect to inspect.
If the agent says it cannot browse, paste the skill text instead of the URL.
Option 2: commit it as repository instructions
For agents that read repository instructions automatically, add the skill to the file the agent reads before editing:
- Codex: put it in
AGENTS.mdat the repository root, or in the nearestAGENTS.mdfor the app folder. - Claude Code: put it in
CLAUDE.md. - Cursor: put it in
.cursor/rules/otalan.mdor your project rules. - Copilot or a generic chat agent: paste it into repository instructions, then reference it in the task.
This is the best option for teams because every future task inherits the same Otalan rules.
Option 3: paste it into one task
If the agent has no web access and no repository instruction file, paste the skill block into the chat before the task. Then ask for one concrete job:
Use the Otalan SDK and CLI skill. This is a Capacitor app. Wire the runtime SDK, update .env.example, and leave the publish flow ready for CI without adding real keys.
Give the agent the app type, expected appId, channel, platform, runtimeVersion, build command, and whether it should only prepare files or also run local commands.
Do not paste real OTA App Keys or OTA Publish Keys into an agent prompt. Use placeholders in code and put real values in local env files or CI secrets.
Copy the skill
Paste this into your repository's AI instructions, such as AGENTS.md, CLAUDE.md, .cursor/rules, or a tool-specific skill file.
# Otalan SDK and CLI skill
Use this skill when a task touches Otalan OTA setup, runtime SDK integration, bundle generation, publishing, rollback, or release automation.
## Core rules
- Use Bun commands for package and CLI work.
- Do not replace Bun commands with npm, yarn, or pnpm unless the repository explicitly uses that package manager.
- Use an OTA App Key only in installed mobile apps.
- Use an OTA Publish Key only in local release tooling or CI.
- Use `OTALAN_API_KEY` as the CLI secret name, and store an OTA Publish Key value such as `otalan_ci_...` in it.
- Never put an OTA Publish Key in Expo public env vars, Vite public env vars, frontend code, or mobile app code.
- Keep every release scoped to one exact `appId`, `platform`, `channel`, and `runtimeVersion`.
- Native code, native plugins, permissions, entitlements, and runtime-version changes still require an App Store or Play Store release.
## Task intake
Before editing, identify or ask for:
- runtime: Expo or Capacitor
- package manager and lockfile
- app ID, platform, channel, and runtime version
- local build command and generated web output directory
- where app env vars live
- where CI secrets and release commands live
- whether the task is app runtime setup, CLI publish setup, rollback, or troubleshooting
## First checks
- Detect whether the app is Expo or Capacitor before editing.
- Read existing env files, app config, build output paths, and package scripts.
- Prefer existing project conventions, but keep Otalan commands on Bun.
- Update `.env.example` when adding Otalan env vars.
- Run lint and typecheck after changing app code.
- Do not run `otalan publish`, rollback, pause, or resume without explicit user approval.
## CLI release flow
```bash
# Install the Otalan CLI globally with Bun.
bun add -g @otalan/cli
# Save the Otalan API URL and OTA Publish Key for release automation.
otalan login --api-key "$OTALAN_API_KEY" --api-url "${OTALAN_API_URL:-https://api.otalan.com}"
# Link this repository to the Otalan app.
otalan init --app-id "$OTALAN_APP_ID"
# Create `.otalan/bundle/bundle-<bundle-id>.zip` and any target-specific metadata.
otalan bundle --target "$OTALAN_TARGET" --platform "$OTALAN_PLATFORM" --runtime-version "$OTALAN_RUNTIME_VERSION"
# Upload, validate, and activate the bundle.
otalan publish --channel "$OTALAN_CHANNEL"
```
## Capacitor SDK setup
```bash
# Install the Otalan Capacitor runtime and required native update packages.
bun add @otalan/capacitor @capawesome/capacitor-live-update @capacitor/app @capacitor/core
# Sync native Capacitor projects after changing plugins.
bunx cap sync
```
Use `@otalan/capacitor` for the installed app runtime. Keep one initialized updater instance and expose a function such as `syncOtalanUpdates()` that can be called from app boot, settings, or another user interaction.
`initializeUpdater()` prepares install confirmation and the optional resume listener. It does not run a launch update check by itself; call `syncOtalanUpdates()` when update work should run.
## Expo SDK setup
```bash
# Install the Otalan Expo helper.
bun add @otalan/expo
# Install Expo update and application modules with Expo's version resolver.
bunx expo install expo-updates expo-application
```
Use `@otalan/expo` with `expo-updates` and `expo-application`. Keep `expo-updates` runtime installation in Expo, and call `check()` when the app only needs `updateAvailable` or `sync()` when it should check and apply OTA work.
Set Expo `checkAutomatically` to `NEVER` when Otalan controls the check path, so Expo does not check before the Otalan helper is initialized.
Keep `x-api-key` declared in native `updates.requestHeaders`. `@otalan/expo` manages the stable rollout device ID and writes `otalan-device-id` to Expo update extra params, so app code should not add a separate Otalan device header.
## Foreground resume checks
When the app should load OTA work after the user sends it to the home screen and opens it again, wire a foreground/resume check instead of relying on a force-kill:
- Capacitor: keep `onResume: true` in `initializeUpdater(...)`; the initialized helper runs a deduplicated sync when the app resumes.
- Expo: listen for React Native `AppState` returning to `active` and call `syncOtalanUpdates()` from that handler.
- Keep Expo `checkAutomatically` as `NEVER` for Otalan staged rollouts; the app-state handler should call the Otalan helper, not bypass it.
- If the host app already has app-state listeners, reuse that path and avoid firing repeated checks on every small state transition.
## Local HTTP testing
- For Android local HTTP testing, allow cleartext only in development, for example with `android:usesCleartextTraffic="true"` in the Android manifest or the framework's equivalent Android config.
- For Capacitor bundle downloads over plain HTTP, also pass `allowInsecureBundleUrls: true` only in local development.
- Do not ship cleartext or insecure bundle URL settings in production builds.
## Publish checks
- For Capacitor, build the web app before `otalan bundle`.
- Add `.otalan/` to `.gitignore`; it is generated bundle output.
- For Expo, use `otalan bundle --target expo` so `.otalan/bundle/manifest.json` is generated.
- Publish with the exact channel and runtime version the installed app checks.
- Verify one update and one rollback before widening rollout.
- If rollback is needed, roll back only to a bundle already registered in the same release tuple.
## Task templates
Capacitor setup:
```text
Use the Otalan SDK and CLI skill. This is a Capacitor app. Wire `@otalan/capacitor`, add placeholder Vite env vars, update `.env.example`, keep publish keys out of app code, and run the relevant checks.
```
Expo setup:
```text
Use the Otalan SDK and CLI skill. This is an Expo app with `expo-updates`. Wire `@otalan/expo`, keep `checkAutomatically` controlled by Otalan, update `.env.example`, and run the relevant checks.
```
CI publish setup:
```text
Use the Otalan SDK and CLI skill. Add a CI publish path using `otalan bundle` and `otalan publish`. Use CI secret names only, never real keys, and keep the release tuple explicit.
```
Troubleshooting:
```text
Use the Otalan SDK and CLI skill. Inspect why this app is not receiving an OTA update. Check the app ID, platform, channel, runtime version, key type, bundle output, and whether Expo or Capacitor is handling runtime installation.
```
Foreground resume check:
```text
Use the Otalan SDK and CLI skill. Add a foreground/resume OTA check so sending the app to the home screen and opening it again calls `syncOtalanUpdates()` and can load a newly published compatible bundle without force-killing the app.
```
## Expected output
When finished, report:
- files changed
- Otalan env vars added or expected
- whether app code uses an OTA App Key only
- whether release automation uses an OTA Publish Key only
- commands run
- commands the user still needs to run manually
- any publish or rollback action that was intentionally not executed
## Useful docs
- `/docs/quick-start/capacitor`
- `/docs/quick-start/expo`
- `/docs/tooling/cli`
- `/docs/tooling/sdk`