Dokoro
Persistent session memory. tachi-agent calls dokoro.recall before each run and dokoro.log after — bookending the loop with durable context. Opt in to in-loop recall and per-step note writes for long multi-step tasks.
// the hub
One small orchestrator at the center. Every front-end calls orchestrator.run(task); the hub recalls memory, runs a bounded ReAct loop, logs the trace, and halts cleanly.
Three composable layers: Dokoro gives tachi-agent persistent memory. TachiBot gives it better judgment — TachiBot orchestrates models; tachi-agent orchestrates work.
The complete public API is three interfaces — see src/types.ts. Because the orchestrator depends only on these, every integration composes the same hub.
| Seam | Swap it to… | Default |
|---|---|---|
| Driver the brain |
Pick a registered heart via TACHI_DRIVER — ollama · hermes · openai · openrouter — or register your own via registerDriver (a cloud model, OpenClaw, a Kimi swarm). A queued task's driver field overrides per task. Implement one Driver interface. |
local Qwen2.5 / Ollama (native /api/chat) |
| ToolHost the tools |
Add or remove MCP servers and tools — config, not code. An allow allowlist keeps dangerous tools out unless granted. |
dokoro + tachibot merged over stdio, namespaced ${server}_${tool} |
| Memory the context |
Swap the persistent-context backend or disable it entirely. The orchestrator is stateless between runs. | dokoro session recall / log |
Three composable layers — memory, runtime, and reasoning. Each is independently replaceable; none depends on the internals of another.
Persistent session memory. tachi-agent calls dokoro.recall before each run and dokoro.log after — bookending the loop with durable context. Opt in to in-loop recall and per-step note writes for long multi-step tasks.
The ReAct loop that orchestrates work: drives the bounded reason/act/observe cycle, owns the task queue and daemon, manages skills, and surfaces the REPL, CLI, Telegram, and Gateway front-ends.
Multi-model council that orchestrates models. tachi-agent calls tachibot_jury, tachibot_council, tachibot_grok_search, and other council tools over MCP — TachiBot handles provider routing and adjudication.
"TachiBot orchestrates models; tachi-agent orchestrates work."
Tools come from whatever MCP servers are connected — all config, not code. Connect tachibot and dokoro and these surface automatically, namespaced and ready:
# namespaced ${server}_${tool} — no registration in code tachibot_jury tachibot_council tachibot_grok_search tachibot_perplexity_ask tachibot_nextThought tachibot_execute_prompt_technique tachibot_workflow dokoro_session_recall # …add a server in config and its tools join the loop
Every run is wrapped by memory and bounded on three axes:
dokoro for relevant session context before the first reasoning step.dokoro for the next run to recall.maxIterations, a wall-clock timeoutMs, or a cooperative AbortSignal — Ctrl-C yields haltedBy: "aborted".By default memory is a bookend — recall once before the loop, log once after. Set memoryInLoop: true in OrchestratorOptions to go further:
Memory.note → dokoro shared_note_append — the append-only, agent-tagged blackboard.const result = await createOrchestrator({ driver, host, memory, options: { maxIterations: 20, timeoutMs: 120_000, memoryInLoop: true, // opt-in }, }).run("audit every ADR and flag gaps");
bookend (default): recall → loop → log · in-loop (opt-in): per-iteration recall refresh + per-step note → shared_note_append
The hub stays a per-run unit. The daemon wraps it for unattended operation — it owns the queue, the worker, the schedules, the event log, and the notifiers. Drivers are pluggable hearts behind the registry: TACHI_DRIVER sets the default, each queued task can override it.
A persistent, crash-safe task queue (.tachi/queue.json) and a worker
that drains it. Interrupted tasks re-queue on restart; failures retry with
exponential backoff. POST /tasks enqueues from outside.
A hand-edited .tachi/schedules.json (daily at HH:MM or
every N minutes), re-read live each tick; machine state kept in a
separate -state.json. Due entries feed the same queue.
TACHI_DRIVER picks the default brain — ollama ·
hermes · openai · openrouter — and a task's
driver field overrides it per task. Explicit selection only:
an unavailable heart fails the task loudly, never silently substitutes.
Every run appends to a durable JSONL log in .tachi/runs/, and
TACHI_NOTIFY pushes each task outcome to Telegram / Slack — the
record and the ping for runs nobody watched.