Skip to content
ArenukvernPublic

About

Oka is a declarative application platform: one typed Dart file you own (tool/oka_pipeline.dart) composes the whole loop — build without Gradle, run on devices, patch running programs live, supervise processes, and publish to stores. Humans and agents operate it identically: every operation has a plan you can read (oka explain), a probe you can run

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

4 stars

Watchers

0 watching

Forks

Latest commit

 

History

324 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Oka — one typed Dart surface to build, run, patch, and distribute apps

Oka: one typed Dart surface to build, run, patch, and distribute apps

skills.sh License: MIT Docs Ask DeepWiki CI Flutter All Contributors maintained with Skill Steward

TL;DR — Oka is a declarative application platform: one typed Dart file you own (tool/oka_pipeline.dart) composes the whole loop — build without Gradle, run on devices, patch running programs live, supervise processes, and publish to stores. Humans and agents operate it identically: every operation has a plan you can read (oka explain), a probe you can run (oka debug step), and failures that name the fix. oka init → oka build apk → oka run device.

Who it's for: Flutter teams and release engineers who want a single inspectable build surface; agents and CI that need oka explain and actionable errors; anyone shipping store-free updates to installed apps. Not a full Gradle/AGP emulator — see FAQ and charter.

Four pillars, one surface

Oka started as a no-Gradle Android build system. The same laws — typed values, validated plans, evidence over demos — now carry three more pillars, each at a different, honestly-labeled maturity:

Pillar What it does Maturity
Build No-Gradle APK/AAB: flutter assemble + direct SDK tools, provenance on every artifact, byte-equivalence gates Production — on pub.dev (see VERSION)
Distribute Play / AppGallery / RuStore / web stores, multiple developer accounts, white-label brands — dry-run by default Production — on pub.dev
Update Live per-unit patching of running programs: the oka run dev session, oka ship store-free air channel, AOT slots Gate-proven experimental — runs from a checkout
Operate Declarative supervisor, process leases, session-state, content-addressed artifact store with delta chains Production — supervisor at adoption rung L0

The design laws are constant across pillars: configuration is typed Dart you own, every chain validates before any tool runs, and an agent can set up and fix things from oka's messages alone. The full north star, invariants, and expansion gates live in the charter.

Why oka is different

Your app is one codebase — but building it is scattered across Gradle DSL, XML manifests, plists, proguard rules, and per-store index.html surgery. None of it typed, all of it drifting. Oka collapses all of that into one typed, copyable Dart file that both humans and AI agents can run, inspect, and fix.

Gradle + AGP Oka
Config 5+ formats, hidden defaults One typed Dart file, in your repo
Every build pays ~30s daemon/configuration tax Direct SDK tools, ~23s incremental
First build Works by convention, breaks mysteriously oka explain shows the whole plan before any tool runs
When it fails Generated glue hides the cause The error names the failing step and the fix
Stores & accounts Per-store branches and gradle flavors More targets in the same file — dry-run by default
AI agents Fight the build Built for them: plans, probes, byte-equivalence gates

Three words carry the design:

  • Declarative — the build is typed values (AndroidBuild, ManifestSpec, …) in a project-owned tool/oka_pipeline.dart. Config is code: checkable, diffable, copyable between projects.
  • Compositional — every capability is a BuildStep with declared inputs/outputs; the whole chain is validated before any tool runs. A store target or a platform is another package over the same kernel.
  • AI-native — self-describing plans, single-step probes, byte-equivalence gates, failures that name the fix. An agent can set up and fix a build from oka's messages alone.

60-second start

# 1. Install (needs Dart, not Flutter)
dart pub global activate oka        # or: curl -fsSL https://raw.githubusercontent.com/Arenukvern/oka/main/install.sh | bash

# 2. One-time Android SDK bootstrap (into ~/.oka/android-sdk)
oka get android-sdk && oka doctor

# 3. In your Flutter project: scaffold config, build, run
oka init
oka build apk --release             # → .oka_cache/build/release/app-release.apk
oka run device                      # install → launch → crash-log scan

Migrating an existing Gradle app? Migration guide (same android/key.properties and plugins keep working).

Pick your path

Every path below is the same two moves: add values to tool/oka_pipeline.dart, run oka. Start anywhere.

Build 1 — Daily dev loop: hot reload without Gradle

oka build apk --debug   # once
oka dev                 # r hot reload · R hot restart · q quit · d detach
oka dev --watch --json  # agents: Dart edits auto-reload; native edits print
                        # the honest full-rebuild command

Hot reload is Dart-only — native/res/manifest changes need a rebuild (ADR-0011).

Build 2 — Release builds: proven, not hoped

oka build apk --release          # AOT + R8 + signed (mapping.txt included)
oka build aab --release --verify-aab   # store upload format, bundletool-verified
oka run verify                   # prove the release actually starts on a device
oka compare old.apk new.apk      # byte-equivalence gate for refactors

Every artifact carries oka-provenance.json (engine + snapshot hashes); a wrong engine/snapshot pairing fails the build instead of hanging the device on a splash screen (ADR-0029).

Distribute 3 — Stores: one app, many stores

Publish targets are project-declared values, dry-run by default: the plan prints endpoint, track, artifact, and metadata with zero HTTP and zero credentials (ADR-0014).

// tool/oka_pipeline.dart
targets: const [
  DeviceTarget(),
  PlayPublishTarget(),                                    // oka run publish-play
  HuaweiPublishTarget(release: HuaweiReleaseConfig(appId: '110012345')),  // GMS-free variant + upload
  RuStorePublishTarget(packageName: 'com.example.app'),   // readiness + verification
],
oka explain --targets        # see every declared target and its step chain
oka build aab --release --verify-aab
oka run publish-play         # rehearsal — flip dryRun: false when ready

Credentials are file paths, never values: typed config → OKA_<TARGET>_* env var → ~/.oka/credentials/<target>/. Full console setup: Publishing guide.

Distribute 4 — Multiple accounts & white-labeling

One codebase → many branded, store-separated apps. Two PlayPublishTargets with distinct names, package ids, and service accounts is all it takes:

targets: const [
  // Your account:
  PlayPublishTarget(
    targetName: 'publish-play-acme',
    packageName: 'com.acme.myapp',
    serviceAccountPath: 'keys/play-acme.json',
  ),
  // A client's account (white-label):
  PlayPublishTarget(
    targetName: 'publish-play-client',
    packageName: 'com.client.myapp',
    serviceAccountPath: 'keys/play-client.json',
  ),
],
oka run publish-play-acme     # dry-run plan for account 1
oka run publish-play-client   # dry-run plan for account 2

The build side is the same Dart file: declare one AndroidPipeline per brand (different packageName/applicationId, keystore, icon) and pick it in main() from your own flag — it's a program, not a DSL. Recipes and caveats: Accounts & stores guide.

Distribute 5 — Web: shell station, not a platform

Per-store web/index.html as typed, drift-checked Dart. One composition, no per-store branches (ADR-0016):

targets: const [
  WebShellTarget(spec: mySpec, contributions: [MyStoreContribution()]),
  WebBuildTarget(),      // honest delegation to flutter build web
  GhPagesDeployTarget(), // or ItchDeployTarget() — dry-run by default
],

Guide: Web shell station.

Update 6 — Live patching: change running programs

The kernel/update stack (oka_dart_kernel + oka_update) applies changes to running Dart programs — and ships patches to installed ones without a store (ADR-0037). Proven by the gate harness across macOS/linux/android/web and three real products (the oka CLI itself, an MCP stdio server, a Flutter desktop app). A full live apply lands in 0.57 s; AOT deltas compile ~94x faster than JIT.

oka run dev --platform macos --project <app>   # r = oka's delta lane, R = restart
oka ship                                       # derive + publish a patch from the working tree
packages/oka_dart_kernel/example/live_showcase/run.sh   # 30 s demo

Works today: the dev session (macOS/web) with watch-on-save, asset sync, and live shader recompiles; invisible patch authoring; signed channels; migration chains with snapshot fallback; the boot watchdog; command lanes on the watcher. Not yet: the android dev session convergence, live freshness for already-loaded assets (engine seam), per-unit AOT over the air (research line, ADR-gated). The update stack itself is not on pub.dev — it runs from an oka repo checkout; everything it patches can be a plain pub app.

Guide: Live update.

Operate 7 — Supervise, lease, store

oka supervisor apply plan.json   # one converge pass over a declared plan
oka supervisor status --json     # recorded process state as data
oka supervisor check plan.json   # plan-vs-records drift gate for CI
oka processes list --json        # every lease oka recorded (emulators, browsers, daemons)
oka stop <lease-id>              # graceful, identity-verified teardown
oka artifacts put out.bin        # content-addressed store; git keeps a pointer
oka artifacts materialize out.bin # recreate bytes anywhere (delta chains, ~0.03% deltas)

Supervisor plans are versioned JSON (SpecCodec); the shipped rung is one-shot converge — no resident daemon (that is ADR-0042, proposed and gated). Guides: Supervisor · Process lifecycle · Artifacts.

The agent surface

This is what "AI-native" means — every operation is checkable and scriptable:

Command What an agent gets
oka explain / oka build --dry-run The validated plan: steps, artifacts, signing, versions — zero tools invoked
oka explain --targets Every project-declared target with its compiled step chain
oka why <step> Step-cache forensics: fingerprinted inputs, which changed, what's uncovered
oka debug step <name> One pipeline step re-run against .oka_cache — 10-minute loops become 30-second probes
oka compare a.apk b.apk Byte-equivalence gate — refactors prove, not claim
oka cache --json / oka cache clean Storage inventory and reclaimable totals as data
oka run dev --json Dev-session receipts: reload/restart events as structured lines
oka ship Derive + publish a store-free patch from the working tree (checkout)
oka supervisor status --json / check plan.json Recorded process state and the plan-vs-records drift gate as data
oka processes --json / oka stop Process leases as data; graceful identity-verified teardown
oka session-state list/inspect/resume Durable browser/emulator state as inspectable data
oka_artifacts (package CLI: put/materialize/verify) Build artifacts as pointers + delta chains — git stays small, LFS optional
oka doctor Full environment + build-health audit, secret-tier checks included

Configuration in one glance

The whole build config — typed, const, programmable:

// tool/oka_pipeline.dart
Future<void> main(List<String> args) => okaRun(
  args,
  oka: const Oka(
    pipelines: [
      AndroidPipeline(
        config: AndroidBuild(
          name: 'my_app',
          packageName: 'com.example.my_app',
          minSdk: '23', targetSdk: '36', compileSdk: '36',
          versionCode: 51, versionName: '1.0.0',
          javaVersion: 17,
        ),
        overrides: PipelineOverrides(
          resourceConfigs: ['en', 'ru'],
          manifest: ManifestSpec(permissions: [/* … */]),
          deeplinks: [DeeplinkConfig(scheme: 'https', host: 'my.app')],
        ),
        steps: [...AndroidPipeline.defaultSteps],
      ),
    ],
  ),
);

Prefer YAML? oka.yaml fast-settings still work (oka init --yaml); migrate with oka init --from-yaml. Precedence: defaults < oka.yaml < Dart config < CLI args. Everything the keys do: Build & configuration guide.

How it works

Diagram: oka_pipeline.dart to flutter assemble and Android SDK tools, output APK or AAB

Example terminal session: oka explain, build, and doctor

Source: docs/images/pipeline-flow.mmd (Mermaid).

  1. Host checks + codegen (manifest, MainActivity, adaptive vector icons)
  2. flutter assemble (assets / kernel / AOT) — never flutter build apk
  3. Engine libflutter.so extraction from the Flutter cache
  4. Plugin packaging + Maven/AAR resolution (parallel, deterministic)
  5. aapt2 → javac/kotlinc → d8 compile-and-dex (sorted, reproducible)
  6. Extra assets, zip staging, zipalign -p 4, apksigner
  7. Layout validation + post-build lint

Every step declares typed requires/provides artifacts; the chain is validated before any tool runs. Canonical copyable config: example/tool/oka_pipeline.dart.

Learn by building: the examples ladder

Start at examples/ and climb — each step is a small, runnable project with a five-minute README (step 6 is a guided demo that runs from this checkout):

Step You learn
01 hello app Smallest possible oka build (one Dart file, one command)
02 dev loop Hot reload / hot restart with oka dev
03 release Release signing, R8, oka run verify
04 stores & accounts Play + AppGallery + RuStore, two Play accounts, white-label brands
05 web stores Web shell, GitHub Pages, itch.io
06 live patch Patch a running app via the air channel (demo runs from this checkout)

The full reference app remains example/ — every feature composed in one file.

FAQ

Short answers live in docs/FAQ.md (also on the docs site). Highlights:

Do I need Gradle? No — ever. The default path never falls back to flutter build apk (enforced by tests). What you give up is listed honestly: no full AGP compatibility (AIDL, RenderScript, data binding, NDK); some plugins with complex native code fail loudly instead of silently (ADR-0001).

Which platforms? Android is the deepest (APK + AAB, full dev loop). Web gets the configuration/distribution layer (shell station + deploy targets); its compile stays flutter build web. The update stack already patches plain Dart programs on macOS/linux/web. iOS/desktop builds are criteria-gated, not calendar-driven — depth before breadth.

Where's the cache? Project outputs in .oka_cache/, shared store in ~/.oka/store. oka cache inventories everything (including emulator data); oka cache clean previews before deleting.

Why Dart, not YAML? YAML keys fail silently; Dart is typed, refactorable, and as writable by agents as by humans. oka.yaml covers the 90% case and its growth is frozen (ADR-0010).

Design rationale: Design FAQ. Agents: llms.txt and AGENTS.md.

Packages

Twelve packages ride the automated release train on pub.dev; the live-update kernel stack is checkout-only while its API settles.

Package Pub Purpose
oka ✅ CLI + agent surface
oka_core ✅ Platform-agnostic contracts: pipeline, artifacts, typed config
oka_android ✅ Android pipelines, toolchain, plugin packaging
oka_play ✅ Google Play publish target
oka_huawei ✅ AppGallery Connect target (GMS-free variant + upload)
oka_rustore ✅ RuStore target (readiness + verification; adapter-supplied upload)
oka_web ✅ Web shell station + deploy targets
oka_conformance ✅ The contract suite every target must pass
oka_supervisor ✅ Declarative supervisor: pure planner + crash-only converge
oka_artifacts ✅ Content-addressed artifact store with delta chains
oka_harness ✅ Device E2E targets over oka dev sessions
resource_composition ✅ Zero-dependency resource composition contracts
oka_dart_kernel checkout Kernel-graph partitioning + live-patch gates (ADR-0032)
oka_update checkout Patch-unit authoring/planner surface (ADR-0031)

Documentation

Published via docs.page: docs.page/arenukvern/oka

I want to… Read
Newcomer questions FAQ · docs.page/FAQ
Copy-paste the common loops Quick recipes
Run/build/test/configure Build & configuration guide
Publish to stores, set up accounts Publishing · Accounts & stores
Ship a web app Web shell station guide
Patch running apps / ship updates Live update
Govern daemons, watchers, automations Supervisor guide
Manage processes, emulators, browsers Process lifecycle
Keep build binaries out of git Artifacts guide
Know why it's designed this way Design FAQ
Where oka is going Roadmap
Check phase status docs/PHASE_CHECKLIST.mdx

Contributing

Contributions of any kind welcome — code, docs, examples, bug reports, ideas. See CONTRIBUTING.md and the contribution guide; use conventional commits (feat:, fix:, docs:) and run just lint (dart analyze --fatal-infos) and just check-contracts before merging. Please follow the Code of Conduct. Agents: start from AGENTS.md or llms.txt.

Contributors

Arenukvern
Arenukvern

🤔 💻 📖 🎨 🚧 👀 ⚠️

This project follows the all-contributors specification — any contribution counts, not just code. Add yourself with npx all-contributors add <username> <contribution> (or ask in a PR) and commit both README.md and .all-contributorsrc.

Security

See SECURITY.md. Please report vulnerabilities privately.

License

MIT — see LICENSE. Changelog: packages/oka/CHANGELOG.md (index: CHANGELOG.md).

About

Oka is a declarative application platform: one typed Dart file you own (tool/oka_pipeline.dart) composes the whole loop — build without Gradle, run on devices, patch running programs live, supervise processes, and publish to stores. Humans and agents operate it identically: every operation has a plan you can read (oka explain), a probe you can run

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages