Skip to content

Profiles: one window per profile, fully scoped #280

Description

@simion

Profiles are approved.
The plan is docs/plans/profiles.md, and this issue tracks phase 1.
Phase 2, several accounts per agent, is #278, which is where the ask came from and where that half is tracked.

What it is

A profile is a fully isolated termic instance: its own projects, tasks, settings, agents and config, running in its own window.
The point is two windows on two monitors, live at the same time, that cannot see each other's projects.
Not a sidebar filter, and not serial switching inside one window.

This replaces the Spaces idea, which was deleted in 8f8161e.
Spaces was a filter with a window attached, and the ask was the boundary rather than the view.

Settled

  • One window per profile. Strictly 1:1 in v1. Several windows sharing one profile is deferred: it needs a Rust-authoritative sync layer, and the same task mounted twice means either two WebGL terminals on one PTY or scrollback replay on every move.
  • Everything is profile scoped: settings, projects, tasks, agents, config.
  • Phase 1 changes nothing about agent logins. Every profile shares the one login each agent already has, so a new profile opens with its agents already signed in. No config dir is relocated in this phase.
  • The CLI and MCP address the profile that owns the project. A project registered in more than one profile resolves to the most recently focused window.

Data layout

One frozen slug keys both trees, so the two halves of a profile are the same word in each:

  • <data>/profiles/<slug>/ for settings, projects, tasks and scratch.
  • ~/termic/profiles/<slug>/tasks for worktrees.

The default profile is the existing root directory and nothing moves, so an install that never creates a second profile is byte for byte what it is today, and profiles.json does not exist until the first one is created.
App data deliberately stays out of ~/termic: the Seatbelt profile ends with a deny on the data dir, and nesting that inside the worktrees tree would put an allow and a deny in one subtree.

UI

  • A strip above the sidebar footer carrying the accent tile and the profile name in clear, which appears only once a profile exists. Clicking it switches to a profile, or launches its window if it is closed.
  • The footer loses its Add project button, which duplicates the one in the PROJECTS header.
  • A New Profile wizard, not WelcomeDialog, whose welcomed flag is global and must never replay.
  • Deleting a profile asks whether to keep its worktrees. It never deletes a branch and never touches a main checkout.

Decide before any code

How Rust resolves which profile a command means.
Threading a slug through every command signature is invasive and silently forgettable.
Deriving it from the calling window (window: tauri::Window, profile-<slug> label) and then deleting data_dir() makes a forgotten call site a compile error rather than a silent write into the default profile's projects.json.

Biggest known cost

localStorage is not per profile and never will be for free: all windows share one webview origin, so everything not keyed by task UUID needs a profile:<slug>: namespace or a move to the per-profile data dir.
The plan lists the rest, including the tray merge, the deep_link_take_pending race across windows, and the multi-window perf budget.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    plannedFeature is planned and will be implemented

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions