<!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
<!-- Copyright (C) 2026 SOTTO contributors -->

# Sotto setup, phase by phase

This is the self-hoster's build-order map. Sotto ships as a
[roadmap that always leaves something working](index.html#roadmap): each phase
stands up one more capability on top of a system that already runs, so you set it
up the same way you would build it, one phase at a time. Stop at any phase and you
still have a usable system; the next phase only adds to it.

Use this page to decide where to start and what to do next. Each phase below says
what you get, what you stand up, and which detailed guide or contract to follow.
The step-by-step commands live in the guides this page links; the exact interface
detail lives in the `specs/*.md` contracts. This page is orientation. When it and a
spec disagree, the spec wins; fix the spec and mirror it here in the same change.

## How to read this

- **You only need the phases you want.** A private text chatbot on your LAN is done
  at Phase 1. Voice is Phase 3. Tools are Phase 4. Pick your stopping point.
- **The phases are ordered by dependency, not preference.** Phase 0 (the link) is
  the one hard prerequisite: nothing else is reachable from the phone until it
  works. After that, the server phases (1, 3, 4) and the client phases (2, 3, 4)
  interleave on the same encrypted link.
- **Two devices, one link.** Most phases touch both the Mac (the brain) and the
  phone (the microphone and the hands). The [architecture overview](architecture.md)
  is the map of how they fit together if you want the whole picture first.

## Phase 0: Link first

**What you get:** a verified, end-to-end-encrypted iroh tunnel between the phone and
the Mac, dialed by the Mac's public key, with a relay fallback for when the two
peers cannot punch a direct path. Nothing else in Sotto is reachable from the phone
until this link is real, so it comes first.

**What you stand up:** the Rust iroh sidecar (`sidecar/`), one daemon that owns the
link on each side. The Mac runs it in listen mode and admits only allowlisted peers
by public key; the phone (or a second host, for a bench test) runs it in dial mode.

**Follow:** the [bootstrap and connectivity smoke test](bootstrap.md) takes you from
two cold machines to a trusted tunnel and proves it with a smoke test. The transport
contract is [`specs/transport.md`](specs/transport.md). If you run a commercial VPN,
the [networking guide](networking.md) shows the per-app split-tunnel so the direct
path stays direct.

## Phase 1: Server text loop

**What you get:** a private text chatbot. The Mac runs the models and owns the
canonical chat, project, and memory store; the phone (or any HTTP client) hits an
OpenAI-compatible endpoint over the Phase 0 link and gets streamed replies. No
third-party AI provider is ever in the path.

**What you stand up:** the Python orchestrator (`server/orchestrator/`), the FastAPI
brain, plus the model engine (Ollama serving Gemma 4). This is the full server
stack, so the full-stack guide is the entry point.

**Follow:** the [full-stack quickstart](quickstart.md) takes you from a clean machine
to a running server on either a Mac (native engine, containerized services) or Linux
with an NVIDIA card (fully containerized). The wire shape is
[`specs/api.md`](specs/api.md); everything you configure, including model tags and
secrets, is [`specs/config-and-secrets.md`](specs/config-and-secrets.md).

## Phase 2: Chatbot app

**What you get:** a clean chatbot on the phone before it ever hears you. A native
Jetpack Compose UI, chats and projects synced to the Mac, text in and text out over
the same encrypted link.

**What you stand up:** the Android client (`app/`). You pair it with the Mac (trust
the Mac's public key, admit the phone's), then let it sync against the store the
orchestrator already owns.

**Follow:** pairing reuses the Phase 0 allowlist from [bootstrap.md](bootstrap.md).
Sync semantics (what is authoritative, how conflicts resolve) are
[`specs/sync.md`](specs/sync.md); the chat and project data model behind it is
[`specs/data-and-rest.md`](specs/data-and-rest.md).

## Phase 3: Voice loop

**What you get:** spoken conversation. You talk, the phone captures until you stop,
the Mac transcribes and reasons and speaks the reply back, streaming the audio
sentence by sentence so the first words land while the model is still generating.

**What you stand up:** the speech services on the Mac. Kokoro for text to speech
(`server/tts`) and, off the Mac, whisper.cpp for speech to text (`server/stt`); on
the Mac itself, Parakeet runs natively for transcription. The app grows audio
capture and playback, push-to-talk first and then wake-word invocation.

**Follow:** the audio pipeline, the streaming-TTS contract, and the barge-in rules
are [`specs/audio.md`](specs/audio.md). The speech services come up with the rest of
the stack in the [quickstart](quickstart.md).

## Phase 4: Assistant role + tools

**What you get:** an assistant that can act. Invoke it by gesture as the Android
assistant, and let it run real device actions, all off by default and behind
explicit, per-tool consent.

**What you stand up:** the tool registry and the permissions screen in the app,
wiring native Android actions and the Shizuku bridge behind their toggles. Every
tool maps to a real permission or grant, carries a risk tier, and is opt-in;
high-risk tools ask every time.

**Follow:** the tool model (two-tier exposure, the consent gate, the audit trail,
per-project overrides) is [`specs/tools.md`](specs/tools.md).

## Phase 5: Package & open-source

**What you get:** a reproducible, shareable install. The server wrapped as a Mac
menu-bar app that supervises the native services, the Docker Compose stacks for both
deploy paths, pinned versions and sane defaults. This is the public release, and the
phase this guide is part of.

**What you stand up:** the `mac-app/` supervisor bundle, or the Compose stacks
straight from the repo. This is the same stack as Phase 1, now packaged rather than
run by hand.

**Follow:** the [full-stack quickstart](quickstart.md) is the packaged install path;
pinned model tags and defaults trace back to
[`specs/config-and-secrets.md`](specs/config-and-secrets.md).

## Phase 6: Global memory

**What you get:** memory that persists across conversations, scoped per project and
fully under your control. This is the future release, not part of the current public
build.

**What you stand up:** the memories table, retrieval, and a management UI. When it
ships, it layers onto the store the orchestrator already owns; nothing you set up in
the earlier phases changes.

**Follow:** the design and contract are [`specs/memory.md`](specs/memory.md).

## Where to go next

- Building on Sotto rather than just running it? Start with the
  [architecture overview](architecture.md).
- Standing up the server right now? Jump to the
  [full-stack quickstart](quickstart.md).
- Just want the link proven first? Run the [bootstrap smoke test](bootstrap.md).
