Files
paseo/docs/glossary.md
T
Mohamed BoudraandGitHub 20e46e3e3f Restore project grouping across hosts (#2565)
* fix(projects): restore cross-host grouping

Random host-local project IDs replaced the remote-derived value that had also served as grouping identity. Persist a separate opaque group key and let normal boot reconciliation backfill older records without a migration.

* fix(projects): keep ambiguous clones separate

A shared remote can identify a project across hosts, but it cannot distinguish two independent clones on one host. Treat those keys as ambiguous so host-local project IDs remain separate.

* fix(projects): preserve host-local project identity

* fix(projects): strengthen grouping identity

* test(app): update project host shape contract

* fix(projects): preserve selected host identity

* fix(projects): close grouped routing gaps

* fix(projects): stabilize legacy subproject grouping

* fix(projects): preserve selected project identity

* fix(projects): isolate legacy host identity

* fix(projects): preserve symlinked bootstrap roots

* fix(projects): reconcile grouped custom names

* fix(projects): stabilize settings and path identity

* fix(projects): normalize default remote ports

* fix(projects): harden host and remote identity

* fix(projects): preserve host-scoped actions

* fix(projects): preserve remote path semantics

* fix(projects): model SCP remote semantics

* fix(projects): keep settings on routed host

* fix(projects): preserve SSH URL path semantics

* fix(projects): separate identity from presentation

* test(projects): use grouped identity in UI specs

* fix(projects): harden grouped project routing

* test(projects): expect framed settings route

* fix(projects): preserve exact placement identity

* fix(projects): harden grouping identity and routing

* fix(projects): restore project key as grouping identity

Random host-local project IDs had replaced the persisted cross-host value carried by projectKey. Keep projectId for routing while reconciliation owns and persists projectKey for grouping.

* fix(projects): prevent project key collisions

Preserve platform path semantics and generic remote transports in cross-host keys, and compare legacy checkout roots using filesystem equivalence before materializing ownership.

* test(projects): assert host-scoped project keys

* fix(projects): preserve project key compatibility

Resolve legacy workspace project references at the daemon boundary while keeping projectKey as the cross-host identity. Complete generic SSH normalization without collapsing distinct repositories.

* fix(projects): harden project reference identity

* fix(projects): retain archived reference errors

* fix(projects): scope legacy paths to hosts

* test(app): model persisted project keys

* fix(projects): retain absolute scp users

* fix(projects): resolve legacy mutation aliases

* fix(projects): preserve conservative identity boundaries

* fix(projects): preserve legacy placement identity

* test(projects): assert legacy placement identity

* test(projects): expect canonical Windows keys

* fix(projects): separate bootstrap identity fields

* fix(projects): scope legacy paths by host

* fix(projects): stabilize opaque project identity

* fix(projects): preserve remaining opaque identities

* fix(projects): classify forward-slash UNC roots

* fix(projects): preserve opaque selection keys

* fix(projects): frame host-local project keys

* fix(projects): canonicalize framed identities

* test(projects): isolate repeated remote fixtures

* fix(projects): keep project key as UI identity

* fix(projects): reconcile hydrated project references

* fix(projects): preserve archived project identity

* refactor(projects): group projects from project records, not workspaces

Cross-host grouping had been built by hanging a projectKey off every
workspace descriptor. That scoped the key to the wrong entity: the app
then had to reconstruct project identity per workspace in six modules,
which forced projectKey fallbacks into RPC arguments and a server-side
resolver that turned grouping keys back into project ids.

A workspace has a projectId. The key belongs to the project, and
grouping is a display concern, so the daemon now publishes projects
over project.list plus the existing project.update channel and the app
groups them in one place. Projects are addressed by host-local
projectId everywhere, including the settings route.

Projects persisted without a key are backfilled by ordinary boot
reconciliation, with no migration. Old daemons advertise no projectList
capability and simply do not group.

* test(projects): seed projects alongside workspaces in fixtures

Sidebar fixtures seeded workspaces without their projects, which the
daemon cannot produce now that projects arrive on their own channel, so
nothing rendered. Adds a seeding helper that supplies both.

Also drops the provisioning test for accepting a project key where a
project id belongs; that resolver was removed deliberately.

* fix(projects): keep derived project identity stable

Four gaps left by shrinking the key derivation:

Local keys used a bare path resolve, so one directory reached by a
different spelling produced a different key and reset grouped identity.
Windows CI caught this with the 8.3 and long-name forms of one temp
path. Canonicalize through the shared realpath-aware normalization.

Subproject display names lost their selected-path input, so every
subproject of a monorepo rendered under the same remote-derived name.

Reconciliation only ever backfilled a missing key, so a project whose
remote changed stayed grouped with hosts on the old remote.

Project settings kept a disconnected host selected and rendered a dead
end with no way back to an editable host.

* fix(projects): read scheme remotes as URLs, not scp form

An `ssh://user@host:22/org/repo` remote matched the scp-form pattern
first, because `[^@]+` happily eats `ssh://git`, so the port landed in
the path and the project keyed as `remote:host/22/org/repo`. Two
spellings of one remote therefore never grouped.

Try scp form only when there is no scheme, and drop protocol-default
ports so an explicitly written `:22` matches the same remote without it.
2026-07-29 23:36:31 +02:00

11 KiB

Paseo Glossary

Authoritative terminology. UI label wins. Don't invent synonyms; use what's here.

  • Project — A stable, exact selected-root record. Its host-local projectId is an opaque prj_<16 hex> value. Its persisted projectKey is an opaque equivalence key that may group the logical project across hosts. A normalized Git remote is the current key producer, but consumers must not parse or rederive it. Git facts can update mutable kind and grouping metadata but never the ID, root, or default display name. UI: "Project" / "Add project". Forbidden: "Repo", "Repository" as UI label.
  • Workspace — One concrete cwd on one daemon, with git state; belongs to exactly one project. Its id is opaque workspace identity; its cwd is the filesystem directory. UI: "Workspace". Code: WorkspaceDescriptorPayload (packages/protocol/src/messages.ts:2178). Don't confuse with: Branch (one branch can back many workspaces via worktrees). Forbidden: "Folder", "Directory" as UI label.
  • Archive workspace — Removes one workspace from active use and archives everything it owns. UI, CLI, and MCP always say "Archive workspace", regardless of backing. The daemon leaves ordinary directories intact and removes a Paseo-owned worktree only when no active workspace still references it.
  • Workspace kind — "directory" | "local_checkout" | "worktree". The git-derived, persisted property of a workspace, used across its lifetime (archive safety, sidebar, grouping). Derived from the cwd's git reality by deriveWorkspaceKind in workspace-registry-model.ts, not stored from a user choice. Don't confuse with Isolation (the create-time intent).
  • Isolation — Create-time choice for a new workspace: reuse the existing checkout (Local) or cut a dedicated git worktree (New worktree). A transient setup input, also remembered as a create-form preference; it is not a workspace property. UI: "Isolation" control on the New Workspace screen. Code: isolation ("local" | "worktree"), useWorkspaceIsolation (packages/app/src/screens/new-workspace-screen.tsx); persisted as FormPreferences.isolation (packages/app/src/create-agent-preferences/preferences.ts). Distinct from Workspace kind, which is the git-derived property the intent produces (Local → local_checkout or directory by git-ness; New worktree → worktree). On the wire it is the create request's source.kind (directory | worktree, packages/protocol/src/messages.ts:1693).
  • Agent — See Agent session. UI still says "Agent" / "New Agent" in places, but moving toward Agent session as the canonical term. Code: AgentSnapshotPayload (packages/protocol/src/messages.ts:608). Forbidden: "Task", "Job", "Run".
  • Daemon — Local Paseo server process; identified by serverId. UI: "Daemon" (system contexts only). Code: serverId in ServerInfoStatusPayloadSchema (packages/protocol/src/messages.ts:1936), DaemonClient (packages/client/src/daemon-client.ts).
  • Host — Client-side connection profile pointing at a daemon; bundles one or more HostConnections. UI: "Host" / "Add host" / "Switch host". Code: HostProfile (packages/app/src/types/host-connection.ts:37). Forbidden: "Connection" (means HostConnection, not host).
  • Project host entry — One row in a project for a single (project, daemon) pair, aggregating that daemon's workspaces in the project. Internal. Code: ProjectHostEntry (packages/app/src/utils/projects.ts:11). Don't introduce "Checkout" as a synonym.
  • Placement — One workspace's stable foreign-key relationship to its project plus its git checkout snapshot. Internal. An explicit creation projectId is authoritative when active.
  • Branch — Plain git branch. UI: "Switch branch". Code: currentBranch in WorkspaceGitRuntimePayloadSchema (packages/protocol/src/messages.ts:2136); BranchSwitcher (packages/app/src/components/branch-switcher.tsx).
  • Forge — Git hosting service behind Paseo's change-request features: GitHub, GitLab, Gitea, Forgejo, or a future registered adapter. Code: ForgeService, forge-registry, forge-resolver. Use forge for internal abstraction and registry IDs; use concrete forge names only when a behavior or RPC is forge-specific.
  • Change request — Forge-neutral term for a proposed branch-to-branch code change. UI normally renders the forge noun instead: GitHub/Gitea/Forgejo "PR", GitLab "MR". Code: forge_change_request attachments, checkoutSource: { kind: "change_request" }, and PR/MR status payloads.
  • MR — GitLab merge request. UI label for GitLab change requests only; do not use MR for GitHub/Gitea/Forgejo.
  • Worktree — Paseo-managed git worktree (~/.paseo/worktrees/{name}); also a workspaceKind value. User-facing creation treats it as the worktree workspace isolation choice. Code and paseo.json retain worktree terminology for git lifecycle implementation. Forbidden: "Checkout" as a product synonym.
  • Repository / Remote — Internal Git observations. They may produce mutable kind, branch, and project-grouping metadata but never the host-local project ID, root, display name, or workspace membership. No UI label.
  • Directory-backed surface — A right-sidebar surface whose content is determined by the workspace's cwd, so two workspaces on the same directory see identical content: git diff/status, forge change-request info, file preview/explorer contents. Keyed by (serverId, cwd), never workspaceId. See architecture.md.
  • Workspace-owned state — Per-workspace state that never leaks to a same-cwd sibling: tabs, agents, terminals, panes, title, plus review drafts, diff-mode overrides, composer attachments, and file-explorer open/expand state. Keyed by workspaceId (cwd only as a fallback for old payloads). See architecture.md.
  • Workspace status bucket — Aggregate activity signal for a workspace row. Same-cwd workspaces intentionally share agent and terminal status buckets, while tab, agent, and terminal visibility remains scoped by workspaceId.
  • Agent session — One running instance of an agent inside a workspace (one provider, one model, one cwd, one timeline). The conceptual unit; in the UI this opens as a tab. Moving toward this as the canonical term over "Agent". Code: AgentSnapshotPayload (packages/protocol/src/messages.ts:608).
  • Session — Two senses: (a) per-client connection to a daemon, internal; (b) user-facing agent session, see Agent session. Code: Session (packages/server/src/server/session.ts) for (a). Don't confuse with: provider-side agent session log.
  • Profile — Internal name for the persisted shape of a host. Code: HostProfile (packages/app/src/types/host-connection.ts:37). Never user-facing.
  • Provider — Agent backend (Claude Code, Codex, Copilot, OpenCode, Pi, Oh My Pi). UI: "Provider". Code: ProviderSnapshotEntry (packages/protocol/src/messages.ts:198).
  • Model — A specific LLM offered by a provider. UI: "Model" / "Select model". Code: AgentModelDefinition (packages/protocol/src/messages.ts:187).
  • Tab — UI surface representing one session inside a workspace. Not a conceptual unit; use Agent session when talking about the model. Code: WorkspaceTabDescriptor (packages/app/src/screens/workspace/workspace-tabs-types.ts).
  • Terminal — Workspace-scoped PTY shell streamed over the binary mux channel. UI: "Terminal". Code: TerminalStreamFrame (packages/protocol/src/terminal-stream-protocol.ts).
  • Schedule — Cron-style trigger that creates new agents. UI: CLI/MCP (paseo schedule, create_schedule). Don't confuse with: Heartbeat (cron prompt back into the same agent) or Loop (iterative re-execution of one agent).
  • Heartbeat — Ephemeral cron prompt sent back into the same agent/conversation. Agent surfaces expose create, update cron, and delete only. Use for reminders and babysitting where status should return inline.
  • Mode — Provider-specific operational mode (plan, default, full-access, …). UI: icon-only. Code: modeId in AgentSessionConfig (packages/protocol/src/messages.ts:257).
  • Attachment — External or local context bound to an agent prompt: forge issue/change request, review context, uploaded file, text, or image. UI: "Attach issue or PR/MR". Code: AgentAttachment (packages/protocol/src/messages.ts:782).
  • Composer — The whole prompt surface for sending work to an agent. Code: Composer (packages/app/src/composer/index.tsx). Don't call this "message input" except for the text-entry subcomponent.
  • Composer input — The text-entry surface inside the composer. Code: MessageInput (packages/app/src/composer/input/input.tsx).
  • Composer toolbar — The bottom control row inside the composer input. Contains agent controls, attachment button, voice controls, and stop/send controls. Code: leftContent, beforeVoiceContent, and rightContent slots in MessageInput (packages/app/src/composer/input/input.tsx). Forbidden: "Status bar".
  • Agent controls — Provider, model, mode, thinking, and provider-feature controls for an agent or draft agent. Code: AgentControls / DraftAgentControls (packages/app/src/composer/agent-controls/index.tsx). Forbidden: "Agent status bar".
  • Composer footer — Optional area rendered below the composer input but still inside the keyboard-shifted composer layout. Code: Composer.footer (packages/app/src/composer/index.tsx).
  • Composer track — A contextual lane above the composer input. Specific tracks use the <thing> track form: Queue track, Subagents track. Code: queue track inside Composer (packages/app/src/composer/index.tsx), SubagentsTrack (packages/app/src/subagents/track.tsx).
  • Subagent — User-facing term for an agent session related to a parent agent session. Use subagents in UI copy and docs. Internal daemon/provider plumbing may say "child agent" or child_session, especially for provider-managed imports; do not surface "child agent" as a product term.
  • Attachment tray — The selected-attachments row inside the composer input, above the text input. Code: renderAttachmentTray (packages/app/src/composer/index.tsx). Forbidden: "Attachment bar".
  • Conflict — Two distinct senses; do NOT use the bare word in UI copy without qualifying which: (a) stale-write conflict on paseo.json ("Config changed on disk", code stale_project_config, packages/app/src/screens/project-settings-screen.tsx:593); (b) git merge conflict (no current UI string).

Inconsistencies (documented, not papered over)

  • CLI --host <host> description "Daemon host target" (packages/cli/src/utils/command-options.ts:5) blurs daemon/host; the app keeps them distinct.
  • WorkspaceDescriptorPayloadSchema.workspaceKind accepts legacy "checkout" on the wire (packages/protocol/src/messages.ts:2187) while PersistedWorkspaceKind does not (packages/server/src/server/workspace-registry-model.ts:8).