Three commands and Ketoy is wired into your Android project - plugin pinned, runtime bootstrapped, sample @KetoyComposable screen mounted, signed .ktx emitted into your APK. The ketoy CLI is an AI agent - bring your own model from Anthropic, OpenAI, Gemini, Mistral, Groq, xAI, OpenRouter, or local Ollama.
0.3.4-alphaThe local-asset path is fully supported: ketoy init wires up your :app module, the compiler plugin emits a signed .ktx into your assets, and the runtime executes it at startup.
Cloud delivery - pushing a .ktx to a CDN so users get updates without going through the Play Store - is under active development and ships shortly. Track progress on the GitHub releases page.
The Compose compiler plugin and the Ketoy compiler plugin are both pinned to 2.0.21 for the alpha. ketoy init pins your gradle/libs.versions.toml automatically to the matched Kotlin / AGP / Compose BOM combination. These pins are temporary - they go away once Ketoy ships its own embedded Kotlin compiler.
The npm package is ketoy-dev (the bare ketoy name is blocked by npm's similarity heuristic). The installed binary is still ketoy.
$ npm i -g ketoy-dev
$ ketoy versionRequires Node.js 20 or newer. Every command runs in the current working directory - there's nothing global to maintain beyond the API-key store at ~/.ketoy-cli/.
ketoy init in your projectFrom the root of your Android project (the directory containing settings.gradle.kts and app/build.gradle.kts), run ketoy init. The CLI inspects your project, plans every change, and asks before applying.
$ ketoy init # interactive, asks before each edit
$ ketoy init -y # accept defaults, no prompts
$ ketoy init --dry-run # show the plan, write nothing
$ ketoy init --hilt # opt into Hilt wiring
$ ketoy init --no-install-screen # skip the MainActivity wrapA typical interactive plan looks like this:
Detected: namespace=com.example.myapp, applicationId=com.example.myapp,
minSdk=26, Hilt=no, Application=none, MainActivity=present
Plan (6 edits, 4 new files):
edit app/build.gradle.kts + Ketoy plugin, dependencies, ketoy {} block
edit app/src/main/AndroidManifest.xml + android:name=".MyApplication"
edit app/src/main/.../MainActivity.kt wrap setContent { … } with KetoyScreen
edit gradle/libs.versions.toml pin Kotlin 2.0.21, AGP 8.13.2, Compose BOM
edit .gitignore + **/keys/*-private.key
new app/src/main/.../MyApplication.kt
new app/src/main/.../ketoyscreens/HelloKetoyScreen.kt
new app/ketoy-capabilities.json
new .ketoy/state.json
Apply? [y/N]namespace, applicationId, minSdk, Hilt usage, existing Application class, and existing MainActivity.gradle/libs.versions.toml to the alpha-matched combination (Kotlin 2.0.21, AGP 8.13.2, Compose BOM 2024.10.00).app/build.gradle.kts - inserts the dev.ketoy.compiler plugin, appends the BOM + runtime + annotations + capabilities + Material3 adapters dependencies, and appends the ketoy { } configuration block.AndroidManifest.xml - sets android:name=".MyApplication" on <application> when no Application class exists.MyApplication.kt with the full bootstrap - KetoyConfig, CapabilityRegistry, KetoyRuntime, generated-adapter / constructor registration, KetoyBundleLoader.MainActivity's setContent with CompositionLocalProvider(LocalKetoyRuntime, LocalKetoyBundleLoader) and a KetoyScreen entry point (use --no-install-screen to skip).HelloKetoyScreen.kt - a sample @KetoyEntryPoint @KetoyComposable to confirm the pipeline works.app/ketoy-capabilities.json (empty registry) and appends **/keys/*-private.key to .gitignore..ketoy/state.json so future commands know your layout.The non-Hilt setup is the default - it works in any Compose project without a DI framework. If you opt in with --hilt, init aborts with a pointer to ketoy chat, where the agent handles Hilt wiring against your existing modules rather than guessing at a stock template.
This step is skippable. If you don't connect an AI provider, ketoy init, build, and analyze still work - they're plain tooling. You just won't have access to the AI features: ketoy chat, ketoy migrate, and ketoy doctor all require a configured provider.
Ketoy is powered by the Vercel AI SDK, so you bring your own key from any major provider. Source code never leaves your machine except as part of the prompts you explicitly send to the provider you chose. No telemetry, no remote logging.
$ ketoy auth anthropic # Anthropic Claude
$ ketoy auth openai # OpenAI
$ ketoy auth google # Google Gemini
$ ketoy auth mistral # Mistral
$ ketoy auth groq # Groq
$ ketoy auth xai # xAI
$ ketoy auth openrouter # 200+ models via one key
$ ketoy auth ollama # local - no API key, just a base URL
$ ketoy auth --list # see what's configured (redacted)Then pin a default model (or override per-command with --model):
# Set a default model used by every command.
$ ketoy config set model anthropic:claude-sonnet-4-5
$ ketoy config set model openai:gpt-4o
$ ketoy config set model google:gemini-2.0-flash-exp
$ ketoy config set model openrouter:meta-llama/llama-3.1-405b-instruct
# Or override per-command.
$ ketoy chat --model anthropic:claude-sonnet-4-5API keys are stored at ~/.ketoy-cli/config.json with mode 0600. The CLI refuses to print them - ketoy config get apiKeys is intentionally blocked. Use ketoy auth --list for a redacted view.
After ketoy init finishes, the project is ready to build. The compiler plugin attaches to compileReleaseKotlin and emits a signed .ktx into app/src/main/assets/ketoy/main.ktx.
$ ketoy buildLaunch the app - the KBC version of HelloKetoyScreen renders. Delete the .ktx, change the entry point to "DoesNotExist", or toggle airplane mode - the native fallback renders identically. That's the production contract.
Once initialized, the agent stays useful for the day-to-day work - writing screens, migrating existing Compose UI, diagnosing build failures, and inspecting bundles.
$ ketoy chat
> add a settings screen with a dark-mode switch and version row
$ ketoy chat "convert app/src/main/.../HomeScreen.kt to a KetoyComposable"
$ ketoy migrate app/src/main/.../HomeScreen.kt app/src/main/.../ProfileScreen.kt
$ ketoy doctor # runs default build, diagnoses failures
$ ketoy doctor :app:ketoyBundle
$ ketoy analyze app/src/main/assets/ketoy/main.ktx --manifest --stringsketoy chatOpen an AI session in the project root. The agent has tools for reading files, proposing surgical edits, running Gradle tasks, and inspecting build output.
ketoy migrateAI-driven per-file Compose → KBC migration. Point it at a Compose screen and it produces a @KetoyComposable equivalent, diff-and-confirmed.
ketoy doctorRuns a Gradle task and diagnoses any compiler-plugin errors. Useful when :app:ketoyBundle fails and you want the agent to read the failure and propose a fix.
ketoy buildEquivalent to ./gradlew :app:ketoyBundle --rerun-tasks, with variant selection: --variant bundle|debug|release.
ketoy analyzeInspect an existing .ktx bundle - view its manifest, extract the string table, or dump the full structure as JSON.
ketoy configList, get, or set CLI configuration. Use it to change your default model or inspect (redacted) provider settings.
The agent runs in your terminal, against your files, with your keys. The boring safety guarantees that make that workable:
build.gradle.kts, AndroidManifest.xml, MainActivity.kt, and your Application class are surgical - single-line additions or block appends at well-identified anchors. Existing dependencies, signing configs, themes, and ProGuard rules are never touched.edit_file tool always shows a unified diff and prompts before applying.ketoy init on an already-configured project is a no-op.cat && rm -rf / looks like cat to a naive checker; the CLI refuses to auto-approve any command containing shell metacharacters (;, &&, ||, |, backticks, $(…), redirects).What you just built is the local-asset path: the .ktx ships inside the APK at compile time, and updates roll out through the Play Store like any other asset.
Cloud delivery - pushing a new .ktx to a CDN where connected devices fetch updates at the next process start (Ed25519-verified, ETag-cached, rolled back on minAppVersion mismatch) - uses KetoyBundleSource.Remote(url). The wire format, signature verification, ETag cache, and runtime activation order are already implemented. The hosted infrastructure (signing pipeline, signed-URL distribution, telemetry) is under active development and ships shortly.
The five-layer stack and why KBC bytecode - not JSON - is the wire format.
Read the specEvery Material3 adapter, every capability, every Compose token Ketoy ships with.
See coverageAdd your own components beyond Material3 - the KSP processor handles the rest.
Read the guide