maiko.os · opening the schematics · one machine, talking to itself · the cycle never stops, even now · one job id, one lock, no races ·

How it turns

the schematics, as far as anyone got.

Maiko is a small Flask brain, a SQLite memory, and a React face, all running on your laptop. Agents are subprocesses in their own git worktrees. Here is how the pieces move. Click any bar to fold it.

the-shape-of-it

// one process, no cloud

One machine, talking to itself

Nothing here is a service you call. It is one machine talking to itself, with the model doing the parts that need judgement and plain code doing everything that does not.

The brain

A Flask app with a background loop. It holds the API, the brain cycle, and the plugin host. It never blocks the UI to think.

The memory

One SQLite file. Pupdates, tasks, jobs, agents, insights, learnings, memos. Schema changes land as idempotent column patches, not migrations you run by hand.

The face

A Vite + React app, also wrapped as a desktop shell. It reads the same API a curl command would. The world is a view, not the state.

The pack

Agents are coding subprocesses, each in an isolated worktree with its own CLAUDE.md. They talk back to the brain over a CLI, not a socket.

no server. it is all in here.
brain-cycle :: heartbeat

// a loop wakes on a cadence and walks fixed phases

The brain cycle

Each phase is allowed to notice things, decide things, and hand work off. Plugins hook into it instead of running their own timers.

01

Gather

Pollers and plugins fold in what changed since last tick. One on_cycle_tick per cycle, so a plugin never has to own a thread.

02

Triage

New pupdates get sorted: ignore, surface as a memo, or become a task. Automations get their chance to fire here on plain predicates.

03

Narrate

The home overview is regenerated: a short, voiced read of what is going on and what you would probably look at first. A greeting, not a dump.

04

Tend

Stuck jobs, awareness checks (two agents about to collide, who knows this area), and the end-of-day campfire when it is time.

it never stops. even now.
pupdates :: the substrate

// everything that happened

Pupdates

A pupdate is the one event type. A PR went stale, a build broke, a calendar block is starting, an agent finished, you left a comment: all of it lands as a pupdate. Pollers and plugins emit them; the cycle triages them; automations match on them. Because there is exactly one substrate, a new integration only has to answer one question: what pupdates do you make? Everything downstream already knows what to do with them.

one kind of event. that's the trick.
automations :: when → then

// the trigger layer is deliberately dumb

Automations route, they do not think

A rule is a predicate over pupdates ("a PR I am tagged on went stale") and an action ("leave me a memo", "wake the reviewer"). No model runs to decide whether a rule fired, so it is fast, legible, and never surprises you.

The predicate

Pure matching on pupdate fields. Same input, same answer, every time. You can read a rule and know exactly when it goes off.

The action

Resolved from a name to a handler: memo, task, wake an agent, or a custom one a plugin registered.

agent-lifecycle

// task → job → worktree → back to you

How an agent actually runs

A task is the thing to finish. An AgentJob is the one identity for a run: every session, automation kickoff, skill, and UI launch routes through it, so there is a single place that knows what an agent is doing and a single lock that stops two triggers from racing.

01

Spawn

Maiko cuts a git worktree and writes TASK.md and a CLAUDE.md (role protocol, the agent's character, the team's active insights). Siblings cannot step on each other.

02

Work, then talk back

The agent commits to its branch and runs maiko reply from inside the worktree. Talk-back is shell commands, not MCP tools, on purpose.

03

Monitor

The brain watches job state instead of trusting it blindly. Stuck or silent jobs get noticed and nudged on the next cycle.

04

Review and iterate

You read the diff in-app and leave inline comments. Request changes and the same job wakes, reads the comments, and goes again.

one job id. one lock. no races.
runtime-seam

// one loop, three ways to run a model

The runtime is swappable

Because an agent talks back over the CLI, the thing running the model sits behind one interface. The lifecycle above does not change when you change the runtime.

Headless

One-shot claude --print. The default. Fire, work, talk back, done.

Interactive in tmux

A persistent pane you can attach to and watch. New prompts inject into the live session instead of starting cold.

Local model

An Ollama runtime for the parts you would rather keep entirely on the machine. Same job, same talk-back.

knowledge :: the rulebook

// the memory that maintains itself

Signals become a rulebook

Review feedback and an agent's own confessed mistakes are signals. They graduate into two durable things: insights (short tribal notes that go in the playbook and inject into every new agent) and learnings (coding rules mined from your PR review history). Learnings are embedded locally and retrieved by relevance: an agent says what it is about to do and gets back only the handful of rules that apply, so hundreds of nits never drown a prompt. The embedding model runs on your machine. Nothing is sent out to score it.

At the end of the day the pack gathers at the campfire and shares what it learned. You approve what sticks. Tomorrow's pack wakes up with it. That ritual is a feature, not decoration.

it keeps the lessons. you keep the say.
plugins :: the seam

// for anything you never want to look at again

One Python class, dropped in

Put a file in ~/.maiko/plugins/ or ship it as a pip package that registers an entry point. It is discovered on startup and can opt into any of these without owning a single timer or thread.

Poll something

Subclass the poller and define what you fetch and what pupdates it becomes. The cycle drives the interval.

Add an action

Register a named handler and it shows up in the automation editor next to the built-ins.

A setup button

Expose a one-time bootstrap action (import this, connect that) as a button in Settings.

Hook the cycle

Run on a brain phase or once per tick. The instant another tool starts yelling at you, make Maiko deal with it instead.

teach it once. never look again.
deeper/

// read the long version

Go deeper

This page is the map. The full write-up has the corners: data and persistence, the substrate in detail, A2A and the maiko CLI, RAG retrieval, the parked LoRA experiment, awareness, guardrails, and the sharp edges.