* feat(voice): configure OpenAI STT and TTS endpoints separately
Replace providers.openai.voice (a single apiKey/baseUrl shared by
speech-to-text and text-to-speech) with independent providers.openai.stt
and providers.openai.tts, each carrying its own apiKey/baseUrl. STT and
TTS now resolve fully independently, so they can point at different
OpenAI-compatible endpoints. The env equivalents OPENAI_VOICE_API_KEY /
OPENAI_VOICE_BASE_URL split into OPENAI_STT_* and OPENAI_TTS_*.
No backcompat: the voice key is removed and no longer read. Each feature
still falls back to providers.openai.apiKey/baseUrl, then OPENAI_API_KEY/
OPENAI_BASE_URL. Composer dictation resolves from the STT endpoint.
* fix(voice): keep daemon bootable and respect global OpenAI key
Two issues from review of the STT/TTS endpoint split:
- A config from an older release that still sets providers.openai.voice
crashed daemon startup, because the strict schema rejects the now-unknown
key. Strip it before parsing (alongside the existing local.autoDownload
strip) so the daemon boots; the value is discarded, not migrated.
- An empty endpoint env var (e.g. a copied .env.example leaving
OPENAI_STT_API_KEY= blank) shadowed the OPENAI_API_KEY fallback, so
speech was reported as missing credentials despite a configured global
key. firstDefined now skips empty/whitespace strings.
* fix(voice): isolate STT and TTS option parsing per endpoint
An STT-only OpenAI setup could be broken by a stale or invalid TTS env
var (e.g. a leftover TTS_VOICE/TTS_MODEL), because the single resolution
schema validated both endpoints' option groups before the per-endpoint
gate. Split into endpoint-key, STT-option, and TTS-option schemas and
parse each option group only when that endpoint has credentials, so an
unused endpoint's bad env can no longer take down the configured one.
* fix(voice): tag voice-config shim and update direct-daemon test callers
- Mark the providers.openai.voice strip with a COMPAT(openaiVoiceConfig)
comment + removal date so it shows up in the back-compat cleanup
inventory, per repo convention.
- Update the tests that build the daemon directly with a resolved OpenAI
config (bootstrap smoke + the real-API voice/daemon e2e suites) to the
new { stt, tts } shape; the old top-level { apiKey } is no longer read,
and these files are excluded from typecheck so the break was silent.
* fix(voice): update voice-roundtrip debug script to new OpenAI config shape
Last direct daemon caller still passing the removed top-level
openai: { apiKey }; the debug script lives outside tsconfig.scripts.json
so the stale shape wasn't caught by typecheck. Use { stt, tts }.
* Add Docker images and agent Docker Mods
Ship official container images that run the Paseo daemon headless. One
Dockerfile parametrized by BASE_IMAGE covers Debian 12/13, Ubuntu 22.04/24.04
and Alpine; it bundles Node 22, the npm-published server + CLI, a vendored
s6-overlay as PID 1, and a small Docker Mods loader.
Agents are chosen at runtime via DOCKER_MODS (pipe-separated mod images). Each
mod is a FROM scratch image carrying only an install hook that runs
`npm install -g <agent-cli>`; the loader pulls the layers from the registry,
extracts them, and runs the hook before the daemon starts, so any requested
agent is on PATH when Paseo probes provider availability.
- docker/base: Dockerfile, install scripts, s6 services, mods loader
- docker/mods/*: claude-code, codex, copilot, opencode, pi
- docker/docker-compose.example.yml + docker/README.md
- .github/workflows/docker.yml: multi-arch (amd64/arm64) buildx matrix,
publishes to ghcr.io/getpaseo on version tags
- docs/docker.md + CLAUDE.md docs index row
* feat(docker): print pairing QR and link on daemon startup
Add an s6 oneshot service that waits for the daemon to listen, then runs
`paseo daemon pair` so the pairing QR code and link surface in the container
logs. Best-effort: never blocks boot, skips gracefully when relay is disabled.
Opt out with PASEO_PAIRING_QR=0.
* build(docker): add Arch image support
* ci(docker): build Arch without Buildx
* docs(docker): document paseo env contract
* feat(docker): add opt-in sudo mode
* docs(docker): link env references
* fix(docker): create agent config dirs
* fix(docker): default home to /home/paseo
* docs(docker): document agent auth setup
* docs(docker): document relay port setup
* fix(docker): install Node from tarball
* docs: add Docker quick start
* docs(docker): remove legacy home example
* docs(docker): set container hostname
* fix(docker): prepare opencode storage
* fix(docker): allow paseo login shell
* fix docker opencode permissions
* ci(docker): use Node 24 actions
* fix(docker): install bzip2 runtime tools
* fix(docker): update Pi mod package
* fix(docker): quiet default daemon logs
* fix(docker): split home from state
Docker images now keep HOME at /home/paseo and store Paseo daemon state under /home/paseo/.paseo by default.
Existing volumes can keep the old layout by setting PASEO_HOME=/home/paseo.
* fix(docker): keep mods out of paseo home
* ci(docker): skip alpine arm64 builds
* fix(docker): address review findings
* fix(docker): verify s6 overlay downloads
* fix(docker): honor custom healthcheck port
* fix(docker): fail on mod extraction errors
* feat(docker): add official container image
Ship a focused daemon image with the bundled web UI enabled and document extending it with agent CLIs.
* ci(docker): publish images only on stable releases
* fix(docker): check daemon health over HTTP
---------
Co-authored-by: Herbrant <cdavide98carnemolla@gmail.com>
Documents the daemon-served web UI from #1635: enabling it, reverse
proxy, TLS, tunnels, and the auth/exposure model. Adds a community
projects page for community-built self-hosting tooling.
Resolve OpenAI voice credentials and endpoints from voice-specific config before broader OpenAI fallbacks, and use the same REST STT provider for dictation and voice mode.
Covers providers showing "Not installed", the login-shell/PATH
mismatch behind agents and terminals not seeing your commands, and
restarting the daemon after config changes.
Metadata prompts (workspace title + branch, commit message, PR) mixed the
functional contract with style guidance in one block, and project-owner
instructions from paseo.json were appended after the defaults with an
"override where they conflict" notice — so custom wording competed with the
built-in style instead of replacing it.
Each prompt is now a non-overridable contract (what to produce, the JSON
shape, correctness/safety rules) plus style slots that paseo.json
instructions replace wholesale. Title and branch style are now separate
keys (metadataGeneration.title vs .branchName); previously branchName
instructions also shaped the title.
* Name agents by their first prompt line instead of an LLM summary
The workspace title already captures the task; the LLM-generated agent
title just restated the same prompt. Drop the generator and keep the
provisional title (first prompt line), so the agent label stays
deterministic and explicit titles still win.
* Remove the no-op agent-title setting and leftover generator plumbing
Deleting the agent-title generator left its whole surface dangling: a
configurable "Agent titles" project setting that no longer did anything,
dead create-path plumbing, generator-only import/MCP deps, and the mock
provider's agent-title parser. Remove all of it, plus a dead test mock
and timing sleeps that guarded the deleted background job. Replace them
with a no-mock lifecycle test asserting the title stays the first prompt
line across create and settle.
Old paseo.json files with metadataGeneration.agentTitle still parse via
schema passthrough — see COMPAT(projectMetadataAgentTitle).
* Rework docs navigation and move alternatives to top-level pages
- Add nested docs nav with categories, collapsible groups, breadcrumbs,
and a right-hand page outline with heading slugs.
- Move alternatives out of /docs/alternatives into /alternatives/*
marketing pages with 301 redirects.
- Add github-slugger for heading IDs and require explicit width on
SiteShell so new pages can't accidentally pick the narrow prose layout.
- Remove the best-practices doc from public-docs.
* Make docs content column prose-width
Adds a new conceptual Workspaces doc that explains how Paseo organizes work around projects, workspaces, and sessions. Reframed the existing Git worktrees page as the technical deep-dive it always was. Updated glossary with agent session and tab terminology. Reordered docs nav so workspaces and worktrees come before providers.
The ACP catalog kimi entry still referenced the legacy Python kimi-cli. Moonshot's actively maintained agent is now the TypeScript Kimi Code CLI (@moonshot-ai/kimi-code), which exposes the same kimi acp server. Update title, description, version, and install link to match; the launch command is unchanged.
* Add configurable worktree root
Allow new Paseo worktrees to be created under a custom worktrees.root from config.json while preserving the existing PASEO_HOME/worktrees default. Thread the resolved root through create/list/archive/ownership flows, MCP/session paths, checkout metadata, schema, docs, and targeted tests.
* Address worktree root review feedback
Use the resolved Paseo worktree base when a custom PASEO_HOME is provided, and remove an unused worktreesRoot dependency from worktree list handling.
* Fix checkout worktree path test on Windows
Use platform-native paths in the custom PASEO_HOME regression test so Windows CI compares against the same resolved root shape as production code.
* Clarify optional worktrees config docs
---------
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
Adds the /grok SEO landing page (and its auto-generated route/sitemap
entries), the /agents directory card, and the Grok line in the ACP
catalog docs, following the Grok Build provider added to the in-app
catalog.
v2 is English-only; v3 covers 25 European languages with automatic
language detection. The archive shares v2's filenames, architecture,
sample rate, and feature dim, so no runtime loader changes are needed.
Document that the `language` config field and PASEO_*_LANGUAGE vars
only steer the OpenAI STT provider — the local Parakeet models ignore
them, so multilingual local dictation means selecting the v3 model.
The documented parakeet-tdt-0.6b-v3-int8 doesn't exist in the model
catalog; only the v2 variant is accepted. Copying the doc value into
config produced an "invalid model id" error on daemon restart.
Group the docs sidebar by directory so the new pages cluster
under a heading, add a hamburger menu for the mobile docs nav,
and let the docs main column shrink so wide code blocks and
tables scroll inside instead of pushing the page wide.
* fix(cli): honor PASEO_PASSWORD env var (fix#776)
The CLI only extracted passwords from `tcp://host?password=` URIs, so
`PASEO_PASSWORD=xxxx paseo ls` connected without auth and was rejected
by the daemon with "Password required". Fall back to the env var when
the host (TCP or otherwise) carries no password.
* docs: document PASEO_PASSWORD env var as a CLI auth source
Pairs with the CLI fix in this branch — the "Connecting with a password"
section now lists both the tcp URI query and the env-var fallback, with
their precedence. Also clarify the dual role (daemon vs CLI) of
PASEO_PASSWORD in the env var reference.
Only /api/health remains public for liveness probes. /api/status
exposes hostname, version, and server ID which shouldn't be
accessible without authentication.
Pass `--host https://app.paseo.sh/#offer=...` (or `PASEO_HOST=...`) to
any CLI command and the connection routes through the relay with E2EE,
the same way the mobile and desktop apps connect. Same `paseo daemon
pair` link the app already accepts — no new pairing flow.
Closes#181
* docs: rename to lowercase + drop leftover plans
Rename docs in docs/ to lowercase kebab-case for consistency and update
all references in CLAUDE.md, CONTRIBUTING.md, CHANGELOG.md,
packages/server/CLAUDE.md, and inter-doc links.
Drop two leftover design plan docs:
- docs/ATTACHMENT_BASED_REVIEW_CONTEXT_PLAN.md
- docs/plan-approval-normalization.md
* docs: drop stale uppercase entries from case-insensitive rename
* feat(website): power /docs from public-docs/ markdown tree
Move website docs out of TSX route components and into a root-level
public-docs/ directory of plain markdown files with frontmatter
(title, description, nav, order).
- Add packages/website/src/docs.ts loader using import.meta.glob with
?raw to compile the markdown into the bundle at build time.
- Replace the 9 hand-written docs/*.tsx routes with a single $.tsx
catch-all that renders any slug via react-markdown.
- Drive the docs sidebar nav from frontmatter order/nav.
- Auto-discover docs routes in vite.config.ts so the sitemap stays in
sync without manual edits.
* fix(website): bind dev server to 0.0.0.0 so port collisions trigger fallback
`host: "127.0.0.1"` (or unset) lets macOS coexist with another process
holding an IPv6 dual-stack `*:8082` socket, so Vite never sees
EADDRINUSE and silently binds alongside it. Forcing IPv4 wildcard
makes the conflict real, and Vite's default `strictPort: false`
falls through to the next free port.
* fix(website): restore docs page styling after markdown migration
Add a .docs-prose class that mirrors the styling the original
docs/*.tsx components hand-rolled (h1/h2/h3 sizes, paragraph/list
spacing, link colors, code blocks, callout-style blockquotes).
ReactMarkdown was emitting unstyled HTML because the previous
wrapper class only had inline-code rules — headings and code
blocks fell back to user-agent defaults.