Repository navigation
feat(desktop): create an empty project and reassign sessions between projects (drag and drop) #5389
Description
Problem
Creating a project in the desktop app goes through a native folder picker — the
composer's "Add project", the + next to the Projects header, and Settings →
Projects all end at projects.add(), which registers an existing directory. The
project is then named after that folder, and the name can only be changed
afterwards from the row menu.
Two gaps remain once that is stated plainly:
- No explicit "New project" flow. The only entry point is "Add project",
which reads as "bring an existing folder in" rather than "create a
container". Users who organize the way ChatGPT Projects do — make the
container first, file conversations into it later — have to invent a folder
for it. - No way to move an existing task into a different project (or out to
"No project" / Ungrouped) from the desktop UI. The session row menu only
offers Pin / Rename / Archive / Unarchive / Delete.
Direction
A project stays directory-backed: creating one names a directory (picked, or
created inside the picker). We are deliberately not adding directory-less
projects, so this does not depend on the default-working-directory work in
#2322 / #2998 — those are about where a project-less session runs, which is a
separate concern.
One consequence worth stating explicitly: the Host resolves a project target to
that project's preferred directory (HostWorkspaceResolver), so moving a task
into a project also moves its working directory. That is intended — it is what
the CLI /move already does for the folder case (#1101).
Desired outcome
- A "New project" action that names a directory (and, ideally, the project)
in one step, instead of an "Add project" affordance that only accepts an
existing folder. - Move an existing task into another project, or out of every project, from
the session row. - Drag and drop as the fast path: drag a session row onto a project in the
sidebar, or onto the Inbox / Ungrouped bucket to clear its association. - A non-drag fallback for accessibility: a "Move to project…" item on the
session row menu.
Why the move half is cheap on the backend
The runtime already supports changing a session's project without a new
protocol:
packages/runtime/src/session-manager.ts—relocateSessionWorkspace(sessionId, { expectedRevision, cwd, projectId })has a dedicatedprojectIdChanged
branch that commits aprojectId-only update whencwdis unchanged.- The Runtime Host exposes it as the operation
session.workspace.relocate,
which accepts a{ kind: 'project', projectId }or a{ kind: 'host_path', path }workspace target.
What is missing is purely the desktop surface: SessionRowActions in
packages/ui/src/session-history-list.tsx exposes only
onToggleFlag | onArchive | onUnarchive | onRename, and the existing
moveToProject / moveToInbox copy is wired only to Work Board items
(apps/desktop/src/renderer/work-board-panel.tsx), not to sessions.
Notes
- Zero-session projects already exist (feat: add persistent project management #1545), so an "empty" project is simply a
folder-backed project with no sessions yet. - Related work: product(desktop): capture deferred work in a project-aware Work Board #2560 (Work Board Inbox vs. project scope), Adding a directory that belongs to an archived project fails with no way to restore it #4935 / fix(desktop): offer to restore an archived project when re-adding its directory #4936
(restore an archived project when re-adding its directory).
Activity
MoonOld commentedon Sep 16, 2026
I'd like to pick this up.
Rough plan:
session.workspace.relocateprojectId-only path (no cwd change).Open question I'd like to settle before writing code: the intended cwd semantics for sessions filed into a directory-less project — this seems tied to #2322 / #2998. I'll start with steps 1–2 and open a PR against
mainonce the direction is clear.MoonOld commentedon Sep 16, 2026
take
MoonOld commentedon Sep 16, 2026
Updating the direction to close the open question in the original write-up.
Decision: a project stays directory-backed. Creating one names a directory (picked, or created in the picker). We are not adding directory-less projects, so this no longer depends on #2322 / #2998 — those cover the fallback cwd for sessions with no project, which is a different problem.
That also means "empty project" is already possible today: it is a folder-backed project with no sessions yet (#1545). The remaining gaps are (a) an explicit "New project" affordance instead of the "Add project"-only entry point, and (b) moving an existing task between projects — which the Host already supports via
session.workspace.relocateand which the desktop UI simply does not expose yet.One consequence to be explicit about: because the Host resolves a project target to that project's preferred directory, moving a task into a project also moves its working directory (same as the CLI
/move). I am treating that as intended.I am starting with (b): a "Move to project…" submenu on the session row, wired to
session.workspace.relocatewith a project target (and ahost_pathtarget seeded from the task's current cwd for the "remove from project" case). Drag and drop, and the "New project" dialog, follow.MoonOld commentedon Sep 17, 2026
Implemented in #5392, which now uses
Fixes #5389so this issue closes when the PR merges.The PR covers named directory-backed project creation, the task-row Move to project menu, and session drag/drop onto project rows (including empty projects) and the visible Ungrouped bucket. Moving into a project also changes cwd to its preferred directory; detaching preserves cwd.
Real desktop validation caught an additional integration bug: the BrowserWindow file-drop guard intercepted session drags before React could receive them. The guard now permits the session MIME only on designated project targets. After restarting the development app, the reporter confirmed manual dragging works.
The branch is synced with main, the architecture conflicts are resolved, and 75 targeted tests plus typecheck, lint, format, and architecture checks pass. CI/review and merge remain pending; keeping the issue open until merge. The default-directory and Work Board issues referenced above remain outside this PR's scope.
MoonOld commentedon Sep 20, 2026
Visual evidence for the implementation in #5392 (which carries
Fixes #5389).What shipped
项目名称→选择文件夹) runs before the folder picker, and the project is registered under the typed name. Entry points are the + on the rail's 项目 heading and Settings → Projects; on macOS the picker getscreateDirectory, so a new folder can be made in place rather than having to exist beforehand.移动到项目item on the session row (keyboard path) and drag and drop onto a project row, including an empty project and the ungrouped bucket.Screenshots (from the development app, driven over CDP)
Verified in the running app, not only in tests:
dragoverreaches React withtypes: ['application/x-maka-session']and is accepted by the row under the pointer (and only by eligible rows), and an end-to-end move into an empty project resolvesokwith the cwd following the project's directory and the rail regrouping live.From review (#5392) — three findings, all fixed: the detach now commits the revision it read instead of replaying a stale directory; Runtime Host groups are headings, not drop targets; and drop eligibility now matches the menu (available, unarchived). Move affordances also follow the Session's Host, since the rail holds only the local Host's project list.
CI is green on the current head; the PR is waiting on a committer's approval.