[{"data":1,"prerenderedAt":1881},["ShallowReactive",2],{"docs-page:en:\u002Fdocs\u002Ftooling\u002Fai-skill":3,"docs-navigation:en":1781},{"id":4,"title":5,"body":6,"description":1775,"extension":148,"meta":1776,"navigation":169,"path":1777,"seo":1778,"stem":1779,"__hash__":1780},"docs_en\u002Fen\u002Fdocs\u002Ftooling\u002Fai-skill.md","AI skill",{"type":7,"value":8,"toc":1766},"minimark",[9,13,16,21,24,29,32,43,46,52,55,59,62,93,96,100,103,109,126,129,133,144,1729,1733,1762],[10,11,12],"p",{},"Use this page when you want an AI coding assistant to work inside an Otalan app repository.",[10,14,15],{},"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.",[17,18,20],"h2",{"id":19},"how-to-use-it-with-agents","How to use it with agents",[10,22,23],{},"There are three useful ways to give this skill to an AI agent.",[25,26,28],"h3",{"id":27},"option-1-share-the-skill-url","Option 1: share the skill URL",[10,30,31],{},"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.",[33,34,40],"pre",{"className":35,"code":37,"language":38,"meta":39},[36],"language-text","Read and follow the Otalan AI skill at https:\u002F\u002Fotalan.com\u002Fdocs\u002Ftooling\u002Fai-skill.\nThis is a Capacitor app.\nWire the Otalan runtime SDK, update .env.example, and prepare the CLI publish flow.\nDo not add real keys. Use placeholders only.\n","text","",[41,42,37],"code",{"__ignoreMap":39},[10,44,45],{},"Before you let the agent edit, ask it to confirm what it read:",[33,47,50],{"className":48,"code":49,"language":38,"meta":39},[36],"Before changing files, summarize the Otalan rules you will follow and list the files you expect to inspect.\n",[41,51,49],{"__ignoreMap":39},[10,53,54],{},"If the agent says it cannot browse, paste the skill text instead of the URL.",[25,56,58],{"id":57},"option-2-commit-it-as-repository-instructions","Option 2: commit it as repository instructions",[10,60,61],{},"For agents that read repository instructions automatically, add the skill to the file the agent reads before editing:",[63,64,65,76,83,90],"ul",{},[66,67,68,69,72,73,75],"li",{},"Codex: put it in ",[41,70,71],{},"AGENTS.md"," at the repository root, or in the nearest ",[41,74,71],{}," for the app folder.",[66,77,78,79,82],{},"Claude Code: put it in ",[41,80,81],{},"CLAUDE.md",".",[66,84,85,86,89],{},"Cursor: put it in ",[41,87,88],{},".cursor\u002Frules\u002Fotalan.md"," or your project rules.",[66,91,92],{},"Copilot or a generic chat agent: paste it into repository instructions, then reference it in the task.",[10,94,95],{},"This is the best option for teams because every future task inherits the same Otalan rules.",[25,97,99],{"id":98},"option-3-paste-it-into-one-task","Option 3: paste it into one task",[10,101,102],{},"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:",[33,104,107],{"className":105,"code":106,"language":38,"meta":39},[36],"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.\n",[41,108,106],{"__ignoreMap":39},[10,110,111,112,115,116,115,119,115,122,125],{},"Give the agent the app type, expected ",[41,113,114],{},"appId",", ",[41,117,118],{},"channel",[41,120,121],{},"platform",[41,123,124],{},"runtimeVersion",", build command, and whether it should only prepare files or also run local commands.",[10,127,128],{},"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.",[17,130,132],{"id":131},"copy-the-skill","Copy the skill",[10,134,135,136,115,138,115,140,143],{},"Paste this into your repository's AI instructions, such as ",[41,137,71],{},[41,139,81],{},[41,141,142],{},".cursor\u002Frules",", or a tool-specific skill file.",[33,145,149],{"className":146,"code":147,"language":148,"meta":39,"style":39},"language-md shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","# Otalan SDK and CLI skill\n\nUse this skill when a task touches Otalan OTA setup, runtime SDK integration, bundle generation, publishing, rollback, or release automation.\n\n## Core rules\n\n- Use Bun commands for package and CLI work.\n- Do not replace Bun commands with npm, yarn, or pnpm unless the repository explicitly uses that package manager.\n- Use an OTA App Key only in installed mobile apps.\n- Use an OTA Publish Key only in local release tooling or CI.\n- Use `OTALAN_API_KEY` as the CLI secret name, and store an OTA Publish Key value such as `otalan_ci_...` in it.\n- Never put an OTA Publish Key in Expo public env vars, Vite public env vars, frontend code, or mobile app code.\n- Keep every release scoped to one exact `appId`, `platform`, `channel`, and `runtimeVersion`.\n- Native code, native plugins, permissions, entitlements, and runtime-version changes still require an App Store or Play Store release.\n\n## Task intake\n\nBefore editing, identify or ask for:\n\n- runtime: Expo or Capacitor\n- package manager and lockfile\n- app ID, platform, channel, and runtime version\n- local build command and generated web output directory\n- where app env vars live\n- where CI secrets and release commands live\n- whether the task is app runtime setup, CLI publish setup, rollback, or troubleshooting\n\n## First checks\n\n- Detect whether the app is Expo or Capacitor before editing.\n- Read existing env files, app config, build output paths, and package scripts.\n- Prefer existing project conventions, but keep Otalan commands on Bun.\n- Update `.env.example` when adding Otalan env vars.\n- Run lint and typecheck after changing app code.\n- Do not run `otalan publish`, rollback, pause, or resume without explicit user approval.\n\n## CLI release flow\n\n```bash\n# Install the Otalan CLI globally with Bun.\nbun add -g @otalan\u002Fcli\n\n# Save the Otalan API URL and OTA Publish Key for release automation.\notalan login --api-key \"$OTALAN_API_KEY\" --api-url \"${OTALAN_API_URL:-https:\u002F\u002Fapi.otalan.com}\"\n\n# Link this repository to the Otalan app.\notalan init --app-id \"$OTALAN_APP_ID\"\n\n# Create `.otalan\u002Fbundle\u002Fbundle-\u003Cbundle-id>.zip` and any target-specific metadata.\notalan bundle --target \"$OTALAN_TARGET\" --platform \"$OTALAN_PLATFORM\" --runtime-version \"$OTALAN_RUNTIME_VERSION\"\n\n# Upload, validate, and activate the bundle.\notalan publish --channel \"$OTALAN_CHANNEL\"\n```\n\n## Capacitor SDK setup\n\n```bash\n# Install the Otalan Capacitor runtime and required native update packages.\nbun add @otalan\u002Fcapacitor @capawesome\u002Fcapacitor-live-update @capacitor\u002Fapp @capacitor\u002Fcore\n\n# Sync native Capacitor projects after changing plugins.\nbunx cap sync\n```\n\nUse `@otalan\u002Fcapacitor` 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.\n\n`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.\n\n## Expo SDK setup\n\n```bash\n# Install the Otalan Expo helper.\nbun add @otalan\u002Fexpo\n\n# Install Expo update and application modules with Expo's version resolver.\nbunx expo install expo-updates expo-application\n```\n\nUse `@otalan\u002Fexpo` 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.\n\nSet Expo `checkAutomatically` to `NEVER` when Otalan controls the check path, so Expo does not check before the Otalan helper is initialized.\n\nKeep `x-api-key` declared in native `updates.requestHeaders`. `@otalan\u002Fexpo` 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.\n\n## Foreground resume checks\n\nWhen the app should load OTA work after the user sends it to the home screen and opens it again, wire a foreground\u002Fresume check instead of relying on a force-kill:\n\n- Capacitor: keep `onResume: true` in `initializeUpdater(...)`; the initialized helper runs a deduplicated sync when the app resumes.\n- Expo: listen for React Native `AppState` returning to `active` and call `syncOtalanUpdates()` from that handler.\n- Keep Expo `checkAutomatically` as `NEVER` for Otalan staged rollouts; the app-state handler should call the Otalan helper, not bypass it.\n- If the host app already has app-state listeners, reuse that path and avoid firing repeated checks on every small state transition.\n\n## Local HTTP testing\n\n- 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.\n- For Capacitor bundle downloads over plain HTTP, also pass `allowInsecureBundleUrls: true` only in local development.\n- Do not ship cleartext or insecure bundle URL settings in production builds.\n\n## Publish checks\n\n- For Capacitor, build the web app before `otalan bundle`.\n- Add `.otalan\u002F` to `.gitignore`; it is generated bundle output.\n- For Expo, use `otalan bundle --target expo` so `.otalan\u002Fbundle\u002Fmanifest.json` is generated.\n- Publish with the exact channel and runtime version the installed app checks.\n- Verify one update and one rollback before widening rollout.\n- If rollback is needed, roll back only to a bundle already registered in the same release tuple.\n\n## Task templates\n\nCapacitor setup:\n\n```text\nUse the Otalan SDK and CLI skill. This is a Capacitor app. Wire `@otalan\u002Fcapacitor`, add placeholder Vite env vars, update `.env.example`, keep publish keys out of app code, and run the relevant checks.\n```\n\nExpo setup:\n\n```text\nUse the Otalan SDK and CLI skill. This is an Expo app with `expo-updates`. Wire `@otalan\u002Fexpo`, keep `checkAutomatically` controlled by Otalan, update `.env.example`, and run the relevant checks.\n```\n\nCI publish setup:\n\n```text\nUse 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.\n```\n\nTroubleshooting:\n\n```text\nUse 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.\n```\n\nForeground resume check:\n\n```text\nUse the Otalan SDK and CLI skill. Add a foreground\u002Fresume 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.\n```\n\n## Expected output\n\nWhen finished, report:\n\n- files changed\n- Otalan env vars added or expected\n- whether app code uses an OTA App Key only\n- whether release automation uses an OTA Publish Key only\n- commands run\n- commands the user still needs to run manually\n- any publish or rollback action that was intentionally not executed\n\n## Useful docs\n\n- `\u002Fdocs\u002Fquick-start\u002Fcapacitor`\n- `\u002Fdocs\u002Fquick-start\u002Fexpo`\n- `\u002Fdocs\u002Ftooling\u002Fcli`\n- `\u002Fdocs\u002Ftooling\u002Fsdk`\n","md",[41,150,151,164,171,178,183,192,197,206,214,222,230,260,268,310,318,323,331,336,342,347,355,363,371,379,387,395,403,408,416,421,429,437,445,463,471,489,494,502,507,517,524,539,544,550,604,609,615,634,639,645,683,688,694,712,718,723,731,736,743,749,768,773,779,791,796,801,827,832,854,859,867,872,879,885,895,900,906,923,928,933,1007,1012,1038,1043,1088,1093,1101,1106,1112,1117,1145,1182,1208,1216,1221,1229,1234,1252,1270,1278,1283,1291,1296,1313,1340,1368,1376,1384,1392,1397,1405,1410,1416,1421,1429,1435,1440,1445,1451,1456,1463,1469,1474,1479,1485,1490,1497,1503,1508,1513,1519,1524,1531,1537,1542,1547,1553,1558,1565,1571,1576,1581,1589,1594,1600,1605,1613,1621,1629,1637,1645,1653,1661,1666,1674,1679,1693,1705,1717],{"__ignoreMap":39},[152,153,156,160],"span",{"class":154,"line":155},"line",1,[152,157,159],{"class":158},"sMK4o","# ",[152,161,163],{"class":162},"sBMFI","Otalan SDK and CLI skill\n",[152,165,167],{"class":154,"line":166},2,[152,168,170],{"emptyLinePlaceholder":169},true,"\n",[152,172,174],{"class":154,"line":173},3,[152,175,177],{"class":176},"sTEyZ","Use this skill when a task touches Otalan OTA setup, runtime SDK integration, bundle generation, publishing, rollback, or release automation.\n",[152,179,181],{"class":154,"line":180},4,[152,182,170],{"emptyLinePlaceholder":169},[152,184,186,189],{"class":154,"line":185},5,[152,187,188],{"class":158},"## ",[152,190,191],{"class":162},"Core rules\n",[152,193,195],{"class":154,"line":194},6,[152,196,170],{"emptyLinePlaceholder":169},[152,198,200,203],{"class":154,"line":199},7,[152,201,202],{"class":158},"-",[152,204,205],{"class":176}," Use Bun commands for package and CLI work.\n",[152,207,209,211],{"class":154,"line":208},8,[152,210,202],{"class":158},[152,212,213],{"class":176}," Do not replace Bun commands with npm, yarn, or pnpm unless the repository explicitly uses that package manager.\n",[152,215,217,219],{"class":154,"line":216},9,[152,218,202],{"class":158},[152,220,221],{"class":176}," Use an OTA App Key only in installed mobile apps.\n",[152,223,225,227],{"class":154,"line":224},10,[152,226,202],{"class":158},[152,228,229],{"class":176}," Use an OTA Publish Key only in local release tooling or CI.\n",[152,231,233,235,238,241,245,247,250,252,255,257],{"class":154,"line":232},11,[152,234,202],{"class":158},[152,236,237],{"class":176}," Use ",[152,239,240],{"class":158},"`",[152,242,244],{"class":243},"sfazB","OTALAN_API_KEY",[152,246,240],{"class":158},[152,248,249],{"class":176}," as the CLI secret name, and store an OTA Publish Key value such as ",[152,251,240],{"class":158},[152,253,254],{"class":243},"otalan_ci_...",[152,256,240],{"class":158},[152,258,259],{"class":176}," in it.\n",[152,261,263,265],{"class":154,"line":262},12,[152,264,202],{"class":158},[152,266,267],{"class":176}," Never put an OTA Publish Key in Expo public env vars, Vite public env vars, frontend code, or mobile app code.\n",[152,269,271,273,276,278,280,282,284,286,288,290,292,294,296,298,301,303,305,307],{"class":154,"line":270},13,[152,272,202],{"class":158},[152,274,275],{"class":176}," Keep every release scoped to one exact ",[152,277,240],{"class":158},[152,279,114],{"class":243},[152,281,240],{"class":158},[152,283,115],{"class":176},[152,285,240],{"class":158},[152,287,121],{"class":243},[152,289,240],{"class":158},[152,291,115],{"class":176},[152,293,240],{"class":158},[152,295,118],{"class":243},[152,297,240],{"class":158},[152,299,300],{"class":176},", and ",[152,302,240],{"class":158},[152,304,124],{"class":243},[152,306,240],{"class":158},[152,308,309],{"class":176},".\n",[152,311,313,315],{"class":154,"line":312},14,[152,314,202],{"class":158},[152,316,317],{"class":176}," Native code, native plugins, permissions, entitlements, and runtime-version changes still require an App Store or Play Store release.\n",[152,319,321],{"class":154,"line":320},15,[152,322,170],{"emptyLinePlaceholder":169},[152,324,326,328],{"class":154,"line":325},16,[152,327,188],{"class":158},[152,329,330],{"class":162},"Task intake\n",[152,332,334],{"class":154,"line":333},17,[152,335,170],{"emptyLinePlaceholder":169},[152,337,339],{"class":154,"line":338},18,[152,340,341],{"class":176},"Before editing, identify or ask for:\n",[152,343,345],{"class":154,"line":344},19,[152,346,170],{"emptyLinePlaceholder":169},[152,348,350,352],{"class":154,"line":349},20,[152,351,202],{"class":158},[152,353,354],{"class":176}," runtime: Expo or Capacitor\n",[152,356,358,360],{"class":154,"line":357},21,[152,359,202],{"class":158},[152,361,362],{"class":176}," package manager and lockfile\n",[152,364,366,368],{"class":154,"line":365},22,[152,367,202],{"class":158},[152,369,370],{"class":176}," app ID, platform, channel, and runtime version\n",[152,372,374,376],{"class":154,"line":373},23,[152,375,202],{"class":158},[152,377,378],{"class":176}," local build command and generated web output directory\n",[152,380,382,384],{"class":154,"line":381},24,[152,383,202],{"class":158},[152,385,386],{"class":176}," where app env vars live\n",[152,388,390,392],{"class":154,"line":389},25,[152,391,202],{"class":158},[152,393,394],{"class":176}," where CI secrets and release commands live\n",[152,396,398,400],{"class":154,"line":397},26,[152,399,202],{"class":158},[152,401,402],{"class":176}," whether the task is app runtime setup, CLI publish setup, rollback, or troubleshooting\n",[152,404,406],{"class":154,"line":405},27,[152,407,170],{"emptyLinePlaceholder":169},[152,409,411,413],{"class":154,"line":410},28,[152,412,188],{"class":158},[152,414,415],{"class":162},"First checks\n",[152,417,419],{"class":154,"line":418},29,[152,420,170],{"emptyLinePlaceholder":169},[152,422,424,426],{"class":154,"line":423},30,[152,425,202],{"class":158},[152,427,428],{"class":176}," Detect whether the app is Expo or Capacitor before editing.\n",[152,430,432,434],{"class":154,"line":431},31,[152,433,202],{"class":158},[152,435,436],{"class":176}," Read existing env files, app config, build output paths, and package scripts.\n",[152,438,440,442],{"class":154,"line":439},32,[152,441,202],{"class":158},[152,443,444],{"class":176}," Prefer existing project conventions, but keep Otalan commands on Bun.\n",[152,446,448,450,453,455,458,460],{"class":154,"line":447},33,[152,449,202],{"class":158},[152,451,452],{"class":176}," Update ",[152,454,240],{"class":158},[152,456,457],{"class":243},".env.example",[152,459,240],{"class":158},[152,461,462],{"class":176}," when adding Otalan env vars.\n",[152,464,466,468],{"class":154,"line":465},34,[152,467,202],{"class":158},[152,469,470],{"class":176}," Run lint and typecheck after changing app code.\n",[152,472,474,476,479,481,484,486],{"class":154,"line":473},35,[152,475,202],{"class":158},[152,477,478],{"class":176}," Do not run ",[152,480,240],{"class":158},[152,482,483],{"class":243},"otalan publish",[152,485,240],{"class":158},[152,487,488],{"class":176},", rollback, pause, or resume without explicit user approval.\n",[152,490,492],{"class":154,"line":491},36,[152,493,170],{"emptyLinePlaceholder":169},[152,495,497,499],{"class":154,"line":496},37,[152,498,188],{"class":158},[152,500,501],{"class":162},"CLI release flow\n",[152,503,505],{"class":154,"line":504},38,[152,506,170],{"emptyLinePlaceholder":169},[152,508,510,513],{"class":154,"line":509},39,[152,511,512],{"class":243},"```",[152,514,516],{"class":515},"sJsPd","bash\n",[152,518,520],{"class":154,"line":519},40,[152,521,523],{"class":522},"sHwdD","# Install the Otalan CLI globally with Bun.\n",[152,525,527,530,533,536],{"class":154,"line":526},41,[152,528,529],{"class":162},"bun",[152,531,532],{"class":243}," add",[152,534,535],{"class":243}," -g",[152,537,538],{"class":243}," @otalan\u002Fcli\n",[152,540,542],{"class":154,"line":541},42,[152,543,170],{"emptyLinePlaceholder":169},[152,545,547],{"class":154,"line":546},43,[152,548,549],{"class":522},"# Save the Otalan API URL and OTA Publish Key for release automation.\n",[152,551,553,556,559,562,565,568,571,574,577,580,583,586,589,592,594,596,598,601],{"class":154,"line":552},44,[152,554,555],{"class":162},"otalan",[152,557,558],{"class":243}," login",[152,560,561],{"class":243}," --api-key",[152,563,564],{"class":158}," \"",[152,566,567],{"class":176},"$OTALAN_API_KEY",[152,569,570],{"class":158},"\"",[152,572,573],{"class":243}," --api-url",[152,575,576],{"class":158}," \"${",[152,578,579],{"class":176},"OTALAN_API_URL",[152,581,582],{"class":158},":-",[152,584,585],{"class":176},"https",[152,587,588],{"class":158},":\u002F\u002F",[152,590,591],{"class":176},"api",[152,593,82],{"class":243},[152,595,555],{"class":176},[152,597,82],{"class":243},[152,599,600],{"class":176},"com",[152,602,603],{"class":158},"}\"\n",[152,605,607],{"class":154,"line":606},45,[152,608,170],{"emptyLinePlaceholder":169},[152,610,612],{"class":154,"line":611},46,[152,613,614],{"class":522},"# Link this repository to the Otalan app.\n",[152,616,618,620,623,626,628,631],{"class":154,"line":617},47,[152,619,555],{"class":162},[152,621,622],{"class":243}," init",[152,624,625],{"class":243}," --app-id",[152,627,564],{"class":158},[152,629,630],{"class":176},"$OTALAN_APP_ID",[152,632,633],{"class":158},"\"\n",[152,635,637],{"class":154,"line":636},48,[152,638,170],{"emptyLinePlaceholder":169},[152,640,642],{"class":154,"line":641},49,[152,643,644],{"class":522},"# Create `.otalan\u002Fbundle\u002Fbundle-\u003Cbundle-id>.zip` and any target-specific metadata.\n",[152,646,648,650,653,656,658,661,663,666,668,671,673,676,678,681],{"class":154,"line":647},50,[152,649,555],{"class":162},[152,651,652],{"class":243}," bundle",[152,654,655],{"class":243}," --target",[152,657,564],{"class":158},[152,659,660],{"class":176},"$OTALAN_TARGET",[152,662,570],{"class":158},[152,664,665],{"class":243}," --platform",[152,667,564],{"class":158},[152,669,670],{"class":176},"$OTALAN_PLATFORM",[152,672,570],{"class":158},[152,674,675],{"class":243}," --runtime-version",[152,677,564],{"class":158},[152,679,680],{"class":176},"$OTALAN_RUNTIME_VERSION",[152,682,633],{"class":158},[152,684,686],{"class":154,"line":685},51,[152,687,170],{"emptyLinePlaceholder":169},[152,689,691],{"class":154,"line":690},52,[152,692,693],{"class":522},"# Upload, validate, and activate the bundle.\n",[152,695,697,699,702,705,707,710],{"class":154,"line":696},53,[152,698,555],{"class":162},[152,700,701],{"class":243}," publish",[152,703,704],{"class":243}," --channel",[152,706,564],{"class":158},[152,708,709],{"class":176},"$OTALAN_CHANNEL",[152,711,633],{"class":158},[152,713,715],{"class":154,"line":714},54,[152,716,717],{"class":243},"```\n",[152,719,721],{"class":154,"line":720},55,[152,722,170],{"emptyLinePlaceholder":169},[152,724,726,728],{"class":154,"line":725},56,[152,727,188],{"class":158},[152,729,730],{"class":162},"Capacitor SDK setup\n",[152,732,734],{"class":154,"line":733},57,[152,735,170],{"emptyLinePlaceholder":169},[152,737,739,741],{"class":154,"line":738},58,[152,740,512],{"class":243},[152,742,516],{"class":515},[152,744,746],{"class":154,"line":745},59,[152,747,748],{"class":522},"# Install the Otalan Capacitor runtime and required native update packages.\n",[152,750,752,754,756,759,762,765],{"class":154,"line":751},60,[152,753,529],{"class":162},[152,755,532],{"class":243},[152,757,758],{"class":243}," @otalan\u002Fcapacitor",[152,760,761],{"class":243}," @capawesome\u002Fcapacitor-live-update",[152,763,764],{"class":243}," @capacitor\u002Fapp",[152,766,767],{"class":243}," @capacitor\u002Fcore\n",[152,769,771],{"class":154,"line":770},61,[152,772,170],{"emptyLinePlaceholder":169},[152,774,776],{"class":154,"line":775},62,[152,777,778],{"class":522},"# Sync native Capacitor projects after changing plugins.\n",[152,780,782,785,788],{"class":154,"line":781},63,[152,783,784],{"class":162},"bunx",[152,786,787],{"class":243}," cap",[152,789,790],{"class":243}," sync\n",[152,792,794],{"class":154,"line":793},64,[152,795,717],{"class":243},[152,797,799],{"class":154,"line":798},65,[152,800,170],{"emptyLinePlaceholder":169},[152,802,804,807,809,812,814,817,819,822,824],{"class":154,"line":803},66,[152,805,806],{"class":176},"Use ",[152,808,240],{"class":158},[152,810,811],{"class":243},"@otalan\u002Fcapacitor",[152,813,240],{"class":158},[152,815,816],{"class":176}," for the installed app runtime. Keep one initialized updater instance and expose a function such as ",[152,818,240],{"class":158},[152,820,821],{"class":243},"syncOtalanUpdates()",[152,823,240],{"class":158},[152,825,826],{"class":176}," that can be called from app boot, settings, or another user interaction.\n",[152,828,830],{"class":154,"line":829},67,[152,831,170],{"emptyLinePlaceholder":169},[152,833,835,837,840,842,845,847,849,851],{"class":154,"line":834},68,[152,836,240],{"class":158},[152,838,839],{"class":243},"initializeUpdater()",[152,841,240],{"class":158},[152,843,844],{"class":176}," prepares install confirmation and the optional resume listener. It does not run a launch update check by itself; call ",[152,846,240],{"class":158},[152,848,821],{"class":243},[152,850,240],{"class":158},[152,852,853],{"class":176}," when update work should run.\n",[152,855,857],{"class":154,"line":856},69,[152,858,170],{"emptyLinePlaceholder":169},[152,860,862,864],{"class":154,"line":861},70,[152,863,188],{"class":158},[152,865,866],{"class":162},"Expo SDK setup\n",[152,868,870],{"class":154,"line":869},71,[152,871,170],{"emptyLinePlaceholder":169},[152,873,875,877],{"class":154,"line":874},72,[152,876,512],{"class":243},[152,878,516],{"class":515},[152,880,882],{"class":154,"line":881},73,[152,883,884],{"class":522},"# Install the Otalan Expo helper.\n",[152,886,888,890,892],{"class":154,"line":887},74,[152,889,529],{"class":162},[152,891,532],{"class":243},[152,893,894],{"class":243}," @otalan\u002Fexpo\n",[152,896,898],{"class":154,"line":897},75,[152,899,170],{"emptyLinePlaceholder":169},[152,901,903],{"class":154,"line":902},76,[152,904,905],{"class":522},"# Install Expo update and application modules with Expo's version resolver.\n",[152,907,909,911,914,917,920],{"class":154,"line":908},77,[152,910,784],{"class":162},[152,912,913],{"class":243}," expo",[152,915,916],{"class":243}," install",[152,918,919],{"class":243}," expo-updates",[152,921,922],{"class":243}," expo-application\n",[152,924,926],{"class":154,"line":925},78,[152,927,717],{"class":243},[152,929,931],{"class":154,"line":930},79,[152,932,170],{"emptyLinePlaceholder":169},[152,934,936,938,940,943,945,948,950,953,955,958,960,963,965,968,970,972,974,977,979,982,984,987,989,992,994,997,999,1002,1004],{"class":154,"line":935},80,[152,937,806],{"class":176},[152,939,240],{"class":158},[152,941,942],{"class":243},"@otalan\u002Fexpo",[152,944,240],{"class":158},[152,946,947],{"class":176}," with ",[152,949,240],{"class":158},[152,951,952],{"class":243},"expo-updates",[152,954,240],{"class":158},[152,956,957],{"class":176}," and ",[152,959,240],{"class":158},[152,961,962],{"class":243},"expo-application",[152,964,240],{"class":158},[152,966,967],{"class":176},". Keep ",[152,969,240],{"class":158},[152,971,952],{"class":243},[152,973,240],{"class":158},[152,975,976],{"class":176}," runtime installation in Expo, and call ",[152,978,240],{"class":158},[152,980,981],{"class":243},"check()",[152,983,240],{"class":158},[152,985,986],{"class":176}," when the app only needs ",[152,988,240],{"class":158},[152,990,991],{"class":243},"updateAvailable",[152,993,240],{"class":158},[152,995,996],{"class":176}," or ",[152,998,240],{"class":158},[152,1000,1001],{"class":243},"sync()",[152,1003,240],{"class":158},[152,1005,1006],{"class":176}," when it should check and apply OTA work.\n",[152,1008,1010],{"class":154,"line":1009},81,[152,1011,170],{"emptyLinePlaceholder":169},[152,1013,1015,1018,1020,1023,1025,1028,1030,1033,1035],{"class":154,"line":1014},82,[152,1016,1017],{"class":176},"Set Expo ",[152,1019,240],{"class":158},[152,1021,1022],{"class":243},"checkAutomatically",[152,1024,240],{"class":158},[152,1026,1027],{"class":176}," to ",[152,1029,240],{"class":158},[152,1031,1032],{"class":243},"NEVER",[152,1034,240],{"class":158},[152,1036,1037],{"class":176}," when Otalan controls the check path, so Expo does not check before the Otalan helper is initialized.\n",[152,1039,1041],{"class":154,"line":1040},83,[152,1042,170],{"emptyLinePlaceholder":169},[152,1044,1046,1049,1051,1054,1056,1059,1061,1064,1066,1069,1071,1073,1075,1078,1080,1083,1085],{"class":154,"line":1045},84,[152,1047,1048],{"class":176},"Keep ",[152,1050,240],{"class":158},[152,1052,1053],{"class":243},"x-api-key",[152,1055,240],{"class":158},[152,1057,1058],{"class":176}," declared in native ",[152,1060,240],{"class":158},[152,1062,1063],{"class":243},"updates.requestHeaders",[152,1065,240],{"class":158},[152,1067,1068],{"class":176},". ",[152,1070,240],{"class":158},[152,1072,942],{"class":243},[152,1074,240],{"class":158},[152,1076,1077],{"class":176}," manages the stable rollout device ID and writes ",[152,1079,240],{"class":158},[152,1081,1082],{"class":243},"otalan-device-id",[152,1084,240],{"class":158},[152,1086,1087],{"class":176}," to Expo update extra params, so app code should not add a separate Otalan device header.\n",[152,1089,1091],{"class":154,"line":1090},85,[152,1092,170],{"emptyLinePlaceholder":169},[152,1094,1096,1098],{"class":154,"line":1095},86,[152,1097,188],{"class":158},[152,1099,1100],{"class":162},"Foreground resume checks\n",[152,1102,1104],{"class":154,"line":1103},87,[152,1105,170],{"emptyLinePlaceholder":169},[152,1107,1109],{"class":154,"line":1108},88,[152,1110,1111],{"class":176},"When the app should load OTA work after the user sends it to the home screen and opens it again, wire a foreground\u002Fresume check instead of relying on a force-kill:\n",[152,1113,1115],{"class":154,"line":1114},89,[152,1116,170],{"emptyLinePlaceholder":169},[152,1118,1120,1122,1125,1127,1130,1132,1135,1137,1140,1142],{"class":154,"line":1119},90,[152,1121,202],{"class":158},[152,1123,1124],{"class":176}," Capacitor: keep ",[152,1126,240],{"class":158},[152,1128,1129],{"class":243},"onResume: true",[152,1131,240],{"class":158},[152,1133,1134],{"class":176}," in ",[152,1136,240],{"class":158},[152,1138,1139],{"class":243},"initializeUpdater(...)",[152,1141,240],{"class":158},[152,1143,1144],{"class":176},"; the initialized helper runs a deduplicated sync when the app resumes.\n",[152,1146,1148,1150,1153,1155,1158,1160,1163,1165,1168,1170,1173,1175,1177,1179],{"class":154,"line":1147},91,[152,1149,202],{"class":158},[152,1151,1152],{"class":176}," Expo: listen for React Native ",[152,1154,240],{"class":158},[152,1156,1157],{"class":243},"AppState",[152,1159,240],{"class":158},[152,1161,1162],{"class":176}," returning to ",[152,1164,240],{"class":158},[152,1166,1167],{"class":243},"active",[152,1169,240],{"class":158},[152,1171,1172],{"class":176}," and call ",[152,1174,240],{"class":158},[152,1176,821],{"class":243},[152,1178,240],{"class":158},[152,1180,1181],{"class":176}," from that handler.\n",[152,1183,1185,1187,1190,1192,1194,1196,1199,1201,1203,1205],{"class":154,"line":1184},92,[152,1186,202],{"class":158},[152,1188,1189],{"class":176}," Keep Expo ",[152,1191,240],{"class":158},[152,1193,1022],{"class":243},[152,1195,240],{"class":158},[152,1197,1198],{"class":176}," as ",[152,1200,240],{"class":158},[152,1202,1032],{"class":243},[152,1204,240],{"class":158},[152,1206,1207],{"class":176}," for Otalan staged rollouts; the app-state handler should call the Otalan helper, not bypass it.\n",[152,1209,1211,1213],{"class":154,"line":1210},93,[152,1212,202],{"class":158},[152,1214,1215],{"class":176}," If the host app already has app-state listeners, reuse that path and avoid firing repeated checks on every small state transition.\n",[152,1217,1219],{"class":154,"line":1218},94,[152,1220,170],{"emptyLinePlaceholder":169},[152,1222,1224,1226],{"class":154,"line":1223},95,[152,1225,188],{"class":158},[152,1227,1228],{"class":162},"Local HTTP testing\n",[152,1230,1232],{"class":154,"line":1231},96,[152,1233,170],{"emptyLinePlaceholder":169},[152,1235,1237,1239,1242,1244,1247,1249],{"class":154,"line":1236},97,[152,1238,202],{"class":158},[152,1240,1241],{"class":176}," For Android local HTTP testing, allow cleartext only in development, for example with ",[152,1243,240],{"class":158},[152,1245,1246],{"class":243},"android:usesCleartextTraffic=\"true\"",[152,1248,240],{"class":158},[152,1250,1251],{"class":176}," in the Android manifest or the framework's equivalent Android config.\n",[152,1253,1255,1257,1260,1262,1265,1267],{"class":154,"line":1254},98,[152,1256,202],{"class":158},[152,1258,1259],{"class":176}," For Capacitor bundle downloads over plain HTTP, also pass ",[152,1261,240],{"class":158},[152,1263,1264],{"class":243},"allowInsecureBundleUrls: true",[152,1266,240],{"class":158},[152,1268,1269],{"class":176}," only in local development.\n",[152,1271,1273,1275],{"class":154,"line":1272},99,[152,1274,202],{"class":158},[152,1276,1277],{"class":176}," Do not ship cleartext or insecure bundle URL settings in production builds.\n",[152,1279,1281],{"class":154,"line":1280},100,[152,1282,170],{"emptyLinePlaceholder":169},[152,1284,1286,1288],{"class":154,"line":1285},101,[152,1287,188],{"class":158},[152,1289,1290],{"class":162},"Publish checks\n",[152,1292,1294],{"class":154,"line":1293},102,[152,1295,170],{"emptyLinePlaceholder":169},[152,1297,1299,1301,1304,1306,1309,1311],{"class":154,"line":1298},103,[152,1300,202],{"class":158},[152,1302,1303],{"class":176}," For Capacitor, build the web app before ",[152,1305,240],{"class":158},[152,1307,1308],{"class":243},"otalan bundle",[152,1310,240],{"class":158},[152,1312,309],{"class":176},[152,1314,1316,1318,1321,1323,1326,1328,1330,1332,1335,1337],{"class":154,"line":1315},104,[152,1317,202],{"class":158},[152,1319,1320],{"class":176}," Add ",[152,1322,240],{"class":158},[152,1324,1325],{"class":243},".otalan\u002F",[152,1327,240],{"class":158},[152,1329,1027],{"class":176},[152,1331,240],{"class":158},[152,1333,1334],{"class":243},".gitignore",[152,1336,240],{"class":158},[152,1338,1339],{"class":176},"; it is generated bundle output.\n",[152,1341,1343,1345,1348,1350,1353,1355,1358,1360,1363,1365],{"class":154,"line":1342},105,[152,1344,202],{"class":158},[152,1346,1347],{"class":176}," For Expo, use ",[152,1349,240],{"class":158},[152,1351,1352],{"class":243},"otalan bundle --target expo",[152,1354,240],{"class":158},[152,1356,1357],{"class":176}," so ",[152,1359,240],{"class":158},[152,1361,1362],{"class":243},".otalan\u002Fbundle\u002Fmanifest.json",[152,1364,240],{"class":158},[152,1366,1367],{"class":176}," is generated.\n",[152,1369,1371,1373],{"class":154,"line":1370},106,[152,1372,202],{"class":158},[152,1374,1375],{"class":176}," Publish with the exact channel and runtime version the installed app checks.\n",[152,1377,1379,1381],{"class":154,"line":1378},107,[152,1380,202],{"class":158},[152,1382,1383],{"class":176}," Verify one update and one rollback before widening rollout.\n",[152,1385,1387,1389],{"class":154,"line":1386},108,[152,1388,202],{"class":158},[152,1390,1391],{"class":176}," If rollback is needed, roll back only to a bundle already registered in the same release tuple.\n",[152,1393,1395],{"class":154,"line":1394},109,[152,1396,170],{"emptyLinePlaceholder":169},[152,1398,1400,1402],{"class":154,"line":1399},110,[152,1401,188],{"class":158},[152,1403,1404],{"class":162},"Task templates\n",[152,1406,1408],{"class":154,"line":1407},111,[152,1409,170],{"emptyLinePlaceholder":169},[152,1411,1413],{"class":154,"line":1412},112,[152,1414,1415],{"class":176},"Capacitor setup:\n",[152,1417,1419],{"class":154,"line":1418},113,[152,1420,170],{"emptyLinePlaceholder":169},[152,1422,1424,1426],{"class":154,"line":1423},114,[152,1425,512],{"class":243},[152,1427,1428],{"class":515},"text\n",[152,1430,1432],{"class":154,"line":1431},115,[152,1433,1434],{"class":515},"Use the Otalan SDK and CLI skill. This is a Capacitor app. Wire `@otalan\u002Fcapacitor`, add placeholder Vite env vars, update `.env.example`, keep publish keys out of app code, and run the relevant checks.\n",[152,1436,1438],{"class":154,"line":1437},116,[152,1439,717],{"class":243},[152,1441,1443],{"class":154,"line":1442},117,[152,1444,170],{"emptyLinePlaceholder":169},[152,1446,1448],{"class":154,"line":1447},118,[152,1449,1450],{"class":176},"Expo setup:\n",[152,1452,1454],{"class":154,"line":1453},119,[152,1455,170],{"emptyLinePlaceholder":169},[152,1457,1459,1461],{"class":154,"line":1458},120,[152,1460,512],{"class":243},[152,1462,1428],{"class":515},[152,1464,1466],{"class":154,"line":1465},121,[152,1467,1468],{"class":515},"Use the Otalan SDK and CLI skill. This is an Expo app with `expo-updates`. Wire `@otalan\u002Fexpo`, keep `checkAutomatically` controlled by Otalan, update `.env.example`, and run the relevant checks.\n",[152,1470,1472],{"class":154,"line":1471},122,[152,1473,717],{"class":243},[152,1475,1477],{"class":154,"line":1476},123,[152,1478,170],{"emptyLinePlaceholder":169},[152,1480,1482],{"class":154,"line":1481},124,[152,1483,1484],{"class":176},"CI publish setup:\n",[152,1486,1488],{"class":154,"line":1487},125,[152,1489,170],{"emptyLinePlaceholder":169},[152,1491,1493,1495],{"class":154,"line":1492},126,[152,1494,512],{"class":243},[152,1496,1428],{"class":515},[152,1498,1500],{"class":154,"line":1499},127,[152,1501,1502],{"class":515},"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.\n",[152,1504,1506],{"class":154,"line":1505},128,[152,1507,717],{"class":243},[152,1509,1511],{"class":154,"line":1510},129,[152,1512,170],{"emptyLinePlaceholder":169},[152,1514,1516],{"class":154,"line":1515},130,[152,1517,1518],{"class":176},"Troubleshooting:\n",[152,1520,1522],{"class":154,"line":1521},131,[152,1523,170],{"emptyLinePlaceholder":169},[152,1525,1527,1529],{"class":154,"line":1526},132,[152,1528,512],{"class":243},[152,1530,1428],{"class":515},[152,1532,1534],{"class":154,"line":1533},133,[152,1535,1536],{"class":515},"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.\n",[152,1538,1540],{"class":154,"line":1539},134,[152,1541,717],{"class":243},[152,1543,1545],{"class":154,"line":1544},135,[152,1546,170],{"emptyLinePlaceholder":169},[152,1548,1550],{"class":154,"line":1549},136,[152,1551,1552],{"class":176},"Foreground resume check:\n",[152,1554,1556],{"class":154,"line":1555},137,[152,1557,170],{"emptyLinePlaceholder":169},[152,1559,1561,1563],{"class":154,"line":1560},138,[152,1562,512],{"class":243},[152,1564,1428],{"class":515},[152,1566,1568],{"class":154,"line":1567},139,[152,1569,1570],{"class":515},"Use the Otalan SDK and CLI skill. Add a foreground\u002Fresume 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.\n",[152,1572,1574],{"class":154,"line":1573},140,[152,1575,717],{"class":243},[152,1577,1579],{"class":154,"line":1578},141,[152,1580,170],{"emptyLinePlaceholder":169},[152,1582,1584,1586],{"class":154,"line":1583},142,[152,1585,188],{"class":158},[152,1587,1588],{"class":162},"Expected output\n",[152,1590,1592],{"class":154,"line":1591},143,[152,1593,170],{"emptyLinePlaceholder":169},[152,1595,1597],{"class":154,"line":1596},144,[152,1598,1599],{"class":176},"When finished, report:\n",[152,1601,1603],{"class":154,"line":1602},145,[152,1604,170],{"emptyLinePlaceholder":169},[152,1606,1608,1610],{"class":154,"line":1607},146,[152,1609,202],{"class":158},[152,1611,1612],{"class":176}," files changed\n",[152,1614,1616,1618],{"class":154,"line":1615},147,[152,1617,202],{"class":158},[152,1619,1620],{"class":176}," Otalan env vars added or expected\n",[152,1622,1624,1626],{"class":154,"line":1623},148,[152,1625,202],{"class":158},[152,1627,1628],{"class":176}," whether app code uses an OTA App Key only\n",[152,1630,1632,1634],{"class":154,"line":1631},149,[152,1633,202],{"class":158},[152,1635,1636],{"class":176}," whether release automation uses an OTA Publish Key only\n",[152,1638,1640,1642],{"class":154,"line":1639},150,[152,1641,202],{"class":158},[152,1643,1644],{"class":176}," commands run\n",[152,1646,1648,1650],{"class":154,"line":1647},151,[152,1649,202],{"class":158},[152,1651,1652],{"class":176}," commands the user still needs to run manually\n",[152,1654,1656,1658],{"class":154,"line":1655},152,[152,1657,202],{"class":158},[152,1659,1660],{"class":176}," any publish or rollback action that was intentionally not executed\n",[152,1662,1664],{"class":154,"line":1663},153,[152,1665,170],{"emptyLinePlaceholder":169},[152,1667,1669,1671],{"class":154,"line":1668},154,[152,1670,188],{"class":158},[152,1672,1673],{"class":162},"Useful docs\n",[152,1675,1677],{"class":154,"line":1676},155,[152,1678,170],{"emptyLinePlaceholder":169},[152,1680,1682,1684,1687,1690],{"class":154,"line":1681},156,[152,1683,202],{"class":158},[152,1685,1686],{"class":158}," `",[152,1688,1689],{"class":243},"\u002Fdocs\u002Fquick-start\u002Fcapacitor",[152,1691,1692],{"class":158},"`\n",[152,1694,1696,1698,1700,1703],{"class":154,"line":1695},157,[152,1697,202],{"class":158},[152,1699,1686],{"class":158},[152,1701,1702],{"class":243},"\u002Fdocs\u002Fquick-start\u002Fexpo",[152,1704,1692],{"class":158},[152,1706,1708,1710,1712,1715],{"class":154,"line":1707},158,[152,1709,202],{"class":158},[152,1711,1686],{"class":158},[152,1713,1714],{"class":243},"\u002Fdocs\u002Ftooling\u002Fcli",[152,1716,1692],{"class":158},[152,1718,1720,1722,1724,1727],{"class":154,"line":1719},159,[152,1721,202],{"class":158},[152,1723,1686],{"class":158},[152,1725,1726],{"class":243},"\u002Fdocs\u002Ftooling\u002Fsdk",[152,1728,1692],{"class":158},[17,1730,1732],{"id":1731},"package-references","Package references",[63,1734,1735,1746,1754],{},[66,1736,1737],{},[1738,1739,1743],"a",{"href":1740,"rel":1741},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@otalan\u002Fcli",[1742],"nofollow",[41,1744,1745],{},"@otalan\u002Fcli",[66,1747,1748],{},[1738,1749,1752],{"href":1750,"rel":1751},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@otalan\u002Fcapacitor",[1742],[41,1753,811],{},[66,1755,1756],{},[1738,1757,1760],{"href":1758,"rel":1759},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@otalan\u002Fexpo",[1742],[41,1761,942],{},[1763,1764,1765],"style",{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sJsPd, html code.shiki .sJsPd{--shiki-light:#90A4AE90;--shiki-default:#EEFFFF90;--shiki-dark:#BABED890}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":39,"searchDepth":173,"depth":173,"links":1767},[1768,1773,1774],{"id":19,"depth":166,"text":20,"children":1769},[1770,1771,1772],{"id":27,"depth":173,"text":28},{"id":57,"depth":173,"text":58},{"id":98,"depth":173,"text":99},{"id":131,"depth":166,"text":132},{"id":1731,"depth":166,"text":1732},"Copy a compact assistant skill for Otalan SDK setup, CLI publishing, and safe credential boundaries.",{},"\u002Fen\u002Fdocs\u002Ftooling\u002Fai-skill",{"title":5,"description":1775},"en\u002Fdocs\u002Ftooling\u002Fai-skill","Edfi2txRHq4jeDyFOwLrjIwp1myPd-YahIzV8s0rY2s",[1782],{"title":1783,"path":1784,"stem":1785,"children":1786,"page":1804},"En","\u002Fen","en",[1787],{"title":1788,"path":1789,"stem":1790,"children":1791,"description":1793},"Introduction","\u002Fen\u002Fdocs","en\u002Fdocs\u002Findex",[1792,1794,1805,1815,1825,1835,1855,1871],{"title":1788,"path":1789,"stem":1790,"description":1793},"Understand what Otalan is, when to use it, and how the first safe OTA release flow works for Capacitor and Expo apps.",{"title":1795,"path":1796,"stem":1797,"children":1798,"page":1804},"About","\u002Fen\u002Fdocs\u002Fabout","en\u002Fdocs\u002Fabout",[1799],{"title":1800,"path":1801,"stem":1802,"description":1803},"Security and trust","\u002Fen\u002Fdocs\u002Fabout\u002Fsecurity-trust","en\u002Fdocs\u002Fabout\u002Fsecurity-trust","How Otalan keeps OTA releases controlled: scoped keys, bundle validation, exact matching, rollout controls, rollback, deletion behavior, and support contact.",false,{"title":1806,"path":1807,"stem":1808,"children":1809,"page":1804},"Build","\u002Fen\u002Fdocs\u002Fbuild","en\u002Fdocs\u002Fbuild",[1810],{"title":1811,"path":1812,"stem":1813,"description":1814},"Generate a bundle","\u002Fen\u002Fdocs\u002Fbuild\u002Fgenerate-bundle","en\u002Fdocs\u002Fbuild\u002Fgenerate-bundle","Prepare a release artifact that will pass Otalan's validation pipeline, including the extra considerations required for Expo-based publish flows.",{"title":1816,"path":1817,"stem":1818,"children":1819,"page":1804},"Deploy","\u002Fen\u002Fdocs\u002Fdeploy","en\u002Fdocs\u002Fdeploy",[1820],{"title":1821,"path":1822,"stem":1823,"description":1824},"Publish a release","\u002Fen\u002Fdocs\u002Fdeploy\u002Fpublish-release","en\u002Fdocs\u002Fdeploy\u002Fpublish-release","Submit a release through the dashboard, understand each field in the publish form, and operate the validation lifecycle with confidence.",{"title":1826,"path":1827,"stem":1828,"children":1829,"page":1804},"Integration","\u002Fen\u002Fdocs\u002Fintegration","en\u002Fdocs\u002Fintegration",[1830],{"title":1831,"path":1832,"stem":1833,"description":1834},"Migrate from App Center CodePush","\u002Fen\u002Fdocs\u002Fintegration\u002Fapp-center-codepush","en\u002Fdocs\u002Fintegration\u002Fapp-center-codepush","Plan a migration from Microsoft App Center CodePush to Otalan, with mapping notes, rollout guidance, and common failure modes.",{"title":1836,"path":1837,"stem":1838,"children":1839,"page":1804},"Quick Start","\u002Fen\u002Fdocs\u002Fquick-start","en\u002Fdocs\u002Fquick-start",[1840,1845,1850],{"title":1841,"path":1842,"stem":1843,"description":1844},"Capacitor quick start","\u002Fen\u002Fdocs\u002Fquick-start\u002Fcapacitor","en\u002Fdocs\u002Fquick-start\u002Fcapacitor","Wire the Otalan Capacitor runtime into an installed app so it can check for OTA updates, install compatible bundles, and confirm successful launches.",{"title":1846,"path":1847,"stem":1848,"description":1849},"Expo quick start","\u002Fen\u002Fdocs\u002Fquick-start\u002Fexpo","en\u002Fdocs\u002Fquick-start\u002Fexpo","Configure expo-updates with Otalan, add the Otalan Expo helper, and make the installed app ready to receive compatible OTA bundles.",{"title":1851,"path":1852,"stem":1853,"description":1854},"Publish in 5 minutes","\u002Fen\u002Fdocs\u002Fquick-start\u002Fquick-start","en\u002Fdocs\u002Fquick-start\u002Fquick-start","Create the first Otalan release path, publish a baseline bundle, verify one update, and prove rollback before widening rollout.",{"title":1856,"path":1857,"stem":1858,"children":1859,"page":1804},"Tooling","\u002Fen\u002Fdocs\u002Ftooling","en\u002Fdocs\u002Ftooling",[1860,1861,1866],{"title":5,"path":1777,"stem":1779,"description":1775},{"title":1862,"path":1863,"stem":1864,"description":1865},"CLI","\u002Fen\u002Fdocs\u002Ftooling\u002Fcli","en\u002Fdocs\u002Ftooling\u002Fcli","Learn when to use the Otalan CLI, what workflows it covers, and how it complements the dashboard instead of replacing the platform model.",{"title":1867,"path":1868,"stem":1869,"description":1870},"SDKs","\u002Fen\u002Fdocs\u002Ftooling\u002Fsdk","en\u002Fdocs\u002Ftooling\u002Fsdk","Understand the difference between the Capacitor and Expo integrations, and choose the runtime package that matches the way your mobile app actually updates.",{"title":1872,"path":1873,"stem":1874,"children":1875,"page":1804},"Versions","\u002Fen\u002Fdocs\u002Fversions","en\u002Fdocs\u002Fversions",[1876],{"title":1877,"path":1878,"stem":1879,"description":1880},"v1","\u002Fen\u002Fdocs\u002Fversions\u002Fv1","en\u002Fdocs\u002Fversions\u002Fv1","Supported runtimes, public limits, and post-v1 candidates for Otalan v1.",1780287526981]