chore: reformat codebase with oxfmt

Apply prettier-compatible formatting across the repo to match the
incoming oxfmt configuration. Mechanical reformat only — no logic
changes. Covers YAML quote normalization, package.json key sorting,
Markdown/TOML formatting, and minor TS whitespace tweaks.
This commit is contained in:
Mohamed Boudra
2026-04-23 21:44:48 +07:00
parent 9b25f8fc36
commit ce4b0d54c7
81 changed files with 1171 additions and 1009 deletions
+8 -8
View File
@@ -3,10 +3,10 @@ name: Deploy App
on:
push:
tags:
- 'v*'
- '!v*-beta.*'
- 'app-v*'
- '!app-v*-beta.*'
- "v*"
- "!v*-beta.*"
- "app-v*"
- "!app-v*-beta.*"
workflow_dispatch:
jobs:
@@ -18,10 +18,10 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
registry-url: 'https://npm.pkg.github.com'
scope: '@boudra'
node-version: "22"
cache: "npm"
registry-url: "https://npm.pkg.github.com"
scope: "@boudra"
- name: Install dependencies
run: npm install --workspace=@getpaseo/app --include-workspace-root
+4 -5
View File
@@ -4,8 +4,8 @@ on:
push:
branches: [main]
paths:
- 'packages/relay/**'
- '.github/workflows/deploy-relay.yml'
- "packages/relay/**"
- ".github/workflows/deploy-relay.yml"
workflow_dispatch:
jobs:
@@ -17,8 +17,8 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
node-version: "22"
cache: "npm"
- name: Install dependencies
run: npm install --workspace=@getpaseo/relay --include-workspace-root
@@ -30,4 +30,3 @@ jobs:
run: cd packages/relay && npx wrangler deploy
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
+8 -8
View File
@@ -4,12 +4,12 @@ on:
push:
branches: [main]
paths:
- 'CHANGELOG.md'
- 'packages/website/**'
- 'package.json'
- 'package-lock.json'
- 'patches/**'
- '.github/workflows/deploy-website.yml'
- "CHANGELOG.md"
- "packages/website/**"
- "package.json"
- "package-lock.json"
- "patches/**"
- ".github/workflows/deploy-website.yml"
release:
types: [published]
workflow_dispatch:
@@ -24,8 +24,8 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
node-version: "22"
cache: "npm"
- name: Install dependencies
run: npm install --workspace=@getpaseo/website --include-workspace-root
+22 -22
View File
@@ -3,21 +3,21 @@ name: Desktop Release
on:
push:
tags:
- 'v*'
- 'desktop-v*'
- 'desktop-macos-v*'
- 'desktop-linux-v*'
- 'desktop-windows-v*'
- "v*"
- "desktop-v*"
- "desktop-macos-v*"
- "desktop-linux-v*"
- "desktop-windows-v*"
workflow_dispatch:
inputs:
tag:
description: 'Existing tag to build (e.g. v0.1.0)'
description: "Existing tag to build (e.g. v0.1.0)"
required: true
type: string
platform:
description: 'Optional desktop platform to build.'
description: "Optional desktop platform to build."
required: false
default: 'all'
default: "all"
type: choice
options:
- all
@@ -31,8 +31,8 @@ concurrency:
env:
SOURCE_TAG: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag || github.ref_name }}
DESKTOP_WORKSPACE: '@getpaseo/desktop'
DESKTOP_PACKAGE_PATH: 'packages/desktop'
DESKTOP_WORKSPACE: "@getpaseo/desktop"
DESKTOP_PACKAGE_PATH: "packages/desktop"
jobs:
create-release:
@@ -100,11 +100,11 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
node-version: "22"
cache: "npm"
cache-dependency-path: package-lock.json
registry-url: 'https://npm.pkg.github.com'
scope: '@boudra'
registry-url: "https://npm.pkg.github.com"
scope: "@boudra"
- name: Install JS dependencies
run: npm ci
@@ -278,11 +278,11 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
node-version: "22"
cache: "npm"
cache-dependency-path: package-lock.json
registry-url: 'https://npm.pkg.github.com'
scope: '@boudra'
registry-url: "https://npm.pkg.github.com"
scope: "@boudra"
- name: Install JS dependencies
run: npm ci
@@ -346,11 +346,11 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
node-version: "22"
cache: "npm"
cache-dependency-path: package-lock.json
registry-url: 'https://npm.pkg.github.com'
scope: '@boudra'
registry-url: "https://npm.pkg.github.com"
scope: "@boudra"
- name: Install JS dependencies
run: npm ci
+6 -6
View File
@@ -4,12 +4,12 @@ on:
push:
branches: [main]
paths:
- 'package.json'
- 'package-lock.json'
- "package.json"
- "package-lock.json"
pull_request:
paths:
- 'package.json'
- 'package-lock.json'
- "package.json"
- "package-lock.json"
permissions:
contents: write
@@ -25,8 +25,8 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
node-version: "22"
cache: "npm"
- uses: cachix/install-nix-action@v31
with:
+18 -18
View File
@@ -4,27 +4,27 @@ on:
push:
branches: [main]
paths:
- 'nix/**'
- 'flake.nix'
- 'flake.lock'
- 'package.json'
- 'package-lock.json'
- 'packages/highlight/**'
- 'packages/server/**'
- 'packages/relay/**'
- 'packages/cli/**'
- "nix/**"
- "flake.nix"
- "flake.lock"
- "package.json"
- "package-lock.json"
- "packages/highlight/**"
- "packages/server/**"
- "packages/relay/**"
- "packages/cli/**"
pull_request:
branches: [main]
paths:
- 'nix/**'
- 'flake.nix'
- 'flake.lock'
- 'package.json'
- 'package-lock.json'
- 'packages/highlight/**'
- 'packages/server/**'
- 'packages/relay/**'
- 'packages/cli/**'
- "nix/**"
- "flake.nix"
- "flake.lock"
- "package.json"
- "package-lock.json"
- "packages/highlight/**"
- "packages/server/**"
- "packages/relay/**"
- "packages/cli/**"
permissions:
contents: read
+10 -10
View File
@@ -4,17 +4,17 @@ on:
push:
branches: [main]
paths:
- 'packages/server/**'
- 'package.json'
- 'package-lock.json'
- '.github/workflows/server-ci.yml'
- "packages/server/**"
- "package.json"
- "package-lock.json"
- ".github/workflows/server-ci.yml"
pull_request:
branches: [main]
paths:
- 'packages/server/**'
- 'package.json'
- 'package-lock.json'
- '.github/workflows/server-ci.yml'
- "packages/server/**"
- "package.json"
- "package-lock.json"
- ".github/workflows/server-ci.yml"
jobs:
test:
@@ -27,8 +27,8 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
node-version: "20"
cache: "npm"
- name: Fetch origin/main (worktree tests)
run: git fetch --no-tags origin main:refs/remotes/origin/main
+135
View File
@@ -3,12 +3,15 @@
## 0.1.62 - 2026-04-23
### Added
- Sidebar warning when your app and daemon versions drift apart, with a shortcut to settings.
### Improved
- Workspaces appear in the sidebar immediately on startup instead of waiting for git registration.
### Fixed
- Pull request status resolves correctly for PRs opened from forks.
- Installing the paseo CLI from the macOS desktop app now works in packaged builds.
- Agents launched from the desktop app no longer inherit Electron-only environment variables.
@@ -16,10 +19,12 @@
## 0.1.61 - 2026-04-23
### Added
- `additionalModels` option in provider config lets you add or relabel models without replacing the full list — entries merge with runtime-discovered models (ACP) or your static `models` list. See the [Providers docs](https://paseo.sh/docs/providers).
- New [Providers docs page](https://paseo.sh/docs/providers) covering first-class providers and every custom provider config pattern in one place.
### Improved
- Pi loads your installed extensions on startup so their models show up in the model picker.
- Resizing the explorer sidebar no longer rerenders the rest of the workspace.
- Images in assistant messages (both file paths and inline data URLs) persist as local attachments and open in the file pane.
@@ -27,6 +32,7 @@
## 0.1.60 - 2026-04-22
### Added
- Scripts and services per worktree — define named commands in `paseo.json`, and long-running services get supervised with their own ports and nice proxy URLs like `http://web.my-app.localhost:6767`. See the [worktrees guide](https://paseo.sh/docs/worktrees).
- Launch scripts and services for a worktree directly from the workspace header.
- New Setup tab in every workspace showing setup, teardown, and script progress live.
@@ -41,6 +47,7 @@
- New-workspace picker ranks branches by recency with fast search.
### Improved
- Workspace and tab switching are dramatically faster on desktop and mobile — you can keep many workspaces open in parallel without lag.
- Agent streams render more smoothly during heavy tool output.
- App startup routes through a stable connection and lands on the right screen without flicker.
@@ -55,6 +62,7 @@
- GitHub branch and PR picker loads faster — queries are deferred until the picker opens.
### Fixed
- Composer textarea shrinks back down after sending on web.
- New workspace drafts clear after submit instead of sticking around.
- Replacing a running agent cleans up the previous one without leaving it behind.
@@ -76,18 +84,21 @@
## 0.1.59 - 2026-04-16
### Added
- Opus 4.7 in the Claude model picker, with a 1M-context variant.
- Extra High reasoning effort for Opus 4.7, between High and Max.
## 0.1.58 - 2026-04-16
### Added
- Markdown files render as formatted markdown in the file pane. ([#427](https://github.com/getpaseo/paseo/pull/427) by [@aaronflorey](https://github.com/aaronflorey))
- Cmd+L (Ctrl+L on Windows/Linux) focuses the agent message input.
- Provider models refresh on a freshness TTL; Settings shows last-updated time and any fetch errors. ([#426](https://github.com/getpaseo/paseo/pull/426))
- `disallowedTools` option in provider config to block specific tools from an agent.
### Improved
- Windows: agents launch reliably from npm `.cmd` shims, paths with spaces, and JSON config args — fixes `spawn EINVAL` startup errors. ([#454](https://github.com/getpaseo/paseo/pull/454))
- OpenCode permission prompts include the requesting tool's context. ([#398](https://github.com/getpaseo/paseo/pull/398) by [@aaronflorey](https://github.com/aaronflorey))
- OpenCode todo and compaction events render in the timeline. ([#429](https://github.com/getpaseo/paseo/pull/429) by [@aaronflorey](https://github.com/aaronflorey))
@@ -97,6 +108,7 @@
- Native scrollbars match the active theme across all web views. ([#399](https://github.com/getpaseo/paseo/pull/399) by [@ethersh](https://github.com/ethersh))
### Fixed
- Code file previews can be selected and copied on iOS. ([#447](https://github.com/getpaseo/paseo/pull/447) by [@muzhi1991](https://github.com/muzhi1991))
- File preview no longer shows stale content when reopening the same file. ([#411](https://github.com/getpaseo/paseo/pull/411) by [@muzhi1991](https://github.com/muzhi1991))
- File explorer reinitialises when the client reconnects after a page refresh. ([#442](https://github.com/getpaseo/paseo/pull/442) by [@1996fanrui](https://github.com/1996fanrui))
@@ -110,12 +122,14 @@
## 0.1.56 - 2026-04-14
### Fixed
- Projects with empty git repositories (no commits yet) no longer crash the app on startup.
- A single problematic project can no longer prevent the rest of your workspaces from loading.
## 0.1.55 - 2026-04-14
### Added
- Provider profiles — define custom providers in your Paseo config that appear alongside built-ins. Override a built-in's binary, env, or models, or create entirely new providers. See the [configuration guide](https://github.com/getpaseo/paseo/blob/main/docs/CUSTOM-PROVIDERS.md).
- ACP agent support — add any ACP-compatible agent to Paseo with `extends: "acp"` in your provider config. No code changes needed.
- Choose provider and model when creating scheduled agents.
@@ -123,12 +137,14 @@
- Cmd+, (Ctrl+, on Windows/Linux) opens settings.
### Improved
- Git operations are dramatically faster — workspace status, PR checks, and branch data all use a shared cached snapshot service instead of shelling out to git on every request. Running 20+ workspaces simultaneously is now smooth.
- Windows support — the daemon and CLI run natively on Windows with proper shell quoting, executable resolution, and path handling.
- iPad and tablet layouts work correctly across all screen sizes.
- IME composition (Chinese, Japanese, Korean input) no longer submits prematurely when pressing Enter.
### Fixed
- Creating a worktree no longer briefly flashes it as a standalone project before placing it under the correct repository.
- Worktree creation spinner stays visible throughout the process instead of disappearing on mouse-out.
- Workspace navigation updates correctly when switching between workspaces in the same project.
@@ -138,13 +154,16 @@
## 0.1.54 - 2026-04-12
### Added
- Inline image previews in agent messages — screenshots and images generated by agents render directly in the conversation instead of showing as raw markdown links.
### Improved
- Paseo tools are no longer injected into agents by default — opt in from Settings when you need agent-to-agent orchestration.
- Agent provider and mode are now resolved server-side, so CLI commands like `paseo run` use consistent defaults without client-side lookups.
### Fixed
- Shift+Enter now correctly inserts a newline in agent terminal input instead of submitting.
- Windows: MCP configuration is no longer mangled when spawning Claude agents.
- Branch ahead/behind count no longer errors for branches with no remote tracking branch.
@@ -152,6 +171,7 @@
## 0.1.53 - 2026-04-12
### Added
- Agents get Paseo tools automatically — every new agent gets access to terminals, schedules, worktrees, and other agents through MCP. Toggle it off in Settings under "Inject Paseo tools".
- Git pull — pull remote changes directly from the workspace header. Promoted to the primary action when your branch is behind origin.
- Child agent notifications — parent agents are automatically notified when a child agent finishes, errors, or needs permission approval.
@@ -160,6 +180,7 @@
- Keyboard shortcut to cycle themes.
### Improved
- Unavailable git actions now explain why in a toast instead of being silently greyed out.
- Streaming markdown on mobile renders significantly faster.
- Sidebar, branch switcher, and agent panel no longer re-render unnecessarily — noticeable on large workspaces.
@@ -167,6 +188,7 @@
- Relay and pairing URLs are stripped from daemon logs.
### Fixed
- Closed agent tabs no longer reappear after reconnecting.
- Desktop notification badge counts match across all workspaces.
- Host switcher status syncs correctly when switching between hosts.
@@ -174,11 +196,13 @@
## 0.1.52 - 2026-04-10
### Added
- Theme selector — choose from six themes including Midnight, Claude, and Ghostty dark variants.
- Branch switching — switch git branches directly from the workspace header, with automatic stash and restore for uncommitted changes.
- Auto-download updates — desktop updates download silently in the background so they're ready to install when you are.
### Fixed
- Layout now responds correctly when resizing the window or rotating a tablet — previously the app could get stuck in mobile layout on a large screen.
- Terminal no longer causes massive memory spikes from snapshot thrashing during heavy output.
- Typing in the terminal works reliably — special keys, Ctrl combos, and paste are handled natively by the terminal emulator.
@@ -191,11 +215,13 @@
## 0.1.51 - 2026-04-09
### Added
- Image attachments for OpenCode — attach screenshots and images to OpenCode agent prompts.
- WebStorm — added to the "Open in editor" list alongside Cursor, VS Code, and Zed.
- Send behavior setting — choose whether pressing Enter while an agent is running interrupts immediately or queues your message.
### Fixed
- Model selector no longer crashes on iPad.
- Pairing now uses the correct hostname, fixing connection failures on some network setups.
- OpenCode agents show the correct terminal state and refresh models reliably.
@@ -207,6 +233,7 @@
## 0.1.50 - 2026-04-07
### Added
- Context window meter — see how much of the context window your agent has used, with color thresholds at 70% and 90%. Works with Claude Code, Codex, and OpenCode.
- Open in editor — jump from any workspace straight into Cursor, VS Code, Zed, or your file manager. Paseo remembers your choice.
- Side-by-side diffs — toggle between unified and split-column diff views, with a whitespace visibility option.
@@ -215,6 +242,7 @@
- Background git fetch — ahead/behind counts in the Changes pane stay up to date automatically.
### Improved
- Workspaces load instantly on connect instead of waiting for a full sync.
- File explorer and diff pane remember which folders are expanded when you switch tabs.
- Closing a workspace tab is now instant.
@@ -222,6 +250,7 @@
- Reload agent moved away from the close button to prevent accidental taps.
### Fixed
- Voice mode no longer drifts into false speech detection during long sessions.
- Garbled overlapping text on plan cards.
- Changes pane could show stale diffs when working with git worktrees.
@@ -234,6 +263,7 @@
## 0.1.49 - 2026-04-07
### Fixed
- Models and providers now load reliably on first connect instead of requiring a manual refresh.
- Model picker only shows models from the agent's own provider, not every provider on the server.
- Model lists stay consistent regardless of which screen you open first.
@@ -241,17 +271,20 @@
## 0.1.48 - 2026-04-05
### Added
- Provider diagnostics — tap a provider in Settings to see binary path, version, model count, and status at a glance. Helps troubleshoot why an agent type isn't available.
- Provider snapshot system — daemon now pushes real-time provider availability and model lists to the app, replacing the old poll-based approach. Models and modes update live as providers come online or go offline.
- Codex question handling — Codex agents can now ask the user questions mid-session (e.g. "which file?") and receive answers inline, matching the Claude Code question flow.
- Reload tab action — right-click a workspace tab to reload its agent list without restarting the app.
### Improved
- Model selector redesigned — grouped by provider with status badges, search, and better touch targets on mobile.
- Enter key now submits question card answers and confirms dictation, matching the expected keyboard flow.
- Removed noisy agent lifecycle toasts that fired on every state change.
### Fixed
- Desktop app now resolves the user's full login shell environment at startup, fixing tools like `codex`, `node`, `bun`, and `direnv` not being found when Paseo is launched from Finder or Dock. Terminals spawned by Paseo now inherit the same PATH and environment variables as a normal terminal session. Approach adapted from VS Code's battle-tested shell environment resolution.
- Input field on running agent screens now correctly receives keyboard focus.
- Mobile model selector alignment and sizing.
@@ -259,6 +292,7 @@
## 0.1.47 - 2026-04-05
### Fixed
- Voice TTS in Electron — sherpa now requests copied buffers and the voice MCP bridge sets `ELECTRON_RUN_AS_NODE`, preventing "external buffers not allowed" crashes.
- QR pairing in desktop — CLI JSON output parsing now tolerates Node deprecation warnings in stdout.
- STT segment race condition — segment ID and audio buffer are snapshotted before the async transcription call, so rapid commits no longer interleave.
@@ -267,6 +301,7 @@
## 0.1.46 - 2026-04-04
### Fixed
- Voice activation in packaged builds — Silero VAD model is now copied out of the Electron asar archive so native code can read it.
- App version sent in probe client hello so the daemon's version gate no longer hides Pi/Copilot from reconnected sessions.
- `worktreeRoot` schema made backward-compatible for old clients and daemons that don't send the field.
@@ -275,6 +310,7 @@
## 0.1.45 - 2026-04-04
### Added
- Pi (pi.dev) agent provider — connect Pi as a new ACP-based agent type with thinking levels and tool call support.
- Copilot agent provider re-enabled after ACP compatibility fixes.
- `paseo .` and `paseo <path>` open the desktop app with the given project, similar to `code .`.
@@ -287,11 +323,13 @@
- Setup hint and paseo.sh link on the mobile welcome screen so new App Store users know what to do next.
### Improved
- Desktop startup is faster — existing daemon connections are raced against bootstrap so the app is usable sooner.
- Settings sections reordered for better grouping (integrations and daemon together).
- Sidebar projects and workspaces now persist across sessions, with a context menu to remove projects.
### Fixed
- Sidebar crash when switching iOS theme (Unistyles/Reanimated interaction).
- Silero VAD crash caused by external buffer mode in CircularBuffer.
- Bulk close now correctly archives stored agents instead of leaving orphans.
@@ -308,6 +346,7 @@
## 0.1.44 - 2026-04-03
### Fixed
- Desktop app now stops the daemon cleanly before auto-update restarts.
- Disabled claude-acp and copilot providers from the agent registry.
- Keyboard focus scope resolution now checks multiple candidates for broader compatibility.
@@ -317,16 +356,19 @@
## 0.1.43 - 2026-04-02
### Added
- Copilot agent support via ACP base provider — connect GitHub Copilot as a new agent type.
- Searchable model favorites — quickly find and pin preferred models.
- Slash command support for OpenCode agents.
### Improved
- Refined model selector UX with better mobile sheet behavior.
- Workspace status now uses amber alert styling for "needs input" state.
- Themed scrollbar on message input for consistent styling.
### Fixed
- Ctrl+C/V copy and paste now works correctly in the terminal on Windows and Linux.
- Shell arguments with spaces are now properly quoted on Windows.
- Claude models with 1M context support are now correctly reported.
@@ -334,11 +376,13 @@
## 0.1.42 - 2026-04-01
### Fixed
- Fixed Claude Code failing to launch on Windows when installed to a path with spaces (e.g. `C:\Program Files\...`).
## 0.1.41 - 2026-04-01
### Fixed
- Fixed agent spawning on Windows — all providers (Claude, Codex, OpenCode) now use shell mode so npm shims and `.cmd` wrappers resolve correctly.
- Fixed terminal creation on Windows defaulting to a Unix shell instead of `cmd.exe`.
- Fixed path handling across the app to support Windows drive-letter paths (`C:\...`) and UNC paths (`\\...`).
@@ -350,18 +394,22 @@
- Removed the 40-item cap on activity timeline output so long agent sessions display their full history.
### Improved
- Improved light mode theming with dedicated workspace background, scrollbar handle colors, and lighter shadows.
- Window controls overlay on Windows/Linux reduced from 48px to 29px height for a more compact titlebar.
## 0.1.40 - 2026-04-01
### Added
- Workspace tabs can now be closed in batches.
### Improved
- Provider model lists are now cached per server and provider, reducing redundant model lookups in the UI.
### Fixed
- OpenCode reasoning content no longer appears duplicated as assistant text.
- Daemon no longer crashes when a Codex binary is missing or fails to spawn.
- Archive tab now correctly reconciles agent visibility after archiving.
@@ -372,61 +420,73 @@
## 0.1.39 - 2026-03-30
### Added
- **Terminal management from the CLI** — new `paseo terminal` command group lets you list, create, and interact with workspace terminals without leaving your terminal.
- **Material file icons in the explorer** — the file explorer tree now shows language-specific icons (TypeScript, JSON, Markdown, etc.) so you can spot files at a glance.
### Fixed
- Fixed iOS sidebar scroll flicker caused by redundant overflow clipping.
- Centralized window controls padding into a shared hook, eliminating layout inconsistencies across platforms.
## 0.1.38 - 2026-03-30
### Fixed
- Fixed daemon startup race where the app could time out connecting on first launch because the PID file advertised a listen address before the server was ready.
- Fixed daemon log rotation losing startup traces — trace-level WebSocket logs no longer include full message payloads.
## 0.1.37 - 2026-03-29
### Added
- Custom window controls on Windows and Linux — the native titlebar is replaced with overlay controls that match the app's design.
- Desktop file logging with electron-log for easier debugging of daemon and app issues.
### Fixed
- Fixed broken PATH propagation and Claude binary resolution on Windows.
- Dictation errors now show a visible toast instead of failing silently.
## 0.1.36 - 2026-03-27
### Fixed
- Fixed Windows drive-letter path handling across the codebase.
- Fixed stale Nix hash with automatic lockfile-change detection.
### Added
- Added metrics collection and terminal performance tests.
## 0.1.35 - 2026-03-26
### Improved
- Faster app startup by redirecting to the welcome screen immediately and showing host connection status inline.
- Codex file deletions now display correctly as removed lines in diffs.
- OpenCode questions are now surfaced in the permission UI.
### Fixed
- Fixed queued prompt dispatch after idle transition.
- Replaced bash-only `mapfile` with a portable `while-read` loop in the chat script.
### Added
- Added support for Nix and NixOS installation.
## 0.1.34 - 2026-03-25
### Added
- Added `paseo archive` as a top-level alias for `paseo agent archive`.
- Added the `PASEO_AGENT_ID` environment variable for Claude and Codex agents.
- Added a redesigned command autocomplete with a detail card and dropdown styling.
- Linked Android download surfaces to the Google Play Store.
### Improved
- Autonomous turns now complete gracefully on interrupt instead of being canceled.
- Thinking/model selection now always resolves to a real option instead of showing a generic Default choice.
- Restored per-provider form preferences and removed the Auto model fallback.
@@ -435,6 +495,7 @@
- Improved chat transcript readability.
### Fixed
- Fixed `paseo send --no-wait` not taking effect.
- Fixed stale abort results contaminating replacement turns after an interrupt.
- Fixed Claude interrupt handling and autonomous wake reliability.
@@ -451,6 +512,7 @@
## 0.1.33 - 2026-03-23
### Fixed
- Fixed the desktop app failing to reopen after closing on macOS — the daemon and agent processes were registering with Launch Services as instances of the main app, blocking subsequent launches.
- Fixed dictation not working in the packaged desktop app — the microphone entitlement was missing from the hardened runtime configuration.
- Fixed leaked Claude Code child processes when agents were closed — the SDK query stream was not being properly shut down.
@@ -459,6 +521,7 @@
## 0.1.32 - 2026-03-23
### Added
- Fully rebindable keyboard shortcuts with chord support — all shortcuts are now declarative with proper Cmd (Mac) vs Ctrl (Windows/Linux) separation.
- Migrated the desktop app from Tauri to Electron, with macOS notarization, code signing, and Linux Wayland support.
- Added line numbers and word-wrap toggle to file previews.
@@ -468,6 +531,7 @@
- Added status bar tooltips for project and agent status.
### Improved
- Redesigned the mobile tab switcher as a compact header row with quick access to new agents and terminals.
- Streamlined workspace creation — worktrees are now created inline with a single action instead of a multi-step flow.
- Agent history now streams from disk on reconnect, so you see past messages immediately instead of a blank screen.
@@ -482,6 +546,7 @@
- Better error messages from the daemon — RPC errors now include the actual underlying details.
### Fixed
- Fixed user messages appearing as assistant output in the timeline when messages contained structured content blocks.
- Fixed archived workspace routing so navigating to an archived session no longer breaks the app.
- Fixed Linux AppImage failing to launch on Wayland-only desktops.
@@ -490,16 +555,19 @@
## 0.1.30 - 2026-03-19
### Added
- Added terminal tabs, split pane controls, and drop previews for workspace layouts.
- Added a combined model selector and agent mode visuals across key UI surfaces.
- Added Open Graph metadata improvements for richer website sharing previews.
### Improved
- Improved workspace navigation with better active-workspace tracking and keyboard-driven pane interactions.
- Improved terminal scrollbar behavior, pane focus handling, and status bar/message input spacing.
- Improved project picker path display and general workspace UI polish.
### Fixed
- Fixed agent startup reliability by tightening PATH resolution and surfacing missing provider binaries in status.
- Fixed workspace route syncing, drag hit areas, and git diff panel header styling regressions.
- Fixed website mobile horizontal scrolling and ensured the workspace audio module builds during EAS installs.
@@ -507,30 +575,36 @@
## 0.1.28 - 2026-03-15
### Added
- Added OpenCode build and plan modes.
- Added website landing pages for Claude Code, Codex, and OpenCode.
### Improved
- Improved the git action menu for more reliable repository actions.
- Improved the mobile settings screen, workspace header actions, and welcome screen presentation.
- Updated the website hero copy and added a sponsor callout section.
### Fixed
- Fixed assistant file links so they open the correct workspace files from chat.
## 0.1.27 - 2026-03-13
### Added
- Added voice runtime with new audio engine architecture for voice interactions.
- Added Grep tool support in Claude tool-call mapping.
- Added ability to open workspace files directly from agent chat messages.
- Added desktop notifications via a custom native bridge.
### Improved
- Improved image picker, markdown rendering, and UI interactions.
- Improved shell environment detection using shell-env.
### Fixed
- Fixed platform-specific markdown link rendering.
- Fixed Linux AppImage CLI resource paths.
- Fixed Codex replacement stream being killed by stale turn notifications.
@@ -538,15 +612,18 @@
## 0.1.26 - 2026-03-12
### Added
- Added single-instance desktop behavior, Android APK download access, and refreshed splash screen styling.
- Added bundled Codex and OpenCode binaries in the server so setup no longer depends on global installs.
- Added Windows support with improved cross-platform shell execution.
### Improved
- Improved desktop runtime behavior on Windows by suppressing console windows and defaulting app data to `~/.paseo`.
- Added a Discord link to the website navigation.
### Fixed
- Fixed desktop Claude agent startup from the managed runtime and rotated logs correctly on restart.
- Fixed the home route to hide browser chrome when appropriate.
- Fixed Expo Metro compatibility by updating the `exclusionList` import.
@@ -556,61 +633,79 @@
## 0.1.25 - 2026-03-11
### Fixed
- Fixed desktop app failing to start the built-in daemon on fresh macOS installs. The DMG was not notarized and code-signing stripped entitlements from the bundled Node runtime, causing Gatekeeper to block execution.
- Fixed Linux AppImage build by restoring the AppImage bundle format and stripping CUDA dependencies from onnxruntime.
## 0.1.24 - 2026-03-10
### Improved
- Improved command center keyboard navigation and new tab shortcut.
- Simplified desktop release pipeline for faster and more reliable builds.
## 0.1.21 - 2026-03-10
### Improved
- Improved desktop release reliability by fixing the Windows managed-runtime build path during GitHub Actions releases.
### Fixed
- Fixed a desktop release CI failure caused by a Unix-only server build script on Windows runners.
- Fixed server CI to build the relay dependency before running tests, restoring relay E2EE test coverage on clean runners.
- Fixed a Claude redesign test that depended on the local Claude CLI being installed.
## 0.1.20 - 2026-03-10
### Added
- Added workspace sidebar git actions with quick diff stats and archive controls.
- Added refreshed website downloads and homepage presentation for desktop installs.
### Improved
- Desktop release packaging now rebuilds and validates the bundled managed runtime during CI, improving installer reliability for macOS users.
- Improved desktop and web stream rendering, settings polish, and React 19.1.4 compatibility.
### Fixed
- Fixed Claude interrupt/restart regressions and strengthened managed-daemon smoke coverage for desktop releases.
## 0.1.19 - 2026-03-09
### Added
- Added a draft GitHub release flow so maintainers can upload and review desktop and Android release assets before publishing the final release.
## 0.1.18 - 2026-03-06
### Added
- Added a desktop `Mod+W` shortcut to close the current tab.
### Improved
- New and newly selected terminals now take focus automatically so you can type immediately.
- Kept newly created workspaces and projects in a more stable order in the sidebar.
- Improved project naming for GitHub remotes and expanded project icon discovery to Phoenix `priv/static` assets.
- Updated the website desktop download link to use the universal macOS DMG.
### Fixed
- Restored automatic agent metadata generation for Claude runs.
## 0.1.17 - 2026-03-06
### Added
- New workspace-first navigation model with workspace tabs, file tabs, and sortable tab groups.
- Keyboard shortcuts for workspace and tab navigation, with shortcut badges in the sidebar.
- Workspace-level archive actions with improved worktree archiving flow and context menu support.
- In-chat task notifications rendered as synthetic tool-call events for clearer status tracking.
### Improved
- Desktop builds now ship as a universal macOS binary (Apple Silicon + Intel).
- More reliable workspace routing and tab identity handling across refreshes and deep links.
- Better sidebar drag-and-drop behavior with explicit drag handles and nested list interactions.
@@ -618,6 +713,7 @@
- Stronger provider error surfacing and updated Claude model/runtime handling.
### Fixed
- Fixed orphan workspace runs caused by non-canonical tab routes.
- Fixed mobile terminal tab remount/routing restore issues.
- Fixed agent metadata title/branch update reliability.
@@ -625,7 +721,9 @@
- Fixed reversed edge-wheel scroll behavior in chat/tool stream views.
## 0.1.16 - 2026-02-22
### Added
- Update the Paseo desktop app and local daemon directly from Settings.
- Microphone and notification permission controls in Settings.
- Thinking/reasoning mode — agents can use extended thinking when the provider supports it.
@@ -633,6 +731,7 @@
- `paseo wait` now shows a snapshot of recent agent activity while you wait.
### Improved
- Smoother streaming with less UI flicker and scroll jumping during long agent runs.
- Faster agent sidebar list rendering.
- Archiving an agent now stops it first instead of archiving a half-running session.
@@ -640,16 +739,20 @@
- More reliable relay connections.
### Fixed
- Fixed Claude background tasks desyncing the chat.
- Fixed duplicate user messages appearing in the timeline.
- Fixed a startup crash caused by an OpenCode SDK update.
- Fixed spurious "needs attention" notifications from background agent activity.
## 0.1.15 - 2026-02-19
### Added
- Added a public changelog page on the website so users can browse release notes.
### Improved
- Redesigned the website get-started experience into a clearer two-step flow.
- Simplified website GitHub navigation and changelog headings.
- Improved app draft/new-agent UX with clearer working directory placeholder and empty-state messaging.
@@ -657,11 +760,14 @@
- Hid empty filter groups in the left sidebar.
### Fixed
- Fixed archived-agent navigation by redirecting archived agent routes to draft.
- Fixed duplicate `/rewind` user-message behavior.
## 0.1.14 - 2026-02-19
### Added
- Added Claude `/rewind` command support.
- Added slash command access in the draft agent composer.
- Added `@` workspace file autocomplete in chat prompts.
@@ -670,6 +776,7 @@
- Added shared desktop/web overlay scroll handles, including file preview panes.
### Improved
- Improved worktree flow after shipping, including better merged PR detection.
- Improved draft workflow by enabling the explorer sidebar immediately after CWD selection.
- Improved new worktree-agent defaults by prefilling CWD to the main repository.
@@ -679,6 +786,7 @@
- Improved scrollbar visibility, drag interactions, tracking, and animation timing on web/desktop.
### Fixed
- Fixed worktree archive/setup lifecycle issues, including terminal cleanup and archive timing.
- Fixed worktree path collisions by hashing CWD for collision-safe worktree roots.
- Fixed terminal sizing when switching back to an agent session.
@@ -692,25 +800,32 @@
- Fixed daemon version badge visibility in settings when daemon version data is unavailable.
## 0.1.9 - 2026-02-17
### Improved
- Unified structured-output generation through a single shared schema-validation and retry pipeline.
- Reused provider availability checks for structured generation fallback selection.
- Added structured generation waterfall ordering for internal metadata and git text generation: Claude Haiku, then Codex, then OpenCode.
### Fixed
- Fixed CLI `run --output-schema` to use the shared structured-output path instead of ad-hoc JSON parsing.
- Fixed `run --output-schema` failures where providers returned empty `lastMessage` by recovering from timeline assistant output.
- Fixed internal commit message, pull request text, and agent metadata generation to follow one consistent structured pipeline.
## 0.1.8 - 2026-02-17
### Added
- Added a cross-platform confirm dialog flow for daemon restarts.
### Improved
- Simplified local speech bootstrap and daemon startup locking behavior.
- Updated website hero copy to emphasize local execution.
### Fixed
- Fixed stuck "send while running" recovery across app and server session handling.
- Fixed Claude session identity preservation when reloading existing agents.
- Fixed combobox option behavior and related interactions.
@@ -718,73 +833,93 @@
- Fixed web tool-detail wheel event routing at scroll edges.
## 0.1.7 - 2026-02-16
### Added
- Improved agent workspace flows with better directory suggestions.
- Added iOS TestFlight and Android app access request forms on the website.
### Improved
- Unified daemon startup behavior between dev and CLI paths for more predictable local runs.
- Improved website app download and update guidance.
### Fixed
- Prevented an initial desktop combobox `0,0` position flash.
- Fixed CLI version output issues.
- Hardened server runtime loading for local speech dependencies.
## 0.1.6 - 2026-02-16
### Notes
- No major visible product changes in this patch release.
## 0.1.5 - 2026-02-16
### Added
- Added terminal reattach support and better worktree terminal handling.
- Added global keyboard shortcut help in the app.
- Added sidebar host filtering and improved agent workflow controls.
### Improved
- Improved worktree setup visibility by streaming setup progress.
- Improved terminal streaming reliability and lifecycle handling.
- Preserved explorer tab state so context survives navigation better.
## 0.1.4 - 2026-02-14
### Added
- Added voice capability status reporting in the client.
- Added background local speech model downloads with runtime gating.
- Added adaptive dictation finish timing based on server-provided budgets.
- Added relay reconnect behavior with grace periods and branch suggestions.
### Improved
- Improved connection selection and agent hydration reliability.
- Improved timeline loading with cursor-based fetch behavior.
- Improved first-run experience by bootstrapping a default localhost connection.
- Improved inline code rendering by auto-linkifying URLs.
### Fixed
- Fixed Linux checkout diff watch behavior to avoid recursive watches.
- Fixed stale relay client timer behavior.
- Fixed unnecessary git diff header auto-scroll on collapse.
## 0.1.3 - 2026-02-12
### Added
- Added CLI onboarding command.
- Added CLI `--output-schema` support for structured agent output.
- Added CLI agent metadata update support for names and labels.
- Added provider availability detection with normalization of legacy default model IDs.
### Improved
- Improved file explorer refresh feedback and unresolved checkout fallback handling.
- Added better voice interrupt handling with a speech-start grace period.
- Improved CLI defaults to list all non-archived agents by default.
- Improved website UX with clearer install CTA and privacy policy access.
### Fixed
- Fixed dev runner entry issues and sherpa TTS initialization behavior.
## 0.1.2 - 2026-02-11
### Notes
- No major visible product changes in this patch release.
## 0.1.1 - 2026-02-11
### Added
- Initial `0.1.x` release line.
+3 -4
View File
@@ -18,7 +18,7 @@ This is an npm workspace monorepo:
## Documentation
| Doc | What's in it |
|---|---|
| ---------------------------------------------------- | --------------------------------------------------------------------------------- |
| [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | System design, package layering, WebSocket protocol, agent lifecycle, data flow |
| [docs/CODING_STANDARDS.md](docs/CODING_STANDARDS.md) | Type hygiene, error handling, state design, React patterns, file organization |
| [docs/TESTING.md](docs/TESTING.md) | TDD workflow, determinism, real dependencies over mocks, test organization |
@@ -69,7 +69,7 @@ The app runs on iOS, Android, web (browser), and web (Electron desktop). Code is
### The four gates
| Gate | Type | When to use |
|---|---|---|
| -------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------- |
| `isWeb` | constant | DOM APIs — `document`, `window`, `<div>`, `addEventListener`, `ResizeObserver`. This is the **exception**, not the default. |
| `isNative` | constant | Native-only APIs — Haptics, `StatusBar.currentHeight`, push tokens, camera/scanner, `expo-av`. |
| `getIsElectron()` | cached fn | Desktop wrapper features — file dialogs, titlebar drag region, daemon management, app updates, dock badges. |
@@ -78,7 +78,7 @@ The app runs on iOS, Android, web (browser), and web (Electron desktop). Code is
### Decision matrix
| I need to... | Use |
|---|---|
| -------------------------------------------------------------- | ------------------------------------------------------------------------- |
| Access DOM (`document`, `window`, `<div>`, `addEventListener`) | `if (isWeb)` |
| Use a native-only API (Haptics, push tokens, camera) | `if (isNative)` |
| Use an Electron bridge (file dialog, titlebar, updates) | `if (getIsElectron())` |
@@ -104,5 +104,4 @@ The app runs on iOS, Android, web (browser), and web (Electron desktop). Code is
## Debugging
Find the complete daemon logs and traces in the $PASEO_HOME/daemon.log
+2
View File
@@ -69,6 +69,7 @@ paseo
This shows a QR code in the terminal. Connect from any client. This path is useful for servers and remote machines.
For full setup and configuration, see:
- [Docs](https://paseo.sh/docs)
- [Configuration reference](https://paseo.sh/docs/configuration)
@@ -116,6 +117,7 @@ Then use them in any agent conversation:
## Development
Quick monorepo package map:
- `packages/server`: Paseo daemon (agent process orchestration, WebSocket API, MCP server)
- `packages/app`: Expo client (iOS, Android, web)
- `packages/cli`: `paseo` CLI for daemon and agent workflows
+2
View File
@@ -58,6 +58,7 @@ await rm(staticDir, { recursive: true, force: true });
```
Run with:
```bash
npx tsx packages/server/src/server/your-script.ts
```
@@ -107,6 +108,7 @@ const updated = await client.waitForAgentUpsert(agent.id, (s) => s.status === "i
The daemon hides non-legacy providers (anything other than claude, codex, opencode) from clients that don't send an `appVersion >= 0.1.45`. The `DaemonClient` sends no version by default, so custom providers like ACP-based ones will be invisible in snapshot responses.
Always pass `appVersion`:
```typescript
const client = new DaemonClient({
url: `ws://127.0.0.1:${port}/ws`,
+1 -1
View File
@@ -5,7 +5,7 @@
Controlled by `APP_VARIANT` in `packages/app/app.config.js` (vanilla Expo, no custom Gradle plugin):
| Variant | App name | Package ID |
|---|---|---|
| ------------- | ----------- | ---------------- |
| `production` | Paseo | `sh.paseo` |
| `development` | Paseo Debug | `sh.paseo.debug` |
+4 -2
View File
@@ -54,7 +54,7 @@ The heart of Paseo. A Node.js process that:
**Key modules:**
| Module | Responsibility |
|---|---|
| ------------------------- | ----------------------------------------------------------------------------- |
| `bootstrap.ts` | Daemon initialization: HTTP server, WS server, agent manager, storage, relay |
| `websocket-server.ts` | WebSocket connection management, hello/welcome handshake, binary multiplexing |
| `session.ts` | Per-client session state, timeline subscriptions, terminal operations |
@@ -132,6 +132,7 @@ Server → Client: WSWelcomeMessage { clientId, daemonVersion, sessionId, capab
**Binary multiplexing:**
Terminal I/O and agent streaming share the same connection via `BinaryMuxFrame`:
- Channel 0: control messages
- Channel 1: terminal data
- 1-byte channel ID + 1-byte flags + variable payload
@@ -154,12 +155,13 @@ initializing → idle → running → idle (or error → closed)
Each provider implements a common `AgentClient` interface:
| Provider | Wraps | Session format |
|---|---|---|
| -------- | ------------------- | -------------------------------------------------- |
| Claude | Anthropic Agent SDK | `~/.claude/projects/{cwd}/{session-id}.jsonl` |
| Codex | CodexAppServer | `~/.codex/sessions/{date}/rollout-{ts}-{id}.jsonl` |
| OpenCode | OpenCode CLI | Provider-managed |
All providers:
- Handle their own authentication (Paseo does not manage API keys)
- Support session resume via persistence handles
- Map tool calls to a normalized `ToolCallDetail` type
+18 -4
View File
@@ -40,7 +40,10 @@ No complex inline types in public function signatures.
function enqueueJob(input: { userId: string; priority: "low" | "normal" | "high" }) {}
// Good
interface EnqueueJobInput { userId: string; priority: "low" | "normal" | "high" }
interface EnqueueJobInput {
userId: string;
priority: "low" | "normal" | "high";
}
function enqueueJob(input: EnqueueJobInput) {}
```
@@ -53,7 +56,11 @@ If a function needs more than one argument, use a single object parameter.
function createToolCall(provider: string, toolName: string, payload: unknown) {}
// Good: object param
interface CreateToolCallInput { provider: string; toolName: string; payload: unknown }
interface CreateToolCallInput {
provider: string;
toolName: string;
payload: unknown;
}
function createToolCall(input: CreateToolCallInput) {}
```
@@ -78,7 +85,11 @@ Use discriminated unions instead of bags of booleans and optionals.
```typescript
// Bad
interface FetchState { isLoading: boolean; error?: Error; data?: Data }
interface FetchState {
isLoading: boolean;
error?: Error;
data?: Data;
}
// Good
type FetchState =
@@ -136,7 +147,10 @@ Avoid packing branching, lookup, and transformation into single dense expression
// Bad: nested ternaries + inline lookups
const billing = shouldUseLegacy(account)
? getLegacy(account)
: buildBilling(account, rates.find((r) => r.region === account.region));
: buildBilling(
account,
rates.find((r) => r.region === account.region),
);
// Good: named steps, then assemble
const rate = rates.find((r) => r.region === account.region);
+11 -15
View File
@@ -55,6 +55,7 @@ Use `extends` to create a new provider entry that inherits from a built-in provi
```
Required fields for custom providers:
- `extends` — which built-in provider to inherit from (or `"acp"`)
- `label` — display name in the UI
@@ -96,7 +97,7 @@ Required fields for custom providers:
### Available models
| Model | Tier |
|---|---|
| ------------- | ------------------- |
| `glm-5.1` | Advanced (flagship) |
| `glm-5-turbo` | Advanced |
| `glm-4.7` | Standard |
@@ -149,7 +150,7 @@ Required fields for custom providers:
### API endpoints
| Mode | Base URL |
|---|---|
| ------------------------------- | ----------------------------------------------------------- |
| Coding plan (subscription) | `https://coding-intl.dashscope.aliyuncs.com/apps/anthropic` |
| Pay-as-you-go (no subscription) | `https://dashscope-intl.aliyuncs.com/apps/anthropic` |
@@ -160,7 +161,7 @@ For pay-as-you-go, use `ANTHROPIC_API_KEY` with a standard Model Studio key (`sk
**Recommended for coding plan:**
| Model | Notes |
|---|---|
| ------------------ | --------------------------- |
| `qwen3.5-plus` | Vision capable, recommended |
| `qwen3-coder-next` | Optimized for coding |
| `kimi-k2.5` | Vision capable |
@@ -221,16 +222,12 @@ You can also combine profiles with model overrides to pin specific models per pr
"claude-fast": {
"extends": "claude",
"label": "Claude (Fast)",
"models": [
{ "id": "claude-sonnet-4-6", "label": "Sonnet 4.6", "isDefault": true }
]
"models": [{ "id": "claude-sonnet-4-6", "label": "Sonnet 4.6", "isDefault": true }]
},
"claude-smart": {
"extends": "claude",
"label": "Claude (Smart)",
"models": [
{ "id": "claude-opus-4-6", "label": "Opus 4.6", "isDefault": true }
]
"models": [{ "id": "claude-opus-4-6", "label": "Opus 4.6", "isDefault": true }]
}
}
}
@@ -338,6 +335,7 @@ Set `extends: "acp"` and provide a `command`:
```
Required fields for ACP providers:
- `extends: "acp"`
- `label`
- `command` — the command to spawn the agent process (must support ACP over stdio)
@@ -455,9 +453,7 @@ Example: relabel a discovered model without replacing the full list:
"extends": "acp",
"label": "My Agent",
"command": ["my-agent", "--acp"],
"additionalModels": [
{ "id": "provider/model-id", "label": "My Preferred Label" }
]
"additionalModels": [{ "id": "provider/model-id", "label": "My Preferred Label" }]
}
}
}
@@ -473,7 +469,7 @@ When an `additionalModels` entry has the same `id` as a discovered model, it upd
Every entry under `agents.providers` accepts these fields:
| Field | Type | Required | Description |
|---|---|---|---|
| ------------------ | ------------------------ | ----------------- | ------------------------------------------------------------------ |
| `extends` | `string` | Yes (custom only) | Built-in provider ID to inherit from, or `"acp"` |
| `label` | `string` | Yes (custom only) | Display name in the UI |
| `description` | `string` | No | Short description shown in the UI |
@@ -490,7 +486,7 @@ Every entry under `agents.providers` accepts these fields:
Each entry in the `models` array:
| Field | Type | Required | Description |
|---|---|---|---|
| ----------------- | ------------------ | -------- | ------------------------------------- |
| `id` | `string` | Yes | Model identifier sent to the provider |
| `label` | `string` | Yes | Display name in the UI |
| `description` | `string` | No | Short description |
@@ -500,7 +496,7 @@ Each entry in the `models` array:
### Thinking option
| Field | Type | Required | Description |
|---|---|---|---|
| ------------- | --------- | -------- | ----------------------------------- |
| `id` | `string` | Yes | Thinking option identifier |
| `label` | `string` | Yes | Display name |
| `description` | `string` | No | Short description |
+18 -18
View File
@@ -35,7 +35,7 @@ $PASEO_HOME/
Each agent is stored as a separate JSON file, grouped by project directory.
| Field | Type | Description |
|---|---|---|
| -------------------- | ---------------------------------------- | ---------------------------------------------------------------------- |
| `id` | `string` | UUID, primary key |
| `provider` | `string` | Agent provider (`"claude"`, `"codex"`, `"opencode"`, etc.) |
| `cwd` | `string` | Working directory the agent operates in |
@@ -60,7 +60,7 @@ Each agent is stored as a separate JSON file, grouped by project directory.
### Nested: SerializableConfig
| Field | Type | Description |
|---|---|---|
| ------------------ | -------------------------- | ---------------------------- |
| `title` | `string?` | Configured title |
| `modeId` | `string?` | Configured mode |
| `model` | `string?` | Configured model |
@@ -73,7 +73,7 @@ Each agent is stored as a separate JSON file, grouped by project directory.
### Nested: RuntimeInfo
| Field | Type | Description |
|---|---|---|
| ------------------ | -------------------------- | ------------------------------ |
| `provider` | `string` | Active provider |
| `sessionId` | `string?` | Active session ID |
| `model` | `string?` | Active model |
@@ -84,7 +84,7 @@ Each agent is stored as a separate JSON file, grouped by project directory.
### Nested: PersistenceHandle
| Field | Type | Description |
|---|---|---|
| -------------- | ---------------------- | --------------------------------------------------------------------- |
| `provider` | `string` | Provider that owns the session |
| `sessionId` | `string` | Session ID for resumption |
| `nativeHandle` | `any?` | Provider-specific handle (Codex thread ID, Claude resume token, etc.) |
@@ -95,7 +95,7 @@ Each agent is stored as a separate JSON file, grouped by project directory.
**Toggle:**
| Field | Type |
|---|---|
| ------------- | ---------- |
| `type` | `"toggle"` |
| `id` | `string` |
| `label` | `string` |
@@ -107,7 +107,7 @@ Each agent is stored as a separate JSON file, grouped by project directory.
**Select:**
| Field | Type |
|---|---|
| ------------- | --------------------- |
| `type` | `"select"` |
| `id` | `string` |
| `label` | `string` |
@@ -173,7 +173,7 @@ All fields are optional with sensible defaults.
One file per schedule. ID is 8 hex characters.
| Field | Type | Description |
|---|---|---|
| ----------- | ------------------------------------- | -------------------------------- |
| `id` | `string` | 8-char hex ID |
| `name` | `string?` | Human-readable name |
| `prompt` | `string` | The prompt to send |
@@ -202,7 +202,7 @@ One file per schedule. ID is 8 hex characters.
### Nested: ScheduleRun
| Field | Type | Description |
|---|---|---|
| -------------- | -------------------------------------- | ----------------------- |
| `id` | `string` | Run ID |
| `scheduledFor` | `string` (ISO 8601) | Intended execution time |
| `startedAt` | `string` (ISO 8601) | |
@@ -230,7 +230,7 @@ Single file containing all rooms and messages.
### ChatRoom
| Field | Type | Description |
|---|---|---|
| ----------- | ------------------- | ----------------------------------- |
| `id` | `string` (UUID) | |
| `name` | `string` | Unique room name (case-insensitive) |
| `purpose` | `string?` | Room description |
@@ -240,7 +240,7 @@ Single file containing all rooms and messages.
### ChatMessage
| Field | Type | Description |
|---|---|---|
| ------------------ | ------------------- | ----------------------------------- |
| `id` | `string` (UUID) | |
| `roomId` | `string` | FK to ChatRoom.id |
| `authorAgentId` | `string` | Agent ID of the author |
@@ -258,7 +258,7 @@ Single file containing all rooms and messages.
Single file containing an array of all loop records.
| Field | Type | Description |
|---|---|---|
| ----------------------- | --------------------------------------------------- | ------------------------------------------ |
| `id` | `string` | 8-char UUID prefix |
| `name` | `string?` | Human-readable name |
| `prompt` | `string` | Worker prompt |
@@ -291,7 +291,7 @@ Single file containing an array of all loop records.
### Nested: LoopIteration
| Field | Type | Description |
|---|---|---|
| ------------------- | --------------------------------------------------- | ------------------------ |
| `index` | `number` | 1-based iteration index |
| `workerAgentId` | `string?` | Agent ID of the worker |
| `workerStartedAt` | `string` (ISO 8601) | |
@@ -306,7 +306,7 @@ Single file containing an array of all loop records.
### Nested: LoopLogEntry
| Field | Type |
|---|---|
| ----------- | ---------------------------------------------------- |
| `seq` | `number` (monotonic) |
| `timestamp` | `string` (ISO 8601) |
| `iteration` | `number?` |
@@ -317,7 +317,7 @@ Single file containing an array of all loop records.
### Nested: LoopVerifyCheckResult
| Field | Type |
|---|---|
| ------------- | ------------------- |
| `command` | `string` |
| `exitCode` | `number` |
| `passed` | `boolean` |
@@ -329,7 +329,7 @@ Single file containing an array of all loop records.
### Nested: LoopVerifyPromptResult
| Field | Type |
|---|---|
| ----------------- | ------------------- |
| `passed` | `boolean` |
| `reason` | `string` |
| `verifierAgentId` | `string?` |
@@ -345,7 +345,7 @@ Single file containing an array of all loop records.
Array of project records.
| Field | Type | Description |
|---|---|---|
| ------------- | -------------------- | ------------------------------ |
| `projectId` | `string` | Primary key |
| `rootPath` | `string` | Filesystem root of the project |
| `kind` | `"git" \| "non_git"` | |
@@ -363,7 +363,7 @@ Array of project records.
Array of workspace records. A workspace is a specific working directory within a project.
| Field | Type | Description |
|---|---|---|
| ------------- | ----------------------------------------------- | ----------------------- |
| `workspaceId` | `string` | Primary key |
| `projectId` | `string` | FK to Project.projectId |
| `cwd` | `string` | Filesystem path |
@@ -418,7 +418,7 @@ Stores binary attachment blobs keyed by attachment ID.
### AttachmentMetadata
| Field | Type | Description |
|---|---|---|
| ------------- | --------- | ------------------------------ |
| `id` | `string` | Unique attachment ID |
| `mimeType` | `string` | MIME type |
| `storageType` | `string` | Storage backend identifier |
+6 -1
View File
@@ -31,6 +31,7 @@ PASEO_HOME=~/.paseo-blue npm run dev
### Default ports
In the main checkout:
- Daemon: `localhost:6767`
- Expo app: `localhost:8081`
@@ -64,7 +65,7 @@ Pass either a DB directory or a `paseo.sqlite` file to `--db`. The script opens
Every `scripts` entry with `"type": "service"` receives these environment variables:
| Variable | Value |
|---|---|
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `PASEO_SERVICE_<NAME>_URL` | Proxied daemon URL for a declared peer service. Prefer this for peer discovery; it survives peer restarts. |
| `PASEO_SERVICE_<NAME>_PORT` | Raw ephemeral port for a declared peer service. Use only as a bypass escape hatch; it can go stale if that peer restarts. |
| `PASEO_URL` | Self alias for `PASEO_SERVICE_<SELF>_URL`. |
@@ -135,11 +136,13 @@ $PASEO_HOME/agents/{cwd-with-dashes}/{agent-id}.json
```
Find an agent by ID:
```bash
find $PASEO_HOME/agents -name "{agent-id}.json"
```
Find by content:
```bash
rg -l "some title text" $PASEO_HOME/agents/
```
@@ -149,11 +152,13 @@ rg -l "some title text" $PASEO_HOME/agents/
Get the session ID from the agent JSON (`persistence.sessionId`), then:
**Claude:**
```
~/.claude/projects/{cwd-with-dashes}/{session-id}.jsonl
```
**Codex:**
```
~/.codex/sessions/{YYYY}/{MM}/{DD}/rollout-{timestamp}-{session-id}.jsonl
```
+2 -2
View File
@@ -35,8 +35,8 @@ cat node_modules/material-icon-theme/icons/ICON_NAME.svg
```
3. Add two things to `material-file-icons.ts`:
- The SVG string in `SVG_ICONS`:
```ts
"icon_name": `<svg ...>...</svg>`,
```
@@ -53,7 +53,7 @@ cat node_modules/material-icon-theme/icons/ICON_NAME.svg
53 unique icons covering these extensions:
| Extension(s) | Icon |
|---|---|
| ------------------------------------------ | ----------- |
| `ts` | typescript |
| `tsx` | react_ts |
| `js` | javascript |
+2 -2
View File
@@ -223,7 +223,7 @@ const styles = StyleSheet.create((theme) => ({
},
}));
<Animated.View style={[styles.sidebar, animatedStyle]} />
<Animated.View style={[styles.sidebar, animatedStyle]} />;
```
```tsx
@@ -244,7 +244,7 @@ const { theme } = useUnistyles();
<Animated.View
style={[staticStyles.sidebar, animatedStyle, { backgroundColor: theme.colors.surfaceSidebar }]}
/>
/>;
```
Regular `View` components can safely use Unistyles dynamic styles — the conflict is specific to `Animated.View`.
+2
View File
@@ -30,6 +30,7 @@ Each project opens as a workspace. For git projects, the default workspace is th
### Inside a workspace
A workspace is a flexible canvas:
- Launch multiple agents side by side in split panes
- Open terminals alongside agents
- Mix and match providers within the same workspace
@@ -39,6 +40,7 @@ A workspace is a flexible canvas:
Paseo is a client-server system. The daemon (Node.js) runs on your machine, manages agent processes, and streams output in real time over WebSocket. Clients connect to the daemon — locally or remotely.
This architecture means:
- The daemon can run on any machine: laptop, VM, remote server
- Multiple clients can connect simultaneously
- Agents keep running when you close the app
+9 -2
View File
@@ -264,8 +264,15 @@ If your agent does not speak ACP, implement the interfaces from `agent-sdk-types
interface AgentClient {
readonly provider: AgentProvider;
readonly capabilities: AgentCapabilityFlags;
createSession(config: AgentSessionConfig, launchContext?: AgentLaunchContext): Promise<AgentSession>;
resumeSession(handle: AgentPersistenceHandle, overrides?: Partial<AgentSessionConfig>, launchContext?: AgentLaunchContext): Promise<AgentSession>;
createSession(
config: AgentSessionConfig,
launchContext?: AgentLaunchContext,
): Promise<AgentSession>;
resumeSession(
handle: AgentPersistenceHandle,
overrides?: Partial<AgentSessionConfig>,
launchContext?: AgentLaunchContext,
): Promise<AgentSession>;
listModels(options?: ListModelsOptions): Promise<AgentModelDefinition[]>;
isAvailable(): Promise<boolean>;
// Optional:
+4 -1
View File
@@ -79,7 +79,9 @@ const realSender: EmailSender = { send: sendgrid.send };
function createTestEmailSender() {
const sent: Array<{ to: string; body: string }> = [];
return {
send: async (to: string, body: string) => { sent.push({ to, body }); },
send: async (to: string, body: string) => {
sent.push({ to, body });
},
sent,
};
}
@@ -115,6 +117,7 @@ The test output is the source of truth, not your reading of the code.
## Design for testability
If code isn't testable, refactor it. Signs:
- You want to reach for a mock
- You can't inject a dependency
- You need to test private internals
+21 -23
View File
@@ -19,7 +19,7 @@ The important detail: the automatic native path tracks `props.style`. It does no
Avoid this pattern when the style depends on the theme:
```tsx
<ScrollView contentContainerStyle={styles.container} />
<ScrollView contentContainerStyle={styles.container} />;
const styles = StyleSheet.create((theme) => ({
container: {
@@ -39,10 +39,8 @@ Preferred pattern: put themed backgrounds on a normal wrapper view, and keep `co
```tsx
<View style={styles.container}>
<ScrollView contentContainerStyle={styles.contentContainer}>
{children}
</ScrollView>
</View>
<ScrollView contentContainerStyle={styles.contentContainer}>{children}</ScrollView>
</View>;
const styles = StyleSheet.create((theme) => ({
container: {
@@ -66,10 +64,7 @@ import { StyleSheet, withUnistyles } from "react-native-unistyles";
const ThemedScrollView = withUnistyles(ScrollView);
<ThemedScrollView
style={styles.scrollView}
contentContainerStyle={styles.contentContainer}
/>
<ThemedScrollView style={styles.scrollView} contentContainerStyle={styles.contentContainer} />;
```
`withUnistyles` extracts dependency metadata from both `style` and `contentContainerStyle`, subscribes to the relevant theme/runtime changes, and re-renders only that wrapped component when needed. Its [auto-mapping behavior for `style` and `contentContainerStyle`](https://www.unistyl.es/v3/references/with-unistyles#auto-mapping-for-style-and-contentcontainerstyle-props) is the reason it fixes themed `ScrollView` content containers. Reach for it when wrapper-view layout would be awkward or when a third-party component needs theme-aware non-`style` props mapped through Unistyles.
@@ -80,11 +75,8 @@ The smallest escape hatch is to use `useUnistyles()` and pass an inline value th
const { theme } = useUnistyles();
<ScrollView
contentContainerStyle={[
styles.contentContainer,
{ backgroundColor: theme.colors.surface0 },
]}
/>
contentContainerStyle={[styles.contentContainer, { backgroundColor: theme.colors.surface0 }]}
/>;
```
Use this sparingly. It works because React re-renders the prop, but it gives up the main Unistyles native-update path for that value.
@@ -98,8 +90,14 @@ The sharp edge: Unistyles hashes styles by value. If `withUnistyles` receives a
Concrete regression we hit: `welcome-screen.tsx` had `const ThemedScrollView = withUnistyles(ScrollView)` with `style={{ flex: 1, backgroundColor: theme.colors.surface0 }}`. `agent-panel.tsx` had `root` and `container` styles with the exact same value. All three collided on class `unistyles_j2k2iilhfz`, so the browser stylesheet contained:
```css
.unistyles_j2k2iilhfz { flex: 1 1 0%; background-color: var(--colors-surface0); }
.unistyles_j2k2iilhfz > * { flex: 1 1 0%; background-color: var(--colors-surface0); }
.unistyles_j2k2iilhfz {
flex: 1 1 0%;
background-color: var(--colors-surface0);
}
.unistyles_j2k2iilhfz > * {
flex: 1 1 0%;
background-color: var(--colors-surface0);
}
```
The child-selector rule forced `flex:1` and `background-color: surface0` onto the Composer's outer `Animated.View` (a direct child of `container`), stretching it to fill remaining space and leaving a large empty gap between the composer UI and the bottom of the screen. It also painted a `surface0` band behind the scroll-to-bottom button. The bug only appeared in the browser — Electron skips `WelcomeScreen` after pairing, so the `> *` rule was never injected there.
@@ -113,8 +111,10 @@ Symptoms to watch for:
Quick confirmation in DevTools console:
```js
[...document.styleSheets].flatMap(s => [...(s.cssRules || [])])
.map(r => r.cssText).filter(t => t.includes("unistyles") && t.includes("> *"));
[...document.styleSheets]
.flatMap((s) => [...(s.cssRules || [])])
.map((r) => r.cssText)
.filter((t) => t.includes("unistyles") && t.includes("> *"));
```
Any match beyond benign `r-pointerEvents-* > *` rules from react-native-web is a leak.
@@ -130,9 +130,7 @@ We saw this in `AdaptiveModalSheet`: the body text and buttons were dark-theme-c
```tsx
const { theme } = useUnistyles();
<Text style={[styles.title, { color: theme.colors.foreground }]}>
{title}
</Text>
<Text style={[styles.title, { color: theme.colors.foreground }]}>{title}</Text>;
```
Keep layout and typography in `StyleSheet.create`; move only the stale theme-dependent value through React. If a larger subtree shows the same behavior, consider remounting the sheet on theme changes or moving the themed paint onto a wrapper that is mounted with the visible content.
@@ -170,7 +168,7 @@ Use `useUnistyles()` inside the component instead:
```tsx
const { theme } = useUnistyles();
<ChevronDown size={theme.iconSize.md} color={theme.colors.foregroundMuted} />
<ChevronDown size={theme.iconSize.md} color={theme.colors.foregroundMuted} />;
```
Importing `baseColors`, theme-name constants, or `type Theme` is fine when the value is intentionally static or type-only.
@@ -233,4 +231,4 @@ The welcome-screen investigation used this approach to prove the white layer was
- [GitHub issue #550: ScrollView sticky-header theme updates](https://github.com/jpudysz/react-native-unistyles/issues/550)
- [GitHub issue #817: `UnistylesRuntime.themeName` does not re-render](https://github.com/jpudysz/react-native-unistyles/issues/817)
- [GitHub issue #1030: `Image.tintColor` and native style update edge case](https://github.com/jpudysz/react-native-unistyles/issues/1030)
- [Local research note: welcome theme split](</Users/moboudra/.paseo/notes/welcome-theme-split-research.md>)
- [Local research note: welcome theme split](/Users/moboudra/.paseo/notes/welcome-theme-split-research.md)
@@ -92,9 +92,7 @@ type DaemonClientConfig = {
};
async function loadDaemonClientConstructor(): Promise<
new (
config: DaemonClientConfig,
) => DaemonClientInstance
new (config: DaemonClientConfig) => DaemonClientInstance
> {
const repoRoot = path.resolve(__dirname, "../../../../");
const moduleUrl = pathToFileURL(
+1 -3
View File
@@ -81,9 +81,7 @@ type ArchiveTabDaemonClientConfig = {
};
async function loadDaemonClientConstructor(): Promise<
new (
config: ArchiveTabDaemonClientConfig,
) => ArchiveTabDaemonClient
new (config: ArchiveTabDaemonClientConfig) => ArchiveTabDaemonClient
> {
const repoRoot = path.resolve(__dirname, "../../../../");
const moduleUrl = pathToFileURL(
+1 -3
View File
@@ -49,9 +49,7 @@ function getDaemonWsUrl(): string {
}
async function loadDaemonClientConstructor(): Promise<
new (
config: NewWorkspaceDaemonClientConfig,
) => NewWorkspaceDaemonClient
new (config: NewWorkspaceDaemonClientConfig) => NewWorkspaceDaemonClient
> {
const repoRoot = path.resolve(__dirname, "../../../../");
const moduleUrl = pathToFileURL(
+1 -3
View File
@@ -63,9 +63,7 @@ type TerminalPerfDaemonClientConfig = {
};
async function loadDaemonClientConstructor(): Promise<
new (
config: TerminalPerfDaemonClientConfig,
) => TerminalPerfDaemonClient
new (config: TerminalPerfDaemonClientConfig) => TerminalPerfDaemonClient
> {
const repoRoot = path.resolve(__dirname, "../../../../");
const moduleUrl = pathToFileURL(
@@ -24,4 +24,3 @@ appId: sh.paseo
commands:
- tapOn:
point: "50%,20%"
-1
View File
@@ -3,4 +3,3 @@ appId: sh.paseo
- launchApp:
clearState: true
- runFlow: flows/dev-client.yaml
+1 -1
View File
@@ -1,8 +1,8 @@
{
"name": "@getpaseo/app",
"main": "index.ts",
"version": "0.1.62",
"private": true,
"main": "index.ts",
"scripts": {
"start": "APP_VARIANT=development expo start",
"reset-project": "node ./scripts/reset-project.js",
+15 -14
View File
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="%LANG_ISO_CODE%">
<head>
<meta charset="utf-8" />
@@ -21,8 +21,9 @@
}
/* Prevent white flash before React mounts */
@media (prefers-color-scheme: dark) {
html, body {
background-color: #181B1A;
html,
body {
background-color: #181b1a;
}
}
/* These styles make the root element full-height */
@@ -38,17 +39,17 @@
input,
textarea,
select,
[role='button'],
[role='link'],
[role='textbox'],
[role='combobox'],
[role='tab'],
[role='switch'],
[role='checkbox'],
[role='slider'],
[role='menuitem'],
[role="button"],
[role="link"],
[role="textbox"],
[role="combobox"],
[role="tab"],
[role="switch"],
[role="checkbox"],
[role="slider"],
[role="menuitem"],
[tabindex],
[contenteditable='true'] {
[contenteditable="true"] {
-webkit-app-region: no-drag !important;
}
@@ -59,7 +60,7 @@
outline: none;
}
*:focus-visible {
outline: 2px solid #20744A;
outline: 2px solid #20744a;
outline-offset: 2px;
}
</style>
+2 -3
View File
@@ -7,9 +7,8 @@ let attachmentStorePromise: Promise<AttachmentStore> | null = null;
async function createAttachmentStore(): Promise<AttachmentStore> {
if (isWeb) {
if (isElectronRuntime()) {
const { createDesktopAttachmentStore } = await import(
"../desktop/attachments/desktop-attachment-store"
);
const { createDesktopAttachmentStore } =
await import("../desktop/attachments/desktop-attachment-store");
return createDesktopAttachmentStore();
}
@@ -82,13 +82,7 @@ vi.mock("expo-image", () => ({
vi.mock("react-native", async () => {
const actual = await vi.importActual<Record<string, unknown>>("react-native");
const Modal = ({
visible = true,
children,
}: {
visible?: boolean;
children?: React.ReactNode;
}) =>
const Modal = ({ visible = true, children }: { visible?: boolean; children?: React.ReactNode }) =>
visible ? React.createElement("div", { "data-testid": "lightbox-modal" }, children) : null;
return { ...actual, Modal };
});
@@ -285,13 +285,7 @@ vi.mock("expo-image", () => ({
vi.mock("react-native", async () => {
const actual = await vi.importActual<Record<string, unknown>>("react-native");
const Modal = ({
visible = true,
children,
}: {
visible?: boolean;
children?: React.ReactNode;
}) =>
const Modal = ({ visible = true, children }: { visible?: boolean; children?: React.ReactNode }) =>
visible ? React.createElement("div", { "data-testid": "lightbox-modal" }, children) : null;
return { ...actual, Modal };
});
@@ -134,8 +134,7 @@ interface SplitNodeViewProps extends Omit<SplitContainerProps, "layout"> {
tabDropPreview: TabDropPreview | null;
}
interface SplitPaneViewProps
extends Omit<
interface SplitPaneViewProps extends Omit<
SplitNodeViewProps,
| "node"
| "workspaceKey"
@@ -145,7 +144,7 @@ interface SplitPaneViewProps
| "dropPreview"
| "onMoveTabToPane"
| "onResizeSplit"
> {
> {
pane: SplitPane;
uiTabs: WorkspaceTab[];
isFocused: boolean;
@@ -237,9 +237,9 @@ describe("providers snapshot hook cache scope", () => {
it.each([
{ name: "missing", entries: [] },
{ name: "loading", entries: [codexEntry("loading")] },
])("ensures a selected provider snapshot on selector open when it is $name", async ({
entries,
}) => {
])(
"ensures a selected provider snapshot on selector open when it is $name",
async ({ entries }) => {
enableProvidersSnapshot();
mockClient.getProvidersSnapshot
.mockResolvedValueOnce(providersSnapshot(entries))
@@ -253,7 +253,8 @@ describe("providers snapshot hook cache scope", () => {
expect(mockClient.getProvidersSnapshot).toHaveBeenLastCalledWith({});
expect(mockClient.refreshProvidersSnapshot).not.toHaveBeenCalled();
});
},
);
it("does not ensure a selected provider snapshot on selector open when the provider is ready with no models", async () => {
enableProvidersSnapshot();
@@ -289,14 +289,9 @@ describe("keyboard-shortcuts", () => {
},
];
it.each(matchingCases)("$name", ({
event,
context,
action,
payload,
preventDefault,
stopPropagation,
}) => {
it.each(matchingCases)(
"$name",
({ event, context, action, payload, preventDefault, stopPropagation }) => {
expectShortcutResolution({
event,
context,
@@ -305,7 +300,8 @@ describe("keyboard-shortcuts", () => {
...(preventDefault !== undefined ? { preventDefault } : {}),
...(stopPropagation !== undefined ? { stopPropagation } : {}),
});
});
},
);
const nonMatchingCases: NonMatchingShortcutCase[] = [
{
+2 -7
View File
@@ -491,10 +491,7 @@ export class HostRuntimeController {
private probeRequestVersion = 0;
private probeCycleInFlight: Promise<void> | null = null;
constructor(input: {
host: HostProfile;
deps?: HostRuntimeControllerDeps;
}) {
constructor(input: { host: HostProfile; deps?: HostRuntimeControllerDeps }) {
this.host = input.host;
this.deps = input.deps ?? createDefaultDeps();
this.connectionMachineState = {
@@ -1155,9 +1152,7 @@ export class HostRuntimeStore {
private storageLoaded = false;
private bootstrapAttempted = false;
constructor(input?: {
deps?: HostRuntimeControllerDeps;
}) {
constructor(input?: { deps?: HostRuntimeControllerDeps }) {
this.deps = input?.deps ?? createDefaultDeps();
}
+4 -4
View File
@@ -2,17 +2,17 @@
"name": "@getpaseo/cli",
"version": "0.1.62",
"description": "Paseo CLI - control your AI coding agents from the command line",
"type": "module",
"bin": {
"paseo": "bin/paseo"
},
"files": [
"bin",
"dist"
],
"type": "module",
"publishConfig": {
"access": "public"
},
"bin": {
"paseo": "bin/paseo"
},
"scripts": {
"build": "node -e \"require('node:fs').rmSync('dist',{ recursive: true, force: true })\" && tsc -p tsconfig.json --incremental false",
"prepack": "npm run build",
+11 -11
View File
@@ -3,6 +3,16 @@
"version": "0.1.62",
"private": true,
"description": "Paseo desktop app (Electron wrapper)",
"homepage": "https://paseo.sh",
"license": "AGPL-3.0-or-later",
"author": {
"name": "Mohamed Boudra",
"email": "hello@moboudra.com"
},
"repository": {
"type": "git",
"url": "https://github.com/getpaseo/paseo.git"
},
"main": "dist/main.js",
"scripts": {
"build": "npm --prefix ../.. run build:daemon && npm run build:main && electron-builder --config electron-builder.yml",
@@ -27,15 +37,5 @@
"typescript": "5.9.3",
"unzip-crx-3": "^0.2.0",
"wait-on": "8.0.5"
},
"homepage": "https://paseo.sh",
"repository": {
"type": "git",
"url": "https://github.com/getpaseo/paseo.git"
},
"author": {
"name": "Mohamed Boudra",
"email": "hello@moboudra.com"
},
"license": "AGPL-3.0-or-later"
}
}
+10 -10
View File
@@ -17,23 +17,23 @@ diverse, inclusive, and healthy community.
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
- Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
- The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
@@ -18,11 +18,13 @@ This example showcases the basic functions of the expo-two-way-audio module:
In the `examples/basic-usage` directory:
1. Install dependencies:
```sh
npm install
```
2. Run the app:
```sh
# Run iOS
npm run ios
@@ -1,6 +1,7 @@
{
"name": "expo-two-way-audio-example",
"version": "1.0.0",
"private": true,
"main": "expo/AppEntry.js",
"scripts": {
"start": "expo start",
@@ -11,17 +12,16 @@
"dependencies": {
"buffer": "^6.0.3",
"expo": "^52.0.0",
"react": "18.3.1",
"react-native": "0.76.2",
"expo-build-properties": "~0.13.1",
"expo-dev-client": "~5.0.3",
"expo-build-properties": "~0.13.1"
"react": "18.3.1",
"react-native": "0.76.2"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@types/react": "~18.3.12",
"typescript": "^5.1.3"
},
"private": true,
"expo": {
"autolinking": {
"nativeModulesDir": "../.."
@@ -1,6 +1,7 @@
{
"name": "expo-two-way-audio-flow-example",
"version": "1.0.0",
"private": true,
"main": "expo/AppEntry.js",
"scripts": {
"start": "expo start",
@@ -25,7 +26,6 @@
"@types/react": "~18.3.12",
"typescript": "^5.1.3"
},
"private": true,
"expo": {
"autolinking": {
"nativeModulesDir": "../.."
+6 -6
View File
@@ -1,10 +1,10 @@
{
"name": "@getpaseo/highlight",
"version": "0.1.62",
"files": [
"dist"
],
"type": "module",
"publishConfig": {
"access": "public"
},
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
@@ -14,9 +14,9 @@
"default": "./dist/index.js"
}
},
"files": [
"dist"
],
"publishConfig": {
"access": "public"
},
"scripts": {
"build": "node -e \"require('node:fs').rmSync('dist',{ recursive: true, force: true })\" && tsc -p tsconfig.json --incremental false",
"prepack": "npm run build",
+5 -5
View File
@@ -2,14 +2,11 @@
"name": "@getpaseo/relay",
"version": "0.1.62",
"description": "Paseo relay for bridging daemon and client connections",
"type": "module",
"publishConfig": {
"access": "public"
},
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"type": "module",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
@@ -30,6 +27,9 @@
"default": "./src/cloudflare-adapter.ts"
}
},
"publishConfig": {
"access": "public"
},
"scripts": {
"build": "node -e \"require('node:fs').rmSync('dist',{ recursive: true, force: true })\" && tsc -p tsconfig.json --incremental false",
"prepack": "npm run build",
+11 -4
View File
@@ -199,9 +199,12 @@ async function stopRelayProcess(relayProcess: ChildProcess): Promise<void> {
}
}, SHUTDOWN_TIMEOUT_MS);
it("full flow: daemon and client exchange encrypted messages through relay", {
it(
"full flow: daemon and client exchange encrypted messages through relay",
{
timeout: 90_000,
}, async () => {
},
async () => {
const serverId = "test-session-" + Date.now();
const connectionId = "clt_test_" + Date.now() + "_" + Math.random().toString(36).slice(2);
@@ -233,7 +236,10 @@ async function stopRelayProcess(relayProcess: ChildProcess): Promise<void> {
const clientSharedKey = await deriveSharedKey(clientKeyPair.secretKey, daemonPubKeyOnClient);
const waitForClientSeen = new Promise<void>((resolve, reject) => {
const timeout = setTimeout(() => reject(new Error("timed out waiting for connected")), 5000);
const timeout = setTimeout(
() => reject(new Error("timed out waiting for connected")),
5000,
);
const onMessage = (raw: unknown) => {
try {
const text =
@@ -361,7 +367,8 @@ async function stopRelayProcess(relayProcess: ChildProcess): Promise<void> {
// Cleanup
daemonWs.close();
clientWs.close();
});
},
);
it("relay only sees opaque bytes after handshake", { timeout: 90_000 }, async () => {
const serverId = "opaque-test-" + Date.now();
+1 -5
View File
@@ -1,8 +1,4 @@
export {
createClientChannel,
createDaemonChannel,
EncryptedChannel,
} from "./encrypted-channel.js";
export { createClientChannel, createDaemonChannel, EncryptedChannel } from "./encrypted-channel.js";
export type { Transport, EncryptedChannelEvents } from "./encrypted-channel.js";
export {
+2 -9
View File
@@ -1,7 +1,4 @@
export type {
ConnectionRole,
RelaySessionAttachment,
} from "./types.js";
export type { ConnectionRole, RelaySessionAttachment } from "./types.js";
export {
generateKeyPair,
@@ -12,9 +9,5 @@ export {
decrypt,
} from "./crypto.js";
export {
createClientChannel,
createDaemonChannel,
EncryptedChannel,
} from "./encrypted-channel.js";
export { createClientChannel, createDaemonChannel, EncryptedChannel } from "./encrypted-channel.js";
export type { Transport, EncryptedChannelEvents } from "./encrypted-channel.js";
+1 -3
View File
@@ -3,9 +3,7 @@ account_id = "10ed39a1dbf316e30abd0c409bed40d6"
main = "src/cloudflare-adapter.ts"
compatibility_date = "2024-12-01"
routes = [
{ pattern = "relay.paseo.sh", custom_domain = true }
]
routes = [{ pattern = "relay.paseo.sh", custom_domain = true }]
[observability]
enabled = true
+25 -4
View File
@@ -11,6 +11,7 @@ Paseo is a mobile + CLI app for monitoring and controlling local AI coding agent
## Build / Lint / Test Commands
### Root (monorepo)
```bash
npm run dev # Start daemon + Expo in Tmux
npm run build:daemon # Build: highlight + relay + server + cli
@@ -20,6 +21,7 @@ npm run format # Format with Biome (in-place)
```
### Server package (`packages/server`)
```bash
npm run dev # Start dev daemon (tsx watch)
npm run build # Build lib + scripts to dist/
@@ -45,6 +47,7 @@ npm run test:ui # Vitest UI at localhost:51204
```
### Other useful commands
```bash
npm run build --workspace=@getpaseo/relay # Rebuild relay before daemon
npm run build --workspace=@getpaseo/server # Rebuild server
@@ -58,13 +61,22 @@ npm run cli -- daemon status # Check daemon status
## Code Style
### Biome (formatting only, no linting)
```json
{ "indentStyle": "space", "indentWidth": 2, "lineWidth": 100, "quoteStyle": "double", "trailingCommas": "all", "semicolons": "always" }
{
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 100,
"quoteStyle": "double",
"trailingCommas": "all",
"semicolons": "always"
}
```
### TypeScript
- **Fully strict** — no `any`, no implicit `any`
- **`interface`** over `type`** when possible
- **`interface`** over `type`\*\* when possible
- **`function` declarations** over arrow function assignments
- **Named types** — no complex inline types in public signatures
- **Object parameters** — use single object param when >1 argument
@@ -72,15 +84,18 @@ npm run cli -- daemon status # Check daemon status
- `noUnusedLocals: true`, `noUnusedParameters: true`, `noFallthroughCasesInSwitch: true`
### Imports
- Use path alias `@server/*` in server package (maps to `./src/`)
- No barrel `index.ts` re-exports — they create unnecessary indirection
### Naming
- Files: `kebab-case.ts` named after the main export (`create-tool-call.ts`)
- Tests: collocated with implementation (`thing.test.ts`)
- No prefixes like `RpcX`, `DbX`, `UiX` — keep one canonical type per concept
### Error Handling
- **Fail explicitly** — throw instead of silently returning defaults
- **Typed domain errors** — extend `Error` with structured metadata
@@ -97,10 +112,16 @@ class TimeoutError extends Error {
```
### State Design
Discriminated unions over bags of booleans/optionals:
```typescript
// Bad
interface FetchState { isLoading: boolean; error?: Error; data?: Data }
interface FetchState {
isLoading: boolean;
error?: Error;
data?: Data;
}
// Good
type FetchState =
@@ -169,7 +190,7 @@ npm run db:query -- "SELECT * FROM agent_timeline_rows..."
## Relevant Docs
| File | What it covers |
|---|---|
| ---------------------------------------------------------- | ------------------------------------------------ |
| [../CLAUDE.md](../CLAUDE.md) | Repository overview, critical rules, quick start |
| [../docs/ARCHITECTURE.md](../docs/ARCHITECTURE.md) | System design, WebSocket protocol, data flow |
| [../docs/CODING_STANDARDS.md](../docs/CODING_STANDARDS.md) | Type hygiene, error handling, React patterns |
+4
View File
@@ -49,15 +49,18 @@ npm start
## Project Status
**✅ Completed** (Phases 1-2):
- Package setup and configuration
- Express server with WebSocket
- React UI with Vite
- WebSocket client with ping/pong testing
**⏳ In Progress** (Phase 3):
- Terminal control (tmux integration)
**📋 Planned** (Phases 4-9):
- LLM integration (OpenAI GPT-4)
- Agent orchestrator
- Speech-to-Text (Deepgram)
@@ -95,6 +98,7 @@ PASEO_HOME=~/.paseo-blue PASEO_LISTEN=127.0.0.1:7777 npm run dev
## Testing
Currently manual testing via:
1. Start servers: `npm run dev`
2. Open http://localhost:5173
3. Test WebSocket connection (green status indicator)
+5 -5
View File
@@ -2,11 +2,6 @@
"name": "@getpaseo/server",
"version": "0.1.62",
"description": "Paseo backend server",
"type": "module",
"publishConfig": {
"access": "public"
},
"types": "./dist/server/server/exports.d.ts",
"files": [
"dist/server",
"dist/src",
@@ -15,6 +10,8 @@
"README.md",
".env.example"
],
"type": "module",
"types": "./dist/server/server/exports.d.ts",
"exports": {
".": {
"types": "./dist/server/server/exports.d.ts",
@@ -27,6 +24,9 @@
"default": "./dist/server/utils/tool-call-parsers.js"
}
},
"publishConfig": {
"access": "public"
},
"scripts": {
"dev": "cross-env NODE_ENV=development node --import tsx scripts/dev-runner.ts",
"dev:tsx": "cross-env NODE_ENV=development tsx watch --ignore '**/*.timestamp-*' src/server/index.ts",
+2 -3
View File
@@ -232,11 +232,10 @@ export interface CreateAgentRequestOptions extends AgentConfigOverrides {
labels?: Record<string, string>;
}
export interface CreatePaseoWorktreeInput
extends Pick<
export interface CreatePaseoWorktreeInput extends Pick<
CreatePaseoWorktreeRequest,
"cwd" | "worktreeSlug" | "attachments" | "refName" | "action" | "githubPrNumber"
> {}
> {}
type CheckoutStatusPayload = CheckoutStatusResponse["payload"];
type SubscribeCheckoutDiffPayload = Extract<
@@ -130,9 +130,7 @@ function buildZodValidator<T>(schema: z.ZodTypeAny, schemaName: string): SchemaV
function buildJsonSchemaValidator<T>(schema: JsonSchema): SchemaValidator<T> {
const AjvConstructor = Ajv as unknown as {
new (
options?: AjvOptions,
): {
new (options?: AjvOptions): {
compile: (input: JsonSchema) => ((value: unknown) => boolean) & {
errors?: ErrorObject[] | null;
};
@@ -1203,9 +1203,7 @@ export async function createAgentMcpServer(options: AgentMcpServerOptions): Prom
? (
await Promise.all(
terminalManager.listDirectories().map(async (directory) =>
(
await terminalManager.getTerminals(directory)
).map((terminal) => ({
(await terminalManager.getTerminals(directory)).map((terminal) => ({
id: terminal.id,
name: terminal.name,
cwd: terminal.cwd,
@@ -8,4 +8,3 @@
* This file is kept as a stub to document the migration.
* It can be deleted once the refactoring is confirmed working.
*/
@@ -49,9 +49,7 @@ export class ClaudeSidechainTracker {
private readonly activeSidechains = new Map<string, SubAgentActivityState>();
private readonly getToolInput: (toolUseId: string) => AgentMetadata | null | undefined;
constructor(input: {
getToolInput: (toolUseId: string) => AgentMetadata | null | undefined;
}) {
constructor(input: { getToolInput: (toolUseId: string) => AgentMetadata | null | undefined }) {
this.getToolInput = input.getToolInput;
}
@@ -291,11 +291,7 @@ export class MockLoadTestAgentSession implements AgentSession {
private modeId: string | null;
private modelId: string | null;
constructor(options: {
config: AgentSessionConfig;
sessionId: string;
logger?: Logger;
}) {
constructor(options: { config: AgentSessionConfig; sessionId: string; logger?: Logger }) {
this.id = options.sessionId;
this.logger = options.logger;
this.modeId = options.config.modeId ?? MOCK_LOAD_TEST_MODE_ID;
@@ -192,13 +192,9 @@ describe.runIf(process.platform === "win32")("Windows provider launch parity", (
});
});
test.each(
providerLaunchCases,
)("$provider launches a cmd shim from a path with spaces through spawnProcess", async ({
binaryName,
args,
shell,
}) => {
test.each(providerLaunchCases)(
"$provider launches a cmd shim from a path with spaces through spawnProcess",
async ({ binaryName, args, shell }) => {
const fixture = makeFixture(binaryName, args);
const result = await runProviderFixture({
@@ -213,5 +209,6 @@ describe.runIf(process.platform === "win32")("Windows provider launch parity", (
expect(result.signal).toBeNull();
expect(result.stderr).toBe("");
expect(result.stdout.trim()).toBe("ARGV_OK");
});
},
);
});
@@ -78,11 +78,9 @@ describe("daemon E2E", () => {
await ctx.cleanup();
}, 60000);
describe.each([
"claude",
"codex",
"opencode",
] as const)("live model switching (%s)", (provider) => {
describe.each(["claude", "codex", "opencode"] as const)(
"live model switching (%s)",
(provider) => {
const shouldRun =
provider === "claude" ||
(provider === "codex" && hasCodex) ||
@@ -123,7 +121,8 @@ describe("daemon E2E", () => {
},
180000,
);
});
},
);
test("live thinking switching works for Claude (off -> on)", async () => {
const cwd = tmpCwd();
+1 -5
View File
@@ -35,11 +35,7 @@ export {
type ProviderOverride,
type ProviderProfileModel,
} from "./agent/provider-launch-config.js";
export {
findExecutable,
quoteWindowsArgument,
quoteWindowsCommand,
} from "../utils/executable.js";
export { findExecutable, quoteWindowsArgument, quoteWindowsCommand } from "../utils/executable.js";
export { execCommand, spawnProcess } from "../utils/spawn.js";
// Provider manifest (source of truth for provider definitions)
@@ -1776,9 +1776,9 @@ describe("workspace aggregation", () => {
rmSync(tempDir, { recursive: true, force: true });
}
const response = emitted.find((message) => message.type === "create_paseo_worktree_response") as
| { type: "create_paseo_worktree_response"; payload: any }
| undefined;
const response = emitted.find(
(message) => message.type === "create_paseo_worktree_response",
) as { type: "create_paseo_worktree_response"; payload: any } | undefined;
expect(response?.payload.error).toBeNull();
expect(response?.payload.workspace).toMatchObject({
@@ -7,8 +7,5 @@ export {
type DaemonEvent,
type DaemonEventHandler,
} from "./daemon-client.js";
export {
createDaemonTestContext,
type DaemonTestContext,
} from "./daemon-test-context.js";
export { createDaemonTestContext, type DaemonTestContext } from "./daemon-test-context.js";
export { useTempClaudeConfigDir } from "./claude-config.js";
@@ -172,11 +172,9 @@ describe("pull request timeline message schemas", () => {
expect(parsed.payload.error).toEqual({ kind: "unknown", message: "x" });
});
test.each([
"rate_limited",
"",
undefined,
])("normalizes malformed error kind %j to unknown", (kind) => {
test.each(["rate_limited", "", undefined])(
"normalizes malformed error kind %j to unknown",
(kind) => {
const parsed = PullRequestTimelineResponseSchema.parse({
type: "pull_request_timeline_response",
payload: {
@@ -185,7 +183,8 @@ describe("pull request timeline message schemas", () => {
});
expect(parsed.payload.error).toEqual({ kind: "unknown", message: "" });
});
},
);
});
describe("checkout PR status compatibility", () => {
+1 -1
View File
@@ -6,7 +6,7 @@ main = "@tanstack/react-start/server-entry"
routes = [
{ pattern = "paseo.sh", custom_domain = true },
{ pattern = "www.paseo.sh", custom_domain = true }
{ pattern = "www.paseo.sh", custom_domain = true },
]
[observability]
+5
View File
@@ -19,6 +19,7 @@ Load the **Paseo skill** first if you need CLI guidance for launching or messagi
## Rules
When using chat:
- create a room with `paseo chat create` if you need a new room
- inspect available rooms with `paseo chat ls` and `paseo chat inspect`
- post with `paseo chat post`
@@ -27,6 +28,7 @@ When using chat:
- check chat often while working
Mentions are active:
- write mentions inline in the message body as `@<agent-id>` to notify a specific agent immediately
- use `@everyone` to notify all non-archived, non-internal agents
- notifications are sent to the target agent without blocking the chat post
@@ -99,10 +101,12 @@ paseo chat wait issue-456 --timeout 60s
## Defaults
When creating a room:
- choose a short slug: `issue-456`, `pr-143-review`, `relay-cleanup`
- give it a clear purpose
When using a room:
- read only a bounded window before acting
- post updates when they would help another agent or your future self
- use `--reply-to` when responding to a specific message
@@ -112,6 +116,7 @@ When using a room:
- your own agent ID is available via `$PASEO_AGENT_ID`
Typical things to post:
- status updates
- blockers
- handoffs
+2 -2
View File
@@ -31,8 +31,8 @@ Parse `$ARGUMENTS` to determine:
### Provider Resolution
| User says | --provider | Mode |
|---|---|---|
| *(nothing)* | `codex/gpt-5.4` | `full-access` |
| ----------- | --------------- | ------------- |
| _(nothing)_ | `codex/gpt-5.4` | `full-access` |
| `codex` | `codex/gpt-5.4` | `full-access` |
| `claude` | `claude/opus` | `bypass` |
| `opus` | `claude/opus` | `bypass` |
+2
View File
@@ -108,6 +108,7 @@ paseo loop stop <id> # Stop a running loop
### Worker prompt
The worker prompt must be:
- self-contained
- concrete about commands, files, branches, tests, PRs, or systems to inspect
- explicit about what counts as progress this iteration
@@ -115,6 +116,7 @@ The worker prompt must be:
### Verifier prompt
The verifier prompt should:
- check facts, not offer fixes
- cite commands, outputs, or file evidence
- be specific about what "done" means
+16 -7
View File
@@ -17,6 +17,7 @@ You are an end-to-end implementation orchestrator. You take a task from understa
## Prerequisites
Load these skills before proceeding:
1. **e2e-playwright** — if the task involves frontend/UI work
## Guard
@@ -47,7 +48,7 @@ Merge with defaults for any missing fields. The file maps role categories to `<a
- The part after `/` is the `model` (e.g., `gpt-5.4`, `opus`)
| Category | Roles covered | Default |
|----------|--------------|---------|
| ---------- | --------------------------------- | --------------- |
| `impl` | impl, tester, refactorer | `codex/gpt-5.4` |
| `ui` | impl agents doing UI/styling work | `claude/opus` |
| `research` | researcher | `codex/gpt-5.4` |
@@ -90,11 +91,13 @@ To archive: Paseo **archive agent**.
### How to Write Agent Prompts
**Describe the problem, not the solution.** Your prompt should tell the agent:
- What's wrong or what needs to be built (the goal)
- How it currently fails (error output, test output, user-visible behavior)
- The acceptance criteria (what "done" looks like)
**Do NOT tell the agent:**
- Which specific lines to change
- What code to write
- Which functions to call or which patterns to use
@@ -142,7 +145,7 @@ State the order and briefly why: "Order 3 — touches server session management
**Order 1 — Single file, single concern.** A contained change: fix a bug in one function, add a field to one type, update one component.
| Phase | Agents |
|-------|--------|
| --------- | ----------------------------- |
| Research | 1 researcher |
| Planning | 0 — orchestrator plans inline |
| Implement | 1 impl |
@@ -152,7 +155,7 @@ State the order and briefly why: "Order 3 — touches server session management
**Order 2 — Single module, few files.** A feature or fix within one package that touches 3-8 files.
| Phase | Agents |
|-------|--------|
| --------- | ---------------- |
| Research | 2 researchers |
| Planning | 1 planner |
| Implement | 1 impl per phase |
@@ -162,7 +165,7 @@ State the order and briefly why: "Order 3 — touches server session management
**Order 3 — Cross-module, multiple packages.** A feature that spans packages.
| Phase | Agents |
|-------|--------|
| --------- | ---------------------------- |
| Research | 3-4 researchers |
| Planning | 2 planners + 1 plan-reviewer |
| Implement | 1-2 impl agents per phase |
@@ -172,7 +175,7 @@ State the order and briefly why: "Order 3 — touches server session management
**Order 4 — Architectural, system-wide.** A new subsystem, major refactor, or system-wide change.
| Phase | Agents |
|-------|--------|
| --------- | ------------------------------ |
| Research | 5+ researchers |
| Planning | 2+ planners + 2 plan-reviewers |
| Implement | 2+ impl agents per phase |
@@ -250,6 +253,7 @@ Deploy planners to create an implementation plan informed by research findings.
Every planner prompt must emphasize this: the default agent instinct is to bolt new code on top of existing code. Resist this.
The right approach:
1. Study the existing code — understand why it's shaped the way it is
2. Design the target shape — what would the code look like if this feature had always existed?
3. Identify the refactoring gap — what needs to change so the new feature slots in cleanly?
@@ -344,6 +348,7 @@ Present the plan to the user. Wait for explicit confirmation before proceeding.
Persist the plan to disk and set up the heartbeat:
Use the Paseo **create schedule** tool with:
- `name`: `"heartbeat-<task-slug>"`
- `target`: `"self"`
- `every`: `"5m"`
@@ -394,6 +399,7 @@ Do the following steps in order:
## Phase 7: Implement
Execute phases from the plan sequentially. For each phase:
1. Launch impl agent(s) with `background: true, notifyOnFinish: true`
2. Wait for notification
3. Verify (Phase 8)
@@ -406,6 +412,7 @@ UI passes use `providers.ui` from preferences. All other impl work uses `provide
### TDD — Not Optional
Every impl agent works TDD:
1. Write a failing test that defines the expected behavior
2. Make it pass
3. Refactor if needed
@@ -462,6 +469,7 @@ Run typecheck when done. Do NOT commit."
### Handling Blockers
If an impl agent reports a blocker:
- Do NOT ask the user (in either mode)
- Spin up a researcher to investigate
- Spin up an impl agent to fix it
@@ -478,7 +486,7 @@ After every implementation phase, deploy auditors to verify the work. Auditors a
### Which Auditors to Deploy
| Phase type | Auditors |
|-----------|----------|
| ------------------ | ------------------------------------------------------ |
| Refactor | `parity`, `regression`, `types` |
| Feature (backend) | `overeng`, `tests`, `regression`, `types` |
| Feature (frontend) | `overeng`, `tests`, `types`, `browser` (if applicable) |
@@ -622,6 +630,7 @@ Do NOT edit files."
### Interpreting Findings
If any auditor reports issues:
1. Check the auditor's activity with Paseo **get agent activity** for details
2. Direct the impl agent to fix them via Paseo **send agent prompt**, or launch a new impl agent if the old one is stale
3. Re-deploy the same auditor after fixes
@@ -842,7 +851,7 @@ Every agent has exactly one role. The role determines what the agent does, wheth
**Naming:** `<role>-<scope>[-<specialization>]` in kebab-case.
| Role | Job | Edits? | Prompt emphasis |
|------|-----|--------|----------------|
| --------------- | ------------------------------------------ | ------ | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `researcher` | Gathers info: codebase, docs, web, scripts | No | "Report what you find. Do not suggest solutions. Do not edit files." |
| `planner` | Creates implementation plan from research | No | "Think refactor-first. Design the target shape, not the steps." |
| `plan-reviewer` | Adversarially challenges a plan | No | "Challenge the plan. Find what's wrong, missing, or over-engineered." |
@@ -81,6 +81,7 @@ Do NOT edit files."
## If Issues Are Found
If any final QA agent reports issues:
1. Launch an impl or refactorer agent to fix them
2. Re-run the specific QA check that failed
3. Repeat until all checks pass
@@ -5,6 +5,7 @@ Deploy impl agents to execute the plan phase by phase. Each phase is independent
## TDD — Not Optional
Every impl agent works TDD:
1. Write a failing test that defines the expected behavior
2. Make it pass
3. Refactor if needed
@@ -17,6 +18,7 @@ If an impl agent finds a broken test, it fixes it. No "pre-existing failures." N
Execute phases sequentially from the plan. Refactoring phases first, then feature phases, then UI passes.
After each phase:
1. Verify (see verification.md)
2. Fix any issues found
3. Re-verify
@@ -29,11 +31,13 @@ Use the Paseo **create agent** tool with `background: true` and `notifyOnFinish:
### How to describe the work
**Describe the problem, not the solution.** Your prompt should tell the agent:
- What's wrong or what needs to be built (the goal)
- How it currently fails (error output, test output, user-visible behavior)
- The acceptance criteria (what "done" looks like)
**Do NOT tell the agent:**
- Which specific lines to change
- What code to write
- Which functions to call or which patterns to use
@@ -95,6 +99,7 @@ Run typecheck when done. Do NOT commit."
## Handling Blockers
If an impl agent reports a blocker:
- Do NOT ask the user (in either mode)
- Spin up a researcher to investigate
- Spin up an impl agent to fix it
@@ -7,6 +7,7 @@ Deploy planners to create an implementation plan informed by research findings.
Every planner prompt must emphasize this: the default agent instinct is to bolt new code on top of existing code. Resist this.
The right approach:
1. Study the existing code — understand why it's shaped the way it is
2. Design the target shape — what would the code look like if this feature had always existed?
3. Identify the refactoring gap — what needs to change so the new feature slots in cleanly?
@@ -65,6 +66,7 @@ Challenge the plan:
## Multiple Planners (Order 3+)
For cross-module tasks, deploy planners focusing on different slices:
- One for backend phases
- One for frontend phases
- One for test strategy
@@ -74,6 +76,7 @@ Then deploy a plan-reviewer to challenge the combined plan.
## Iteration
If the plan-reviewer finds significant issues, either:
1. Send follow-up instructions via the Paseo **send agent prompt** tool to the planner
2. Launch a new planner if the original is stale
@@ -25,7 +25,7 @@ Maps role categories to `<agent-type>/<model>` strings. These map directly to th
- The part after `/` is the `model` (e.g., `gpt-5.4`, `opus`)
| Category | Roles covered |
|----------|--------------|
| ---------- | --------------------------------- |
| `impl` | impl, tester, refactorer |
| `ui` | impl agents doing UI/styling work |
| `research` | researcher |
@@ -33,6 +33,7 @@ Maps role categories to `<agent-type>/<model>` strings. These map directly to th
| `audit` | auditor, qa |
If a category is missing, use these defaults:
- `impl` -> `codex/gpt-5.4`
- `ui` -> `claude/opus`
- `research` -> `codex/gpt-5.4`
@@ -44,6 +45,7 @@ If a category is missing, use these defaults:
Freeform array of natural language strings. The user states preferences and the orchestrator appends them here. Read these at startup and weave them into your behavior contextually.
Examples:
- "Prefer small, focused PRs over large bundled ones"
- "Run E2E tests with Maestro, not Playwright"
- "Always check mobile responsiveness"
@@ -19,7 +19,7 @@ State the order and briefly why: "Order 3 — touches server session management
A contained change: fix a bug in one function, add a field to one type, update one component.
| Phase | Agents |
|-------|--------|
| --------- | ----------------------------- |
| Research | 1 researcher |
| Planning | 0 — orchestrator plans inline |
| Implement | 1 impl |
@@ -31,7 +31,7 @@ A contained change: fix a bug in one function, add a field to one type, update o
A feature or fix within one package that touches 3-8 files. Might involve new types, new tests, a few component changes.
| Phase | Agents |
|-------|--------|
| --------- | ---------------- |
| Research | 2 researchers |
| Planning | 1 planner |
| Implement | 1 impl per phase |
@@ -43,7 +43,7 @@ A feature or fix within one package that touches 3-8 files. Might involve new ty
A feature that spans packages (e.g., server + app, or CLI + server). Multiple concerns, multiple file groups, likely needs interface changes between layers.
| Phase | Agents |
|-------|--------|
| --------- | ----------------------------------------------------------------------- |
| Research | 3-4 researchers (one per area: backend, frontend, tests, external docs) |
| Planning | 2 planners + 1 plan-reviewer |
| Implement | 1-2 impl agents per phase |
@@ -55,7 +55,7 @@ A feature that spans packages (e.g., server + app, or CLI + server). Multiple co
A new subsystem, major refactor, or change that touches most of the codebase. New abstractions, new patterns, potentially breaking changes that need migration.
| Phase | Agents |
|-------|--------|
| --------- | --------------------------------------------------- |
| Research | 5+ researchers across all relevant areas |
| Planning | 2+ planners (one per major area) + 2 plan-reviewers |
| Implement | 2+ impl agents per phase, sequenced carefully |
@@ -7,7 +7,7 @@ After every implementation phase, deploy auditors to verify the work. Auditors a
Not every phase needs every auditor. Match auditors to the work:
| Phase type | Auditors |
|-----------|----------|
| ------------------ | ------------------------------------------------------ |
| Refactor | `parity`, `regression`, `types` |
| Feature (backend) | `overeng`, `tests`, `regression`, `types` |
| Feature (frontend) | `overeng`, `tests`, `types`, `browser` (if applicable) |
@@ -151,6 +151,7 @@ Do NOT edit files."
## Interpreting Findings
If any auditor reports issues:
1. Check the auditor's activity with the Paseo **get agent activity** tool for details
2. Direct the impl agent to fix them via the Paseo **send agent prompt** tool, or launch a new impl agent if the old one is stale
3. Re-deploy the same auditor after fixes
+4
View File
@@ -193,6 +193,7 @@ paseo terminal send-keys <terminal-id> --literal "raw text" # No special token
`Enter`, `Tab`, `Escape`, `Space`, `BSpace`, `C-c`, `C-d`, `C-z`, `C-l`, `C-a`, `C-e`
**Common pattern — launch a process and interact with it:**
```bash
id=$(paseo terminal create --name "my-shell" -q)
paseo terminal send-keys "$id" "claude" Enter
@@ -208,11 +209,13 @@ paseo terminal kill "$id"
## Available Models
**Claude (default provider):**
- `--provider claude/haiku` — Fast/cheap, ONLY for tests (not for real work)
- `--provider claude/sonnet` — Good for most tasks
- `--provider claude/opus` — For harder reasoning, complex debugging
**Codex:**
- `--provider codex/gpt-5.4` — Latest frontier agentic coding model (preferred for all engineering tasks)
- `--provider codex/gpt-5.4-mini` — Cheaper, faster, but less capable
@@ -236,6 +239,7 @@ Both `paseo run` and `paseo wait` block until the agent completes. Trust them.
`paseo run` blocks by default and `--output-schema` returns structured JSON, making it easy to compose agents in bash loops and pipelines.
**Detach + wait pattern for parallel work:**
```bash
api_id=$(paseo run -d --name "impl-api" "implement the API" -q)
ui_id=$(paseo run -d --name "impl-ui" "implement the UI" -q)