A control plane that runs on your own machines
Your AI workforce. One route, one decision, one record.
You hold the pools: accounts, models, hosts, projects, roles. Kimene decides which of them runs the work, writes down why, and executes it on real machines through the real CLIs.
Pools
No entity owns another.
No account pinned to a project, no model pinned to an account. Association happens at execution time, is recorded as a route valid for that one run, and dissolves when the work ends.
A project expresses preferences, permissions and a routing mode. The router combines those with live capacity, health and history. What comes out is a record, not a configuration.
Kimene does not invent a quota.
Provider capacity, concurrency policy, resource leases and priority are four different things. Compressed into the one word "quota", an operator can never again tell which limit they hit.
proofgo test ./internal/domain — no quota field exists in the domain
The decision record
"The AI chose it" is not an explanation.
Hard eligibility first, then weighted scoring. The rejected candidates are written into the immutable decision with their reasons, exactly as the winner is.
components
| Why this account? | weight |
|---|---|
| verified_model | 0.25 |
| provider_capacity | 0.25 |
| capability_match | 0.20 |
| session_continuity | 0.15 |
| host_repository_locality | 0.10 |
| user_preference | 0.05 |
penalties
| rate_limit_proximity | −0.12 |
|---|---|
| unknown_capacity | −0.08 |
| stale_auth | −0.05 |
| model_lifecycle | −0.05 |
total0.86 − 0.08 = 0.78
selected
- claude-ops-1srv-ist-10.78
- claude-ops-2srv-fra-10.64
- codex-ops-1srv-ist-10.61
- claude-ops-2srv-ist-10.55
- codex-researchsrv-fra-10.41
rejected
- claude-ops-2ACCOUNT_AT_CONCURRENCY_LIMITat its concurrency limit
- codex-researchPROVIDER_CLI_NOT_INSTALLEDCLI not installed
- llm-yerelMODEL_UNAVAILABLE_FOR_ACCOUNTmodel not on this account
- claude-ops-1REPOSITORY_NOT_AVAILABLE_ON_HOSTrepository not on this host
- claude-arsivACCOUNT_DISABLEDaccount disabled
- codex-ops-1HOST_OFFLINEhost offline
- llm-yerelACCOUNT_NOT_REACHABLE_FROM_HOSTnot reachable from this host
The record carries the selected route, the candidates considered and rejected, every rejection reason, every component of the score, the capacity snapshots consulted, and any operator override.
total = Σ components − Σ penalties. There is no third path.
The route simulator replays the same scoring with hypothetical inputs, acquiring no leases and starting no sessions. "What if that host were down" has an answer that is arithmetic, not a guess.
proofgo test ./internal/routing — refuses a decision that cannot explain itself
Execution
The work runs on real machines, in the real CLIs.
The control plane never speaks to a provider CLI directly. Every session lives inside a tmux session started by the node agent on that machine.
That indirection is what makes a browser refresh, a server deploy and a dropped SSH connection harmless to work in progress.
On reconnect the screen is not redrawn from scratch; it resumes from the cursor you left. Every keystroke you send is applied exactly once — never swallowed, never typed twice.
proofmake test-live-terminal — a running loop survives its manager being shut down entirely
Evidence
"Done" is not a thing the agent gets to say.
Completed is reachable only through review or awaiting approval, and one transition table enforces it. There is no path in the API that writes a task state directly.
- diffsha256:0f0f7c21immutable
- test118 passed · 0 failedimmutable
- buildsha256:0f0fa93eimmutable
- lintno command defined
Each kind of task carries its own evidence contract. A code task wants a diff, a test, a lint and a build report plus a reviewer verdict; a research task wants sources with access dates.
Kimene will not invent a test command on your behalf.
A gate you have not defined stays shut and says why it is shut. Every report carries the command that produced it; artifacts are immutable, content-addressed and hash-verified.
proofgo test ./internal/domain ./internal/artifact — completed is reachable only from review or approval
Approval
A person signs what a person must sign.
Risk level comes from code, not from a prompt. High-risk work goes to a person, and if the operator requires it, that approval asks for a second factor.
- rule
- schema_change_requires_human
- touches
- mercury-api · 1 table · 0 rows destroyed
- on refusal
- task → BLOCKED · session parked at boundary
- requested by
- 01JQ8F3K7P · codex-ops-1
What may be applied with nobody watching are the actions that stop work and call for a person. Nothing that starts work or spends a subscription is applied without a human.
may run unattended
- pause_mission
- stop_session
- raise_alert
- request_human
waits for a person
- start_session
- route_task
- approve_task
- switch_account
- merge_branch
The approval card says what was asked for, which rule fired, which resources it touches and what happens if it is refused. The decision is recorded with who made it.
proofgo test ./internal/approval — approving your own work is structurally impossible
Continuity
A holder that arrives late cannot apply an effect.
Every lease carries an increasing fencing token. The guarded resource remembers the highest token it has seen and refuses anything lower.
- fence=17srv-ist-1granted
- fence=17srv-ist-1renewed
- fence=17srv-ist-1expired
- fence=18srv-fra-1granted
- fence=17srv-ist-1refusedrefused · 17 < 18
A switch happens only at a safe boundary.
A finished turn, a written checkpoint, a wait for a person, or a confirmed rate limit. Never mid tool-call, mid-write, mid-migration or mid-deploy.
- TURN_COMPLETED
- CHECKPOINT_CREATED
- TASK_STEP_COMPLETED
- WAITING_FOR_HUMAN
- RATE_LIMIT_CONFIRMED
- AUTH_FAILURE_CONFIRMED
- MODEL_UNAVAILABLE_CONFIRMED
- RECOVERABLE_SESSION_FAILURE
- mid tool call
- mid file write
- mid migration
- mid deploy
- mid paste
Leases live somewhere explicitly allowed to lose data. The only reason that pairing is safe is the fence: Kimene does not claim a guarantee a single cache cannot give — it claims the weaker, true one.
Transient is not persistent.
A two-second blip is not a provider failure; it retries in place. Only a typed, confirmed rate limit, auth failure or unreachable host moves the route.
proofmake test-integration-live — 32-way contention yields exactly one winner; a dead holder’s renewal is refused
Fleet
Unmeasured is not zero.
Unmeasured capacity has its own colour and its own hatching. Kimene never draws it as a number, because an empty bar and a zero bar look identical and mean opposite things.
What happens when a dependency goes down is written out.
No row in that table says "show stale data as though it were fresh".
| mongodb | Writes stop; reads are not served from cache as if fresh; an explicit unavailable state. |
|---|---|
| rabbitmq | UI and state stay readable; new async work queues in the local outbox; health shows degraded. |
| redis | Distributed operations are restricted; critical leases fail closed; an explicit warning. |
| mqtt | Node heartbeat falls back to the control-plane WebSocket; telemetry is badged degraded. |
The same refusal holds in scoring: unknown capacity is not an optimistic 1.0. A record, a measurement and an estimate are kept apart.
proofgo test ./internal/domain — capacity is a pointer, so unknown is representable and cannot read as zero
Security
The control plane holds no credentials.
Credentials stay on the machine that owns them; the database knows only a path and a reference. Compromising the database yields no provider credential.
- Mutual TLS for every byte after enrolment
- Redaction cannot be bypassed
- The browser never reaches a host directly
Provider isolation goes through the process environment, never a command line: a process list is world-readable and an environment is not. Nodes speak mutual TLS after a single-use enrolment token.
Being on an internal network is not a security control.
Redaction lives inside the log handler rather than at call sites, so it cannot be forgotten. Terminal output is never written as raw HTML, and a browser never connects to a machine directly.
proofgo test ./internal/security/redact — redaction lives in the log handler
Install
Four dependencies, four binaries, one doctor.
Ubuntu, Go and Node. A database, a queue, a cache and a message broker. doctor verifies all of them without changing anything, and tells you which mode it found.
One step waits for you on a fresh install: no account/model pairing is routable until one has been verified. That is deliberate — it is what stops work being sent to a pairing nobody has checked.
Known gaps.
Every document carries a "known gaps" section. That is the honest part; read it before relying on a capability.
- No scheduled backup — the commands exist, nothing runs them on a timer.
- No one-command node install; the binary is copied and enrolled by hand.
- The server install script does nothing about TLS or the reverse proxy; both are manual.
- A retention policy is seeded, and nothing enforces it.
- A handler that fails for a transient reason is not retried; it dead-letters.
- The terminal layer has not yet been exercised against a live tmux.
The recovery procedure differs by mode, which is why doctor names it. No containers, no orchestrator, no runtime that must be installed on every target before anything can run.
proofmake doctor — verifies all four dependencies non-destructively
On your own machines, with your own accounts.
Kimene runs on your infrastructure and manages your own provider accounts. It is not a credential-sharing service, not a multi-tenant proxy, and not a way around provider limits.