---
title: Delete a project
---

# Delete a project

## What it is

Deleting a project removes it from the projects sidebar and terminates any running sessions inside it. It's a **soft delete** — the row stays in the SQLite database with an `is_deleted = 1` flag rather than being physically removed, so an immediate **Undo** restores it cleanly. Your **folder on disk is never touched** — only Omniscio's reference to it goes away. This makes "remove a project" a low-stakes operation: if you delete the wrong one you have ~8 seconds to click the Undo toast, and even after that a developer can hand-flip the flag back in SQLite. Deleted projects do not re-appear after restart, including the auto-created Claude project (`~/Claude`) — once removed, Omniscio respects the user's intent and doesn't resurrect it.

## Where to find it

### How to use it

1. **Right-click the project row.** In the projects sidebar, right-click the project you want to remove. The portal menu opens and the **last** item is **Remove Project** (red trash-can icon).
2. **Click Remove Project.** A confirm dialog appears: _"Are you sure you want to remove "<name>"? This will terminate N active session(s). Your files will not be deleted."_ The session count includes every running, attention, and idle session in the project — paused, ended, archived, and error sessions are already settled and don't count. Click **Remove** (red destructive button) to proceed, or **Cancel** to back out.
3. **Use the middle-click shortcut.** On desktop, middle-clicking the project row also triggers the delete flow — same confirm dialog, same cascade. Quicker than opening the right-click menu when you know what you want. (Not available on mobile, where the right-click menu route is the only path.)
4. **If an agent will not stop, the delete is refused.** Omniscio stops a project's agents before removing it, because removing a project out from under a live agent is how work gets lost. If any agent is still running a few seconds later, the delete stops there and nothing is changed — you get *"Some agents did not stop, so nothing was changed. Stop them and try again."* Stop those sessions by hand (see [pause or stop a session](pause-or-stop-a-session.md)) and click Remove again. Before this, only Claude's agents were stopped and the delete always went through, so an external engine's agent kept working against a project that no longer existed — with nothing on screen saying so.

5. **Use Undo within the toast window.** A toast appears for ~8 seconds: _"Project "<name>" removed"_ with an **Undo** button. Click it (or press the keyboard shortcut shown next to the button — by default the global Undo shortcut) to restore the project row. The sessions that were terminated stay terminated — undo only un-soft-deletes the project record.
6. **Out of luck after the toast?** There is no "Recently deleted" UI yet. If you missed the Undo window, you can manually flip the row back: open the SQLite database at `<userData>/mission-control.db` (path varies by OS — see logs and debugging) and run `UPDATE projects SET is_deleted = 0 WHERE id = '<project-id>'`. The project's sessions are also soft-deleted (cascade), so you may also want `UPDATE sessions SET is_deleted = 0 WHERE project_id = '<project-id>'`. Restart Omniscio to pick up the change.

Note that deleting the **Claude** project (the auto-created `~/Claude` workspace) works the same way — the only twist is that Omniscio won't re-create it on the next launch. The dedup check in the code intentionally includes soft-deleted rows so the user's deletion is respected. If you change your mind, add `~/Claude` as a regular project via the **+** button.

## How it behaves

### Permanently erase (irreversible, no undo)

Directly below **Remove Project** in the same right-click menu is **Permanently Erase** (eraser icon). This is the heavier, one-way cousin of Remove, meant for a privacy/data-subject erasure request rather than everyday tidying:

- **Remove Project** is a soft delete: the row is hidden (`is_deleted = 1`) but its conversation history, embeddings, search index, archive, and attachments all remain in the database until the aged retention purge. It has an ~8-second Undo.
- **Permanently Erase** runs that soft-delete cascade AND then immediately purges the project's stored data — messages, embeddings, FTS search rows, cold-storage archive, and attachments — instead of waiting for the retention horizon. There is **no Undo**.

Clicking it opens a red danger confirm: _"Permanently erase all of "<name>"'s data? This terminates its active sessions and cannot be undone. Your files on disk are not deleted."_ (There is no type-the-name step — the danger button is the guard.) Your files on disk are still never touched; only Omniscio's stored records go. The success toast reads _"Erased all data for "<name>.""_ without a row count, because the purge is a global retention sweep and any number would over-state what belonged to this one project.

### How it works

The right-click menu's **Remove Project** entry and the middle-click handler in [ProjectListItem.tsx](../../src/renderer/src/features/dashboard/ProjectListItem.tsx) both call `handleDeleteProject()`, which uses `useConfirmDialog()` for the confirmation prompt. On confirm, the renderer calls `useProjectStore().removeProject(id)`, which invokes the `PROJECT_DELETE` IPC channel handled in [project-handlers.ts](../../src/main/ipc/project-handlers.ts). The handler delegates to `deleteProjectService(id)` in [project-delete-service.ts](../../src/main/services/project-delete-service.ts), which runs the cascade: stop every non-terminal session on the engine that owns it, through the shared control seam in [engine-agent-control.ts](../../src/main/services/session/engine-agent-control.ts) — an agent run by any engine is stopped, not only Claude's — then call `queries.deleteProject(id)` to flip `is_deleted = 1` and clean up dependent caches (`codebase_stats_cache`, `codebase_stats_ignores`, `recipe_schedules`), clear `settings.ahkLinkedProjectId` if it pointed at the deleted project, and emit `PROJECTS_CHANGED` (plus `RECIPE_SCHEDULES_CHANGED` if any schedules were removed).

The actual SQL is in `deleteProject()` in [queries-projects.ts](../../src/main/db/queries-projects/projects.ts) — a single transaction that runs `UPDATE projects SET is_deleted = 1, updated_at = ? WHERE id = ?` and DELETEs from the three dependent tables. Note `recipe_schedules` is a hard delete, not a soft delete — schedules don't survive project removal even if the project is later undeleted. The undo path in [ProjectListItem.tsx](../../src/renderer/src/features/dashboard/ProjectListItem.tsx) registers a `useUndoStore` entry whose `execute` calls `useProjectStore().undeleteProject(projectId)`, which invokes the `PROJECT_UNDELETE` channel — that one just runs `UPDATE projects SET is_deleted = 0, updated_at = ? WHERE id = ?` in `queries-projects.ts` and emits `PROJECTS_CHANGED`. Sessions are not auto-undeleted because they were also terminated and their `is_deleted` cascade is a separate concern.

Soft delete is a project-wide convention: every query in [queries-projects.ts](../../src/main/db/queries-projects/projects.ts) and every `SELECT` against the `projects` table includes `AND is_deleted = 0`, so deleted rows simply don't appear anywhere in the UI without being physically purged. The `projectExistsByFolderPath()` check in `queries-projects.ts` intentionally **does not** filter by `is_deleted`, which is what makes the Claude project's deletion stick — re-running `ensureClaudeProject()` on the next launch sees the deleted row and skips creation.

**Permanently Erase** (F169) wires the same way but with no undo: the menu item calls `handleEraseProject()` → `useProjectStore().eraseProjectData(id)` → the `PROJECT_ERASE_NOW` channel in [project-handlers.ts](../../src/main/ipc/project-handlers.ts) → `eraseProjectDataNow(id)` in [project-delete-service.ts](../../src/main/services/project-delete-service.ts), which runs `deleteProjectService` + `markProjectSessionsForImmediateErase` + an immediate `purgeExpiredData`. The channel is blocked on the mobile/web bridge and deliberately has no CLI route — an irreversible mass-erase stays a desktop-confirmed action.

## Related

- [project-folder-missing.md](project-folder-missing.md) — different scenario: the folder is gone but the project row stays. Different banner, different fix
- [add-a-project.md](add-a-project.md) — adding a project back if you missed the Undo window
- [edit-a-project.md](edit-a-project.md) — non-destructive changes to a project (rename, recolor, re-icon)
- [default-claude-project.md](default-claude-project.md) — the auto-created Claude project follows the same delete flow but does **not** re-create itself on next launch
