What is PulsePlatform?
PulsePlatform is a framework for building desktop and mobile apps with AI agents. Its aim is to have an agent write the right code, so that an idea takes shape as an app and keeps its shape as the app grows. It has two parts: rules, which are tests your project runs, and a library, which holds the pieces those rules expect. It is built on Compose Multiplatform, with desktop apps on the JVM and Android and iOS apps sharing their Kotlin.
From an idea to an app
You describe what the app should do. The agent writes it with the library's pieces, runs the one test that holds the rules, and fixes what the failures name, until the test passes. You review an app whose code already has the agreed shape, and the next idea is built on the same shape, whoever writes it. Building with AI agents sets this loop up.
Why rules first
An AI agent writes a screen that compiles and works on the first try. What it does not keep by itself is the shape of the code around it. One screen binds its ViewModel in a section, another keeps a var beside its state, a third puts a label in the domain. Each choice works on its own, and the codebase drifts.
A rule written in a prompt or a style guide is easy to skip. A rule that is a failing test is not. PulsePlatform's rules are Konsist assertions you call from one test in your own suite. When the code drifts, the test fails, names the file, and says what to move where. An agent reads that message and fixes the code the same way it fixes a compile error.
The library is the other half. The rules ask that one place binds each ViewModel, that sections and components take only data and callbacks, and that state is one immutable value. The library makes that the easy way to write a screen, so following the rules does not mean writing more code.
What the rules cover
| Area | What is checked |
|---|---|
| UI structure | how a feature is split into the place that binds the ViewModel, sections and components; states and messages; previews |
| Domain and data | how a repository hands out data, and when a use case is worth writing |
| Modules and Koin | which module may depend on which, the packages inside them, and where Koin modules are declared |
| Text | that every string a user reads comes from string resources, so the app can be translated |
Desktop and mobile
A desktop app and a mobile app built with PulsePlatform are two products, each shaped for how it is used, and they share their domain and data rather than their screens; an app on both keeps them under desktop/ and mobile/, as Desktop and mobile describes. The rules and the core are the same on every platform: PulseViewModel holds one immutable state, handles actions and emits events, and PulseContent binds it to the UI. What differs is how many ViewModels a screen has.
A desktop window shows a sidebar, an editor and an inspector at once. Each is a content with its own ViewModel, a host lays them out, and a Container above them carries messages between them. A phone shows one screen at a time, so a screen has one ViewModel and binds it itself, with no Container.
| Desktop | Mobile | |
|---|---|---|
| Artifact | mvi-desktop | mvi-mobile |
| Targets | JVM (Compose Desktop) | Android, iOS (Compose Multiplatform) |
| A feature is | a host, its contents, and a Container | one screen and one ViewModel |
| Binds a ViewModel | each content | the screen |
| Messages between ViewModels | Broadcast and Unicast through the Container | none |
| Rules | assertPulseMviConventions() | assertPulseMobileConventions() |
Desktop Mobile
counter/ counter/
├── CounterHost.kt ├── CounterScreen.kt
├── CounterContainer.kt ├── CounterViewModel.kt
├── CounterContracts.kt ├── CounterContracts.kt
├── content/ ├── section/
│ └── total/ └── component/
│ ├── TotalContent.kt
│ ├── TotalViewModel.kt
│ ├── TotalContracts.kt
│ └── section/
├── section/
└── component/Artifacts
PulsePlatform is published on JitPack as five artifacts. Use the rules on every platform, and the MVI and Navigation 3 artifacts for your target.
| Artifact | Role | Platforms |
|---|---|---|
architecture | the rules, as Konsist assertions for your tests | runs on the JVM; checks desktop and mobile code |
mvi-desktop | PulseViewModel, PulseContainer, PulseHost, PulseContent and the five marker interfaces | desktop |
mvi-mobile | PulseViewModel, PulseContent and three marker interfaces | Android, iOS |
navigation-desktop | ties ViewModels and Containers to a Navigation 3 back stack entry | desktop |
navigation-mobile | ties ViewModels to a Navigation 3 back stack entry | Android, iOS |
Installation
Add JitPack to settings.gradle.kts, then the artifacts for your platform to build.gradle.kts. Replace <version> with a tag from GitHub Releases.
// settings.gradle.kts
dependencyResolutionManagement {
repositories {
maven { url = uri("https://jitpack.io") }
}
}// build.gradle.kts — desktop
dependencies {
implementation("com.github.kaleidot725.PulsePlatform:mvi-desktop:<version>")
implementation("com.github.kaleidot725.PulsePlatform:navigation-desktop:<version>")
testImplementation("com.github.kaleidot725.PulsePlatform:architecture:<version>")
}// build.gradle.kts — mobile (Compose Multiplatform)
kotlin {
sourceSets {
commonMain.dependencies {
implementation("com.github.kaleidot725.PulsePlatform:mvi-mobile:<version>")
implementation("com.github.kaleidot725.PulsePlatform:navigation-mobile:<version>")
}
}
}
dependencies {
// the rules run in the Android unit tests
testImplementation("com.github.kaleidot725.PulsePlatform:architecture:<version>")
}Requirements
| Requirement | Version |
|---|---|
| Java | 17+ |
| Kotlin | 2.0+ |
| Compose Multiplatform | 1.6+ |
| Android | minSdk 26 |
Next steps
- Desktop quick start — a counter window with a host, a content and a Container
- Mobile quick start — a counter screen on Android and iOS
- Building with AI agents — set up the rules so an agent checks its own work
- Rules — every rule and why it exists