Skip to content

Your first app

A Kiki app is a Rust struct annotated with #[kiki::app]. The macro generates the manifest, wires up the agent connection, and validates the app's permissions at compile time. This is the shortest path from nothing to a running app.

Anatomy of an app

rust
use kiki::prelude::*;

#[kiki::app(id = "io.kiki.my-app", type = DesktopApp)]
#[kiki::requires(Capability::AudioOutput)]
struct MyApp {
    // your app's state
}
  • id — a reverse-DNS identifier, e.g. io.kiki.my-app. It namespaces the app's storage, schemas, and store entry.
  • type — the kind of app, which decides how strongly the OS isolates it.
  • #[kiki::requires(...)] — the permissions it needs, validated at compile time and enforced at runtime.

App types

The type tells the OS how to run and isolate your app:

TypeTypical appIsolation
DesktopAppA windowed appNamespaces + Wayland filter
HeadlessAppA background workerNamespaces + network namespace
CliTool / McpToolA command or tool serverNamespaces + seccomp
SystemServiceA privileged serviceExplicit capabilities
AgentExternally-authored agent codeHardware-isolated MicroVM

See Capabilities & sandbox for why agent code gets a MicroVM.

Storing data

By default an app reads and writes its own private space — relative paths, never absolute:

rust
storage::write("notes/draft.md", body).await?;

For data the user wants across devices, request a scoped vault capability; for raw filesystem access, request a scoped fs capability. The user approves these when they install.

Make it agent-operable

The reason to build on Kiki: your app becomes something the agent can drive. Expose actions as tools:

rust
#[kiki::agent_tools]
impl MyApp {
    async fn play(&mut self, track: TrackRef) -> Result<()> { /* ... */ }
}

Now "play that track" works whether the user does it or the agent does it as part of a plan.

Ship it

When it builds, package and publish it. Next: Exposing tools.

Kiki OS, Desktop & SDK are open source. See Licensing.