Repository navigation
cli: projects whose directory was deleted are never removed from the recent projects list #54320
Description
Description
Summary
A project row is created the first time a directory is opened, and it is never removed — not even when the directory itself has been deleted and every session under the project has been deleted. Because each client also refreshes time_active while resolving locations, the dead project keeps jumping back to the top of the recent projects list (Ctrl+O) instead of aging out.
Environment
- opencode version: v2.0.26
- OS: Linux 6.6.114.1-microsoft-standard-WSL2 (WSL2), x86_64
- Terminal:
TERM=xterm-256color(TERM_PROGRAMunset) - Shell: /bin/bash
- Install/channel: standalone binary at
~/.opencode/bin/opencode - Active plugins: none
Reproduction
- Open opencode in some directory and create a session there, e.g.
cd ~/project/foo && opencode. - Delete that directory from the filesystem:
rm -rf ~/project/foo. - Delete the session it created, either from the TUI (
session.delete) or via the API:
opencode api delete /api/session/<sessionID>. The session is gone —GET /api/session/<sessionID>now returns 404. - List projects:
opencode api get /api/project.
Expected Behavior
The project should disappear from the list: its directory no longer exists and it no longer owns any session.
Actual Behavior
The project row persists forever and is still returned by GET /api/project, so it keeps showing in the recent projects menu.
Worse, it does not merely persist — it stays near the top. Every time the client refreshes its locations it re-resolves each project, and for the dead project that resolution fails and still bumps time_active. The project in my DB had its last session on 2026-09-21, but its time_active is 2026-10-10 because I kept opening the recent-projects list.
Two further notes from digging around:
- There is no supported way to remove or hide it.
PATCH /api/project/{projectID}only acceptscanonical,name,icon, andcommands— there is no hidden/archived flag — and there is noDELETE /api/project. Theprojecttable likewise has nohidden/archivedcolumn. - The cascade only runs in one direction.
session,session_v2,permission,project_directory, andworktreeall declareON DELETE CASCADEagainstproject, but nothing ever deletes theprojectrow, so orphaned projects accumulate.
After deleting the last session, the affected row in my database was a pure empty shell — session, session_v2, permission, project_directory, and worktree all matched 0 rows for that project_id — yet it still appeared in the list.
Additional Context
Corresponding log lines, repeating every few seconds while the recent-projects list is open, for a project whose directory no longer exists:
level=INFO message="watcher subscribe" path=<parent-of-deleted-dir> type=entries ignores=0
level=INFO message="watcher started" path=<parent-of-deleted-dir> type=entries backend=node
level=INFO message="watcher stopped" path=<parent-of-deleted-dir> type=entries
level=INFO message="Sent HTTP response" http.method=GET http.url=/api/location http.status=404
Schema of the project table as of this version:
CREATE TABLE `project` (
`id` text PRIMARY KEY,
`worktree` text NOT NULL,
`vcs` text,
`name` text,
`icon_url` text,
`icon_color` text,
`time_created` integer NOT NULL,
`time_updated` integer NOT NULL,
`time_initialized` integer,
`sandboxes` text NOT NULL,
`commands` text,
`icon_url_override` text,
`time_active` integer DEFAULT 0 NOT NULL
)Suggested fix, in order of preference:
- Garbage-collect projects whose
canonicalpath no longer exists and that have no sessions, worktrees, or other dependent rows — either at startup or when listing projects. - Failing that, add an explicit way to remove a project:
DELETE /api/project/{projectID}and/or a "remove from recents" action in the recent-projects menu. - At minimum, stop bumping
time_activewhen location resolution fails with 404, so dead projects at least age out of the recent list on their own.
Current workaround: stop the background service and delete the row by hand:
opencode service stop
python3 -c "
import sqlite3
con = sqlite3.connect('<opencode.db>')
con.execute(\"DELETE FROM project WHERE id='<projectID>'\")
con.commit()
con.close()
"Plugins
No response
OpenCode version
No response
Steps to reproduce
No response
Screenshot and/or share link
No response
Operating System
No response
Terminal
No response
Activity
opencode-agent commentedon Oct 10, 2026
Thanks for the detailed report and the digging into the schema and logs!
I think this is a duplicate of #49442. That issue reports the same thing: projects whose directory was moved or deleted stay in the
/open(Ctrl+O) list and can't be removed. The wider question of what should happen to deleted projects is being tracked in #39903.Possible duplicates and closely related issues, ordered by likelihood:
/open//projectand can't be removedProject.list()(fix(core): exclude deleted projects from listing #39899) was closed so the deleted-project lifecycle could be decided there firstDELETE /project/:projectIDYour finding that resolving a dead project keeps bumping
time_active, so it never ages out of the recent list, is a useful extra detail. Please consider adding it as a comment on #49442 or #39903.The bot will close this issue as a duplicate in 1 day unless you reply explaining how your problem is different.
opencode-agent commentedon Oct 11, 2026
We haven't heard back, so I'm closing this as a duplicate of #49442, which reports the same problem: projects whose directory was deleted stay in the recent projects list (Ctrl+O) and can't be removed.
To follow progress:
/open//projectYour finding that resolving a dead project keeps bumping
time_activeis still useful, so please add it as a comment on #49442 or #39903. If your problem turns out to be different, reply here and we can reopen.