Reaktor Build Tools

Reaktor and BestBuds already use many good tools. The problem is not that the tools are bad. The problem is that their facts are spread across Gradle files, package.json, target folders, shell scripts, Worker configs, mobile release files, test folders, and cloud manifests.

The goal is simple: keep the tools, but stop making every developer and agent remember where each piece lives.

Dependeasy and Reaktor CLI should work together:

  1. Dependeasy produces build facts. It reads the project through Gradle and related project files, then writes a clear model of modules, targets, source sets, artifacts, tests, budgets, deployables, and required tools.
  2. Reaktor CLI operates those facts. It gives humans and agents one command surface for build, test, run, deploy, logs, graph, doctor, performance, and security checks.
  3. Other tools stay as executors. Gradle still builds Kotlin. Wrangler still deploys Workers. Fastlane still packages mobile apps. Playwright still tests web flows. Dependeasy should coordinate them, not replace them.

This page is the map. Use Dependeasy for the Gradle/KMP build plugin details, Reaktor CLI for the command-line implementation, and Reaktor DevOps for deployment and operations.

The Split

The boundary should stay sharp.

LayerJobShould not do
DependeasyDiscover and publish build facts; configure common Gradle/KMP/native defaults; attach tools by module profileBecome a new build system or ask modules to repeat facts Gradle already knows
Reaktor CLIShow and run the current task catalog; explain targets; run doctor checks; call tool adapters safelyHardcode BestBuds service names or scrape scripts forever when Dependeasy facts exist
Reaktor Desktop/MCPShow the same facts visually and expose safe agent operationsKeep a separate model of modules, targets, and tools
ExecutorsGradle, npm, Wrangler, Fastlane, Playwright, Maestro, Karate, k6, Dagger, Pulumi, k3s, and others do their own workOwn Reaktor's mental model

The important rule:

One tool can be clever. Twenty hidden one-off patterns cannot be the system.

What Exists Today

Build and language tools

ToolUsed forCurrent homeDependeasy status
GradleKotlin, Android, JVM, desktop, publication, task graphsettings.gradle.kts, build.gradle.ktsCore supported
Kotlin Multiplatformcommon, Android, iOS, JS, JVM modulesReaktor and BestBuds modulesCore supported
Android Gradle PluginAndroid app/library buildsGradle plugin management and DependeasyCore supported
KSPsymbol processing and future graph/service extractionGradle plugin management and DependeasyApplied today; extraction not built yet
Kotlin serializationDTOs and config parsingGradle plugins and codeSupported
SQLDelightlocal database and schema workGradle plugin management, module build filesOutside central Dependeasy model
BuildKonfiggenerated build constantsplugin classpath/settingsAvailable, not centrally modeled
Kotlin benchmarkbenchmark tasksGradle plugin managementOutside central model
Foojay resolverJDK toolchain resolutionBestBuds settingsOutside Dependeasy

Native and mobile tools

ToolUsed forCurrent homeDependeasy status
CMake and NinjaC++ sidecars, native libraries, ABI buildsmodule cpp/, Dependeasy native tasksSupported for Android/iOS paths
Android NDK and PrefabJNI, FBJNI, Hermes, native dependenciesDependeasy native configSupported
Kotlin/Native cinteropiOS native interopDependeasy generated .def filesSupported
CocoaPodsiOS app dependencies and KMP framework integrationtargets/appDarwin/Podfile, GradlePartly supported
XcodebuildiOS app build/test packagenpm scripts and FastlaneOutside Dependeasy
FastlaneAndroid/iOS release and distribution lanesfastlane/, npm scriptsOutside Dependeasy
MaestroAndroid/iOS/web/desktop user-flow testsreaktor/tools/maestro, tests/*Outside Dependeasy

Web and Worker tools

ToolUsed forCurrent homeDependeasy status
npm workspacestarget packages and scriptsroot and target package.json filesCLI reads today; Dependeasy should publish cleaner facts
Viteweb target buildstarget vite.config.tsOutside Dependeasy
Reactweb UI surfacesweb target packagesOutside Dependeasy
TypeScriptWorker/web checks and packagestarget configs and package scriptsOutside Dependeasy
WranglerCloudflare Worker dev, deploy, logs, types, bindingstarget wrangler.json, npm scriptsCLI can run today; Dependeasy should model bindings
DocusaurusReaktor documentation sitetargets/reaktorWeb/docusaurusOutside Dependeasy
KarakumKotlin/JS to TypeScript package wrappingReaktor ts/package.json filesOutside central model
MetroJS bundle path for reaktor-ffireaktor-ffi/js/package.jsonOutside central model

Test, performance, and replay tools

ToolUsed forCurrent homeDependeasy status
Kotlin/JVM testsunit and regression testsGradle modulesPartly covered through Gradle
Playwrightweb, Worker, CompanyOS, notification, chat, surface teststests/*/playwrightCLI reads scripts; not modeled
KarateHTTP/API contract testsreaktor/tools/karate, tests/*/karateCLI reads script family; not modeled
k6smoke/load probesreaktor/tools/k6, tests/reaktorServer/k6CLI reads script family; not modeled
Keployproduction-like replay for app-servercloud/k3s, targets/reaktorServerCLI reads script family; not modeled
Lighthouseweb performance budgetsreaktor-performance/tools, npm scriptsOutside Dependeasy
Bundle budgetsJS output size checkstests/reaktorWeb/performanceOutside Dependeasy

Deploy, cloud, and operations tools

ToolUsed forCurrent homeDependeasy status
DaggerCI and task orchestration direction.daggerCLI can call; not modeled by Dependeasy
Pulumicloud resource materialization in Reaktorreaktor-cloud/Pulumi.yamlCLI can call; not modeled by Dependeasy
k3s and kubectlJVM server, Memgraph, ClickHouse, Cloudflaredcloud/k3sOutside Dependeasy
Helm valuesmonitoring/radar stackcloud/k3s/radar, reaktor-cloud resourcesOutside Dependeasy
Docker Composemodel/data support servicesmodel foldersOutside Dependeasy
GitHub Actionsexternal CI runner.github/workflowsOutside Dependeasy
Cloudflare bindingsWorkers, R2, D1, service bindings, logswrangler.json, Cloudflare accountOutside Dependeasy

Security tools to add

These should be added through Dependeasy profiles and CLI commands, not scattered scripts.

Tool familyLikely toolsWhy it matters
Secret scanningGitleaks, TruffleHogCatch committed tokens and leaked credentials
Dependency and image scanningOSV-Scanner, Syft, Grype, TrivyKnow vulnerable packages, containers, and native dependencies
Static code checksSemgrep, CodeQL where usefulEnforce cross-language security and architecture rules
Kotlin structure checksKonsist or KSP-based checks, detekt/ktlint if usefulKeep Reaktor module patterns repeated
API and web scanningOWASP ZAP, NucleiTest deployed HTTP surfaces and known risky endpoints
SBOM and license reportsSyft, Gradle/npm license reportsTrack what ships and what license obligations exist

What Reaktor CLI Does Today

The CLI already reads the current project instead of hardcoding BestBuds.

It discovers:

  • the nearest package.json with a top-level reaktor key;
  • root npm scripts and workspaces;
  • concrete folders under targets/;
  • target-local package.json scripts;
  • Gradle modules from settings.gradle.kts;
  • script families such as fastlane:*, maestro:*, karate:*, k6:*, keploy:*, perf:*, and test:*;
  • Wrangler targets by seeing wrangler.json or wrangler.jsonc;
  • direct shortcuts such as radar, ssh, memgraph, clickhouse, and web;
  • cloud entries such as the Dagger directory.

That gives useful commands now:

reaktor
reaktor tasks
reaktor appAndroid
reaktor appAndroid maestro login
reaktor socialServer npm dev
reaktor deploy reaktorWeb
reaktor reaktorServer logs
reaktor test reaktorWeb playwright
reaktor fastlane android release
reaktor doctor

This is a good bridge. It is not the final model. The CLI should move from "discover from many files" to "read Dependeasy facts first, fall back to discovery only when facts are missing."

What Dependeasy Owns Today

Dependeasy already owns a useful part of the build.

It ships:

  • dev.shibasis.dependeasy.settings;
  • dev.shibasis.dependeasy.library;
  • dev.shibasis.dependeasy.application;
  • common Kotlin opt-ins and source-set helpers;
  • Android app/library defaults;
  • KMP common, Android, iOS, JS, and JVM helper shapes;
  • Kotlin/JS package output conventions;
  • Android/iOS CMake tasks;
  • Android Prefab extraction;
  • Kotlin/Native cinterop .def generation;
  • native dependency discovery across Gradle project dependencies;
  • buildReleaseBinaries size logging;
  • Dokka copy helper tasks.

That is enough to prove the direction. It is not enough to tame the whole toolchain.

Build and Deployment Speed

The current build shape is mostly understandable, but it does too much work in the wrong places.

There is no first-party reaktor-apps/ directory in this checkout. The effective app surface is:

  • Reaktor framework modules under reaktor/*, almost all using the same common { }, web { }, droid { }, darwin { }, and server { } KMP shape;
  • BestBuds app modules under modules/*, which source-build Reaktor through includeBuild("../reaktor");
  • deployable app and service targets under targets/*;
  • generated Kotlin/JS packages such as modules/engine/engine-kt and modules/app/bestbuds-kt;
  • native sidecars under module cpp/ folders, coordinated by Dependeasy CMake tasks and root.cmake;
  • Worker deploy descriptors in target-local wrangler.json files.

That is a workable pattern. The slow part is that the target boundary is not yet the build boundary.

Patterns Found In The Current Tree

AreaCurrent patternSpeed risk
Reaktor modulesRepeated Dependeasy KMP shape across common, web, droid, darwin, and serverGood repetition, but the target matrix is not emitted as a machine-readable manifest
BestBuds source buildBestBuds substitutes many Reaktor modules from ../reaktorCorrect for framework development, expensive when a target only needs published or already-generated outputs
Web targetsappWeb, reaktorWeb, companyOS, and prototypes use Vite plus Cloudflare WorkersVite aliases and generated Kotlin/JS package contracts are hand-maintained per target
reaktorWebprebuild always runs :engine:jsBrowserProductionLibraryDistribution before buildDoc-only edits can trigger Kotlin/JS work and fail on unrelated app code
Worker targetsMany targets repeat predeploy config merging and wrangler deploy --minifySame deployment logic is copied across packages and mutates wrangler.json in place
Generated JS packagesengine-kt and bestbuds-kt are large local file packages consumed by Vite and WorkersRebuilding or rebundling them without an input fingerprint wastes time
Native buildsDependeasy uses CMake/Ninja, per-variant build dirs, Prefab extraction, and generated cinterop defsCMake inputs, Prefab inputs, ABI, SDK, and dependency native projects are not summarized in one cache report
Mobile testsnpm scripts wrap Gradle, Xcodebuild, Fastlane, and MaestroUseful scripts, but target facts are repeated in command names and env vars

Duplicate Work To Remove First

  1. Docs deploy must not rebuild the app. A docs-only change should run Docusaurus, place assets under targets/reaktorWeb/dist/client/docs, and deploy reaktor-web assets. It should not run Kotlin/JS generation, Vite client build, app compilation, or unrelated Worker checks.
  2. Generated Kotlin/JS packages need fingerprints. Dependeasy should record the Gradle task, source inputs, dependency graph, Kotlin version, and output hash for bestbuds-kt, engine-kt, and Reaktor ts/export packages. Vite and Workers should consume those facts instead of guessing from file paths.
  3. Worker deploy scripts should be generated. The repeated predeploy JSON merge and wrangler deploy pattern belongs in a Dependeasy/Reaktor CLI Worker adapter. The adapter should write generated config under build/dependeasy/wrangler/<target>.json instead of rewriting the checked-in wrangler.json.
  4. Native build decisions need reports. Dependeasy already knows CMake executable, generator, ABI, SDK, Prefab modules, source files, output dirs, and native project dependencies. It should write that as a cacheable native report so a rebuild explains what changed.
  5. Root npm script sprawl should become generated aliases. Keep the nice commands, but generate most target aliases from the manifest. Humans should not maintain every deploy<Name>, logs<Name>, karate:<target>:..., and maestro:<platform>:... spelling by hand.

Gradle And KMP Speed Practices

Dependeasy should make Gradle fast by making the smallest correct task obvious.

  • Keep org.gradle.caching=true, org.gradle.parallel=true, and Kotlin incremental flags on by default, as they already are.
  • Turn Gradle configuration cache into an explicit project goal: run it on the main task families, list incompatible tasks, and fix them one by one. Reaktor currently leaves configuration cache commented out, which is reasonable while tasks are unstable, but it should not stay unknown.
  • Prefer the Gradle daemon for repeated local loops. Use --no-daemon only when isolation is more important than speed.
  • Split target slices: docs, web-client, worker, kotlin-js-package, android-app, ios-app, desktop, server, and native. A target should state which slices it needs.
  • Give every custom task real inputs and outputs. Dependeasy's CMake and cinterop tasks already move in this direction; reports and generated descriptors should follow it.
  • Make source-build versus published-build a first-class choice. BestBuds should source-build Reaktor while framework code is being changed, but app/docs deploys should be able to use already-built or published artifacts when framework code did not change.
  • Put build timing, task outcome, and cache-miss summaries under build/dependeasy/reports/build/ so agents can see the reason for slowness instead of guessing.

Vite And Web Speed Practices

The web targets should stay Vite-based, but their Reaktor/Kotlin inputs should come from the build graph.

  • Generate Vite alias maps for Reaktor packages, generated Kotlin/JS packages, and browser-only stubs from Dependeasy facts.
  • Keep generated Kotlin/JS packages outside Vite dependency prebundling when needed, but explain that through the manifest rather than per-target tribal knowledge.
  • Use TypeScript project references where a target has both client and Worker TypeScript so tsc -b can skip unchanged projects.
  • Split Docusaurus from the app client. reaktorWeb should have separate commands for docs assets, app assets, Worker code, and full production build.
  • Keep stable manual chunks for large vendor/runtime groups where bundle reports show churn.
  • Store bundle-size reports beside the Dependeasy build reports and key them by target slice.

CMake And Native Speed Practices

Native builds are where hidden duplicate work becomes expensive.

  • Keep Ninja as the default generator. It is already used by Dependeasy and is the right default for fast incremental native builds.
  • Keep separate build directories by module, platform, ABI, SDK, build type, and toolchain version. A stale arm64 simulator cache should never poison an Android ABI build, and one ABI should not force all ABIs to rebuild.
  • Avoid clean builds as a normal command. Clean should be an explicit operation with a safety class because it destroys useful native and Kotlin caches.
  • Replace recursive CMake source globs with generated file lists or a Dependeasy source-file report where practical. If globs remain, Dependeasy should still record the expanded file set so cache misses are explainable.
  • Treat third-party native dependencies such as Hermes, FlatBuffers, FBJNI, and OpenSSL as artifacts with versions, checksums, headers, and ABI outputs. Rebuilding them should be rare and obvious.
  • Emit compile_commands.json, symbols, library sizes, and static/shared library paths into the target report. Native outputs should be visible in reaktor graph, not hidden in build folders.

Deployment Speed Practices

Deployment should be target-aware and slice-aware.

  • reaktor deploy reaktorWeb --slice docs should run only docs validation/build and deploy the reaktor-web asset bundle.
  • reaktor deploy reaktorWeb --slice worker should build or check only the Worker code and bindings.
  • reaktor deploy reaktorWeb --slice full should run Kotlin/JS, Vite, docs, Worker checks, and Wrangler deploy.
  • Worker adapters should show the merged bindings, routes, compatibility flags, assets directory, and run_worker_first paths before deploy.
  • The deploy report should record git SHA, dirty state, target slice, artifact hashes, Wrangler version, Worker version, route, and live verification result.

This would have prevented the recent docs deploy slowdown: a docs-only update would not have depended on :engine:jsBrowserProductionLibraryDistribution, and unrelated Kotlin app errors would not have blocked publishing docs assets.

Highest Priority Features

PriorityFeatureWhy it matters
1Target-slice manifestLets Dependeasy say exactly what docs, web-client, worker, native, android, and ios need
2Docs-only Reaktor Web deployRemoves the most visible wasted work today
3Build fingerprint reportMakes cache hits, cache misses, generated JS packages, CMake variants, and deploy artifacts explainable
4Generated Worker adapterRemoves repeated Wrangler script logic and keeps bindings/routes visible
5Generated Vite alias/package adapterStops every web target from hand-maintaining Reaktor package paths
6Configuration-cache campaignTurns Gradle startup/configuration cost from unknown into tracked work
7Native artifact cache modelPrevents ABI/toolchain/native dependency rebuilds from feeling random
8Script alias generationKeeps the friendly npm/CLI surface while removing hand-written command sprawl

The principle is the same as the rest of Reaktor: keep the powerful tools, but make the graph of work visible. The fastest build is not the one with the most tricks. It is the one that knows the smallest correct thing to do.

The Missing Manifest

The next important artifact is a versioned manifest. It should be generated, checked in only if we intentionally want stable snapshots, and read by CLI/Desktop/MCP/CI.

The root file can look like this:

{
  "schema": "dev.shibasis.dependeasy.project.v1",
  "project": "bestbuds",
  "modules": ["app", "engine", "reaktor-auth"],
  "targets": ["appAndroid", "appDarwin", "appWeb", "reaktorWeb", "socialServer"],
  "tools": ["gradle", "npm", "wrangler", "fastlane", "maestro", "playwright"],
  "reports": ["build", "test", "performance", "security"]
}

Per module and per target, it should answer plain questions:

  • What is this thing?
  • What does it build?
  • Which source sets does it use?
  • Which tool builds it?
  • Which tests prove it?
  • Which deploy command ships it?
  • Which secrets or external services does it need?
  • Which reports and budgets apply?
  • Which facts were inferred, and from which file?

The last point matters. Every fact needs provenance: "from Gradle", "from package.json", "from wrangler.json", "from KSP", "from CMake", "from a generated Dependeasy descriptor", or "manual exception".

The DSL Rule

Do not make module authors repeat facts that the build already knows.

Bad shape:

dependeasy {
    ownsGraph("AuthRuntimeGraph")
    exposesService("AuthService")
    sourceRoots("src/commonMain", "src/jvmMain")
}

Why it is bad:

  • sourceRoots are already Gradle/KMP facts;
  • graph and service names should be found from code, KSP, registration, or runtime graph descriptors;
  • repeated declarations drift;
  • people learn a second fake model instead of the real one.

Better shape:

dependeasy {
    profile(Profiles.StableRuntimeLibrary)

    policy {
        stability = Stability.Stable
        sensitivity = Sensitivity.Auth
        requireGraphConformance = true
        requireThinAdapters = true
    }

    exceptions {
        allow("js-interop-bridge", path = "src/jsMain/**", until = "2026-09-01")
    }
}

That DSL says what humans must decide: stability, sensitivity, required checks, and exceptions. Dependeasy should infer the rest.

Tool Adapters To Build

Build adapters in this order.

1. Fact adapters

These make the map reliable.

AdapterProduces
Gradle/KMPmodules, source sets, dependencies, tasks, artifacts
Dependeasy nativeCMake, Prefab, cinterop, native outputs
npm/packageworkspaces, scripts, package names, JS outputs
WranglerWorker names, bindings, routes, compatibility dates, deploy commands
Vite/Docusaurusweb build outputs, dev commands, bundle entry points
Fastlane/Xcode/Podsmobile lanes, schemes, pods, signing requirements
Test configPlaywright, Maestro, Karate, k6, Keploy entry points

2. Report adapters

These make the map useful.

AdapterProduces
Test reportsJUnit-style pass/fail results across Gradle, Playwright, Karate, Maestro, k6
Performance reportsbundle sizes, Lighthouse, desktop timings, k6 numbers, build timings
Security reportsSARIF/JSON for secrets, static checks, dependencies, containers, web/API scans
Artifact reportsAPK/AAB/AAR, XCFramework, npm package, Worker bundle, jar, container image, checksums

3. Operation adapters

These let CLI/Desktop/MCP act safely.

AdapterRuns
Gradle runnerbuild, test, publish, installDist
npm runnertarget scripts and generated package scripts
Wrangler runnerdev, deploy, tail, typegen, binding checks
Fastlane runnerAndroid/iOS build, release, distribute
k3s runnerapply, rollout, logs, status
Dagger runnerlocal/CI task graph
Pulumi runnerpreview, up, stack inventory

How It Should Feel

The user experience should be boring and clear.

reaktor graph
reaktor doctor
reaktor explain appAndroid
reaktor build reaktorWeb
reaktor test notificationServer
reaktor perf reaktorWeb
reaktor security auth
reaktor deploy socialServer

Each command should say:

  • what it is going to run;
  • why that command was chosen;
  • which files produced the facts;
  • which reports were written;
  • whether the command is read-only, local, deploy-like, or destructive.

That is how we keep power without making a tool jungle.

Priority Plan

  1. Project manifest. Emit .reaktor/build-graph.json from Dependeasy and current project files.
  2. CLI reads manifest first. Keep current discovery as fallback.
  3. Tool registry. Add adapter IDs, report formats, safety class, and install checks.
  4. Profiles. Add profiles such as stable-kmp-library, cloudflare-worker, mobile-app, docs-site, native-interop, security-sensitive, and experimental.
  5. Reports. Normalize test, performance, artifact, and security outputs under build/dependeasy/reports.
  6. Architecture checks. Add KSP/Konsist/Semgrep-style rules for repeated Reaktor patterns.
  7. Security checks. Add secret, dependency, container, static, and API scanning through Dependeasy profiles.
  8. Desktop/MCP projection. Show the same facts in the workbench and expose safe agent operations.

The end state is not fewer tools. It is fewer places to understand.