Oko/Docs

Product

Overview

What Oko owns, supported platforms, source setup, interfaces, operations, and support.

Oko: Understand What Your AI-Native Team Is Working On—and Why#

Source Issues Wisent Discord LinkedIn X Enterprise

Understand Your Team’s Interactions with AI.

What is the ROI on tokens? How did David from HR solve this issue? How long were my offshore contractors working yesterday?

Oko helps you find answers to those questions. We sync, analyse and interpret the transcripts of your interactions with AI to build a proactive, helpful layer of your interactions with your AI models. Monitor your team’s goals, speed and effectiveness. Oko knows everything!

Oko is one program, oko, written in Rust. Every command, every routine and all state live in it; model traffic goes from oko to Brama directly. The native macOS interface is a separate product in `wisent-ai/oko-desktop`, a SwiftUI display over oko through the decode-only OkoKit Swift package.

Product boundary#

Oko owns:

  • discovery of supported local coding-agent processes;
  • import of masked, provider-neutral Transcript Lake exports;
  • the transcript catalogue in the shared Oko database, written from Transcript Lake;
  • normalized transcript, session, process, Git, synchronization, and routing logic, all in oko;
  • headless catalogue, goal, telemetry, calendar, Slack, synchronization, and diagnostic operations in oko;
  • local goal-lifecycle inference through the qualified MLX release, served on loopback only for the command that classifies;
  • the model transport of agent commands and adopted terminals, inside oko.

Oko does not own:

  • a native application bundle, SwiftUI views, application lifecycle, or Sparkle updates — Oko Desktop owns those;
  • raw vendor transcript stores — vendors own them and Transcript Lake owns the masked canonical archive;
  • model credentials — Skarbiec owns secrets and Stado owns their materialization boundary;
  • remote serving-time model routing — Brama owns that contract; Oko's qualified goal-lifecycle model is an on-device exception and never receives provider credentials;
  • remote retained history or organization policy.

Package products#

The Rust crate in rust/ builds the one binary, oko. The Swift package in the same repository exports only OkoKit, the decode-only facade Oko Desktop displays through: each call is one oko command, and nothing in it reads a transcript, opens a database or decides anything.

swift
.product(name: "OkoKit", package: "oko")

Supported platforms#

Oko currently supports macOS 14 or newer only. The remaining platform-specific boundaries include Darwin/POSIX calls, EventKit, launchd, qlmanage, macOS application paths, and Unix permission/socket assumptions. Oko Desktop remains macOS-only.

Source usage#

Requirements: macOS 14 or newer and a Rust toolchain.

bash
git clone https://github.com/wisent-ai/oko.git
cd oko
cargo build --manifest-path rust/Cargo.toml --release --locked

Install the build you just made with a stable signing identity:

bash
rust/target/release/oko install

oko install requires stado 0.22.0 or later on PATH. It stages this build at ~/.stado/bin/oko (or --into PATH) and preserves ai.wisent.oko.oko-cli and the installed code requirement. --identity NAME chooses an exact identity; otherwise stado product signing selects it. For signing without a login-keychain prompt, supply WISENT_CODESIGN_CERTIFICATE_PEM (leaf plus issuers) and WISENT_CODESIGN_PRIVATE_KEY_PEM. Missing, ad-hoc, or incompatible identities are refused without replacing the destination, as is self-installation. The running service is asked to retire once its terminals finish. Oko Desktop does not build, install, embed, or update this executable.

First sign in to your team's Oko, then discover and initialize the catalogue from a real existing source. The task ledger Quickstarts continue from this setup through message ownership and coordinating API and Desktop work across sessions.

bash
oko lake sources
oko lake adopt --source claude --root "$HOME/.claude/projects"

The first-use equivalent is oko onboarding --source claude --root "$HOME/.claude/projects"; --skip-source keeps an empty usable Oko and --reset replays the choice. Transcript Lake validates and ingests the exact discovered root and persists its native identity; only then does oko bring the catalogue in the shared Oko database up to the Lake. Use --json for imported, unchanged, conflicting, rejected, and catalogue counts. Oko never parses the raw vendor source.

Complete operator search

Operator text has its own complete search field. Long assistant/tool sections cannot remove instructions from the middle of a session. Desktop and the MCP tool oko_search_sessions return the matching operator excerpt from the same catalogue. Assistant and tool context remains bounded; the operator field is not sampled.

Catalogue migration preserves existing search text, row IDs, and task evidence. The normal indexer backfills operator text on its next pass, without a reset. If a catalogue came from a newer Oko schema, the CLI refuses to open it instead of changing its contents. Keep the error and use the matching Oko release.

The catalogue journeys run the built oko (OKO_CLI_BIN, else rust/target/release/oko) through swift test --filter 'TaskJourneyTests|OneOffJourneyTests|TranscriptJourneyTests'; receipts stay under .build/.

Enable the bounded autonomous operator and install the one Oko service. The declared unit, com.wisent.compute.service.oko-autonomy, runs oko serve itself. That one process owns the PTY broker and prints `broker listening on synchronisation and task handover are Oko routines Stado schedules, not loops inside it:

bash
oko autonomy mode experimental --max-runs-per-day <runs> \
  --max-runtime-seconds <seconds> --retry-backoff-seconds <seconds>
stado product install oko --surface cli
stado service ensure oko-autonomy --host <registry-target> \
  --from "$HOME/.stado/bin/oko" --arg=serve \
  --env=PATH="$HOME/.local/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin" \
  --reason "run the one Oko process on this host"
oko routines create --id <retained-uuid> --name "Autonomy" \
  --action autonomy --cron "*/5 * * * *" --tz UTC --host <registry-target>

A retired loop flag such as --autonomy-interval is named on stderr and ignored. When the unit starts, it retires the launch agents whose work it absorbed; a person running oko serve by hand never unloads the host's services.

Experimental mode considers only the signed-in local user's active goals under ~/Documents/CodingProjects/Wisent and forbids purchases, irreversible external actions, releases, and service mutations; how many goals a day it may complete, how long a run may take and how long it waits after a failure are the limits given to oko autonomy mode. A goal is closed only after Jeden Pursuit returns a readable successful receipt with an independent acceptance verdict. oko autonomy status reports the policy and every recorded run; oko autonomy mode disabled stops new objective execution and keeps the limits. oko autonomy mode full expands selection to organization goals and permits reversible deployments, while purchases and irreversible external actions remain disabled.

Context, proactive work and routines

oko context snapshot --query "release" --limit <documents per source> reads the masked catalogue plus company and Slack caches without a model call; --limit is required and is how many documents each source answers. Each source names its read operation, location, observation time and error. A cache is labelled cached; an unavailable source is not an empty successful read. The required catalogue is opened read-only. oko chat status --provider slack --json checks actual Slack authentication and conversation access without posting. A credential refusal names the exact Skarbiec consumer, item, field and failed operation.

Questions and explanations do not authorize the actions they mention. suggestions tick answers eligible Slack requests; its proactive output still requires the existing explicit opt-in. Empty or duplicate channel filters are refused. A channel-filtered tick omits global approval retries, assignment fanout and weekly coaching. Explicitly requested actions may still use their existing approval or escalation routes; a channel filter is not a sandbox. The execution journal under ~/.oko/slack-executions records a claim before work and the result before delivery. Delivery retries cannot rerun that work. An interrupted action remains unknown and requires inspection, not blind retry.

Assignment delivery updates ~/.oko/assignments.json only after the recipient's message service acknowledges the send. A failed assignment, reassignment or follow-up does not advance its delivery checkpoint. Concurrent assignment runs are refused through the shared file lock. Corrupt assignment state and failed atomic writes exit nonzero instead of becoming an empty successful plan. suggestions costs uses the same lock and refuses unreadable assignment state. An acknowledgement followed by a failed local write remains uncertain; it is not a guarantee of exactly-once delivery at the messaging provider.

For recurring work, retain a new UUID before creating the schedule:

bash
oko routines create --id <retained-uuid> --name "Monthly context" \
  --action context --limit <documents per source> --cron "0 9 1 * *" \
  --tz Europe/Warsaw --host <registry-target>
oko routines show <schedule-id>
oko routines resume <schedule-id>
oko routines run <schedule-id> --retry-token <retained-run-token>
oko routines inspect <job-id>
oko routines pause <schedule-id>
oko routines remove <schedule-id>

A verb routines does not have is refused by name: routines: unknown command 'x'; the verbs are create, list, show, pause, resume, remove, run, inspect, execute, pending, retain, token. pending lists the creation requests retained before their schedule exists, retain keeps a new one, and token retains the retry token of one run. Inspection asks Stado whether the job has stopped moving — machine status reports terminal beside state — instead of Oko keeping its own copy of Stado's finished-state words.

Creation is paused by default. Stado owns the clock, timezone, placement, overlap prevention and queue; Oko has no second schedule store. The selected existing host needs the installed Oko CLI and its normal Stado agent. A Stado coordinator must be running for clock-driven occurrences. A manual run does not prove the clock is active. Pausing/removing stops future occurrences, not already submitted jobs. Inspect validates routine-result.json against the job and definition; submitted, completed-process and accepted-result states are distinct.

The operations are context, autonomy, control (task handover), telemetry, index (catalogue synchronisation) and suggestions (the Slack responder). Autonomy uses the selected host's persisted policy and configured Jeden model through Brama. A missing model route is a failure, never permission to select another provider. Oko has no payment executor: a calendar entry or a question about monthly payroll cannot authorize or execute a transfer.

The routine journeys exercise an actual Stado coordinator clock and worker, not a simulated provider. The independent Pursuit journey requires a usable configured Brama model; a refusal is a failed journey.

The goal commands oko goals extract and oko goals recompute stage ask the qualified goal-lifecycle model through Brama, as Oko with its scoped bearer and signed body. OKO_LIFECYCLE_MODEL_ALIAS declares the classifier alias; without it the goal operation refuses by name. Oko starts no model server and dials no address of its own. For a separate signed model request, use oko gateway send with the complete request body on standard input.

Interfaces#

  • Oko Desktop: canonical human interface for session inventory, search, local resume, and configured team views; it only displays what oko answers.
  • `oko`: the one program: catalogue, routing, sync, goals, calendar, Slack, tasks, and diagnostic operations; oko help lists every command group with its verbs and what it is for, and oko <group> --help prints that group's line.
  • `oko serve`: the one resident process on a host; it owns the PTY broker.
  • `oko autonomy`: persisted delegated policy, bounded objective selection, Jeden Pursuit execution, and receipt-gated goal completion.
  • `oko mcp serve`: read-only Model Context Protocol server over the catalogue (oko_recent_sessions, oko_search_sessions, oko_roadmap_items) and byk's team views; it never indexes or writes.
  • goal-lifecycle model: the goal commands ask the qualified oko-goal-lifecycle-v1 model through Brama under the alias OKO_LIFECYCLE_MODEL_ALIAS declares; Oko runs no model server of its own.
  • `OkoKit`: decode-only Swift facade over oko for Oko Desktop.
  • Transcript Lake export: canonical historical input contract.
  • Stado release objects: the signed oko binary, its digest manifest, and the source revision it was built from.

Operational model#

  • Configuration comes from explicit settings and environment values; there is no compiled router fallback.
  • The catalogue in the shared Oko database is a projection of Transcript Lake; oko index sync rebuilds it.
  • Repeating or extending an instruction does not delete the earlier task identity, its evidence or its relations. Use oko tasks relate <repeated-task> duplicate-of <original-task> --by <session> to join genuine duplicates explicitly; CLI and Desktop consume that same ledger. Claim, state, check and evidence refuse a withdrawn or reclassified task instead of redirecting the write to a later text extension. For read-only retention qualification, set OKO_TEST_SOURCE_REVISION, OKO_TEST_SESSION, OKO_TEST_ORIGINAL_TASK and OKO_TEST_EXTENDED_TASK to a committed candidate and two consecutive open tasks where the later request extends the earlier verbatim; run cargo test --manifest-path rust/Cargo.toml --test tasks-prefix-identity an_extended_request -- --ignored --nocapture. For refusal qualification, use a separate dedicated live fixture, never an operator's working session: set OKO_TEST_REFUSAL_SESSION, OKO_TEST_NON_TASK_MESSAGE and OKO_TEST_REFUSAL_EXTENDED_TASK to a non-task message and a later unclaimed task extending its text, with the same source-revision input; run cargo test --manifest-path rust/Cargo.toml --test tasks-prefix-identity a_non_task_number -- --ignored --nocapture. It attempts to claim the non-task, retains the refusal naming that session and message, and reads persisted state to prove the later task was not claimed. Both journeys retain commands, exits, output and source/binary identities under .build/tasks/prefix-identity/; both require build/test authorization. A failed candidate can alter the dedicated refusal fixture, which must not be reused as operator work.
  • Where the shared database is (its address, public anon key and the signed-in person's organization) is resolved through Stado and Skarbiec once and kept owner-only in ~/.oko/database.json; oko database check resolves it afresh, and a request that fails drops it so the next command resolves again. The URL and anon key are read as Skarbiec consumer oko-database-client with ~/.stado/oko-database-client-skarbiec-token, never as oko: Skarbiec keeps one bearer per consumer, and oko's is the Brama bearer oko-model-router#token.
  • Without Stado or Skarbiec, set OKO_DATABASE_URL and OKO_DATABASE_ANON_KEY together: Oko then takes the address and key from its environment and asks neither. One of the two without the other is refused with "OKO_DATABASE_URL is set but OKO_DATABASE_ANON_KEY is not; set both, or neither to ask Stado" (or the reverse).
  • Without Brama, the asking session's attestation stands in for a model judgment. When the decision guard (the check that a defect being recorded or assigned, or a supervisor's message to an executor, reverses no operator decision bound to a Tama hook) cannot ask a model — the machine declares none (oko model-service set --none), Brama's route is held, or the call fails — the operation is refused with "<operation> has no judgment: <cause>. Without Brama the asking session's attestation stands in: run it again with OKO_ATTESTATION=…". Run with OKO_ATTESTATION="<what you checked and why the operation holds>" and the operation proceeds on that statement; each attestation is kept, with the operation, the cause no judgment was given and the time, as one JSON line in attestations.jsonl beside Oko's registers (or the file OKO_ATTESTATION_REGISTER names), and the command says on stderr where. A judgment Brama did give is never replaced by an attestation; oko serve's own sends carry none and stay refused.
  • Oko's own actors with no session behind them stand on the decision they act on instead: the model policy pass's continuation step and every supervision pass state what they decided (continuing each stopped executor and supervisor on the open work Oko's registers hold for it, or dispatching it to the executors measured capacity admits, with the briefs composed from their declared templates), and an operation inside them whose judgment Brama does not give stands on that statement, kept in the attestation register like a session's. Without it, a service pass had no attestation to give and, with Brama down, continued and dispatched nothing.
  • Credentials are materialized for exact Skarbiec consumers and remain process-local.
  • A model route being reachable does not prove provider authorization, quota, or end-to-end model success.
  • Autonomous execution is disabled until an explicit persisted policy enables it; the Stado-managed service invokes a single lease-protected scheduler. Broker session listing, task-transcript discovery and lease discovery refuse a failed child-completion observation with the session ID, PID and actual operating-system cause instead of presenting unknown state as live or idle; missing or nonnumeric session creation timestamps also refuse ordering. The controller counts every still-owned worker against capacity and preserves its transcript ownership between writes and after an answer until the actual process completes. It never ends a worker from transcript content; the inferred reaped field is removed. Explicitly ending a terminal reports the signal, owning session, process-group PID and OS cause if signal delivery fails, without dropping that ownership. A kernel-reported absent group is already gone; successful signal delivery alone is not proof that its process has exited. If recording a failed control pass also fails, the returned error retains both the initiating operation and the recording cause; an unpersisted failure is not presented as a successfully recorded pass. The real control-pass qualification requires OKO_TEST_SOURCE_REVISION, retains the candidate patch and binary digest, refuses an uncommitted candidate, and inspects the actual persisted stage rows. The separate broker handover journey in tests/sessions/handover.rs requires that same source binding, refuses shutdown-if-idle while its actual terminal is alive, and verifies the same terminal and owning broker survive before normal handover and final idle shutdown. Neither journey substitutes for dedicated process-observation, signal-refusal or graphical qualification.
  • The autonomy scheduler counts successful accepted outcomes against its daily limit; idle and failed attempts remain recorded and are retry-backoff gated.

Shared session refresh

Concurrent CLI reads, Desktop-backed reads and realtime subscriptions share the signed-in session. Refresh ownership is serialized across Oko processes using the session's sibling lock file. After acquiring ownership, a caller rereads the persisted session and reuses an already refreshed token instead of exchanging it again. A provider-rejected token is replaced even if its locally recorded expiry is still in the future. A server error on the refresh (a 5xx, a proxy's gateway or timeout answer among them) is not a refusal of the token: nothing is recorded, the command fails with the answer, and the next command refreshes again. A recorded rate limit retains both the retry time the provider declared and the actual provider refusal, so later processes explain the same cause without sending another refresh. An older record containing only that retry time remains a refusal and explicitly says the provider cause was not retained; Oko does not fabricate the missing answer or refresh before that time.

A missing or unreadable session identifies its file. Lock acquisition failures identify the lock and operating-system cause. A malformed refresh response names the invalid field; missing expiry is not replaced with the current time. A changed account is refused rather than combining its credentials with the command's previous organization. Provider failures retain the failed operation and provider cause; a rate-limit refusal is not an empty successful task list. If saving a provider refusal or rate limit also fails, the error preserves both the provider cause and the failed persistence operation, path and filesystem cause. If the provider refreshed the session but saving its replacement fails, that accepted exchange is stated explicitly rather than reported as a provider rejection. These errors follow the same CLI and native Tasks failure path; an unsuccessful persistence operation never claims the refusal was durably recorded.

Goal operations preserve that same database refusal rather than relabelling every storage, discovery, organization or refresh failure as a missing login. A provider-supplied retry interval that exceeds the supported signed duration or timestamp range is refused with its exact seconds and the conversion failure; Oko does not wrap it into an expired deadline, panic while adding it, or invent a replacement interval. The provider cause remains part of that recorded refusal. To replace a refused session, use the explicit request and verification flow.

The real concurrency journey requires a separate signed-in account under OKO_TEST_DATABASE_ISOLATED_HOME and a declared OKO_TEST_CONCURRENT_READERS; run cargo test --manifest-path rust/Cargo.toml --test database-session-refresh concurrent_readers -- --ignored --nocapture. It checks actual concurrent database results, one refresh exchange, persisted future expiry and invalid-session refusal. The separate recorded_rate_limit case in that target requires OKO_TEST_SOURCE_REVISION and OKO_TEST_RATE_LIMIT_HOME: a genuine provider-limited account below the checkout's .build, with an unexpired recorded deadline and retained provider cause. Two actual consumer processes must return that cause without another refresh or changed session bytes. It does not manufacture a rate limit or replace the concurrency account. Both select their exact isolated session path even if the caller inherited OKO_SESSION_PATH; reports remain under .build/database/session-refresh/. The release-bound database-login case provider_refusal_survives_failure_to_persist_it sends an invalid isolated token to the actual provider while its profile refuses writes, requiring the provider and observed filesystem causes, unchanged bytes, restored permissions and normal logout. It uses WISENT_SOURCE_COMMIT, WISENT_SOURCE_SHA256 and WISENT_OUTPUT_DIR, retaining commands and restoration under .build/refresh-persistence-<run-id>/. All journeys require the applicable build and test authorization; authored cases are not passing results.

Project status and support#

  • Maturity: public development source for macOS 14+.
  • Local contract: local inspection, normalized transcript rendering, search, and supported local resume.
  • Managed contract: team synchronization, retained history, organization policy, and supported release operation remain separate.
  • Issues: `wisent-ai/oko`.
  • Security and privacy: use private GitHub Security Advisories; never attach transcripts, prompts, tool results, peer metadata, credentials, or production endpoints to a public issue.
  • Licence: no repository licence file is currently present. Do not infer a redistribution grant until dependency and ownership review is complete. Oko Desktop provides the signed Oko.app macOS interface and its independent Sparkle release channel. Updating Oko Desktop does not replace oko; updating Oko does not replace Oko.app.

Migrated from src/content/docs/overview.md