repowise-dev / repowise-dev/repowise
[Bug] A workspace entry whose directory is gone cannot be removed from the UI — and the sidebar tells you to do exactly that
@rishu685 is already working on this.
Since Sep 18, 2026.
- Dominant language
- Python
- Stars
- 6.7k
- Forks
- 711
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 439
Description
Describe the Bug
Rename or delete a repo folder that is listed in .repowise-workspace.yaml and the
workspace entry becomes unremovable from the web UI. There is no API surface for it at
all, so the stale row is permanent until the user finds out that the fix is a CLI command
and a server restart.
Three things compound:
-
DELETE /api/repos/{repo_id}cannot delete a synthetic entry.list_repos
synthesizes rows for workspace members that have no database row, with a prefixed id
(routers/repos.py:307):status = "needs_index" if abs_path.is_dir() else "missing_dir" synthetic_id = f"ws:{entry.alias}"delete_repo(routers/repos.py:564) opens with a database lookup:repo = await crud.get_repository(session, repo_id) if repo is None: raise HTTPException(status_code=404, detail="Repository not found")A
ws:id has no row by construction, so every delete of a synthetic entry 404s.
And a delete that did somehow succeed would not help: the row is re-synthesized
from the YAML on the next listing. -
No workspace endpoint can edit the config.
routers/workspace.pyis read-only
apart fromPOST /api/workspace/sync; nothing exposes theworkspace removethat
the CLI has. So this is not "the UI forgot to call it" — there is nothing to call. -
The UI promises the affordance anyway. The sidebar renders a
missingpill whose
title is (components/layout/sidebar.tsx:287):"Directory missing — open Workspace to remove or fix"
and links to
/workspace. The Workspace page then renders no actions at all for
that exact status (app/workspace/page.tsx:179):actionsFor={(repo) => repo.status === "missing_dir" ? null : ( <SyncButton alias={repo.id} label={repo.status === "indexed" ? "Sync" : "Index now"} /> ) }Meanwhile
attentionSentencenags about it on every visit — "1 directory is missing on
disk (click-to-posh). Each is marked in the list below." — pointing at a list that
offers nothing to do about it. The user is sent to a dead end by name.
Secondary finding: workspace remove from the CLI does not take effect while serve is
running. list_repos reads request.app.state.workspace_config (repos.py:247), which
is loaded once at startup, so the entry survives in the UI until the server is restarted
— with no indication that a restart is what is missing.
Steps to Reproduce
-
Have a workspace at a root with
.repowise-workspace.yamllisting several repos. -
Rename one of the member directories on disk (here:
Click-to-PoSh→Push to PoSh).
The old alias stays in the YAML; the sync script adds the renamed folder as a new
entry, so the workspace now has both. -
repowise servefrom the workspace root, open the UI. -
Sidebar shows
click-to-poshwith amissingpill; its tooltip says to open Workspace
to remove it. The Workspace page lists it with no actions. -
Try the API directly:
$ curl -X DELETE http://127.0.0.1:7337/api/repos/ws:click-to-posh {"detail":"Repository not found"}
Expected Behavior
A workspace member whose directory no longer exists can be removed from the UI, in the
place the UI already points at. Concretely, any of:
DELETE /api/repos/{repo_id}accepts aws:<alias>id, and drops the entry from
.repowise-workspace.yamlrather than looking for a database row; or- a dedicated endpoint (
DELETE /api/workspace/repos/{alias}) that wraps the same code
path asrepowise workspace remove, with a Remove action wired to it in
actionsForformissing_dir.
Either way the config change should be visible without restarting serve — reload
workspace_config after the mutation, or re-read it per request.
If removal from the UI is deliberately out of scope, the honest minimum is to stop
advertising it: change the sidebar tooltip and have attentionSentence name the command
that actually works (repowise workspace remove <alias>, then restart serve).
Actual Behavior
The entry cannot be removed from the UI by any route. DELETE /api/repos/ws:<alias>
returns 404 {"detail":"Repository not found"}. The only working fix is out-of-band:
$ repowise workspace remove click-to-posh
Writing .repowise-workspace.yaml with 21 repo(s), down from 22 — dropping: click-to-posh
✓ Removed repo 'click-to-posh' from workspace.
followed by restarting serve, because the running server holds the old config in memory.
Environment
- OS: Windows 11 Pro 26200
- Python version: 3.12.0
- Repowise version: 0.50.0 (
repowise --version); code paths above verified identical on
upstreammain@aef2d429 - Installation method: pipx
Additional Context
Related but distinct: #2139 covers how workspace_status is computed for
registered-but-never-indexed repos under Postgres. This one is about the absence of any
removal path for the synthetic entries that status produces — same listing code, opposite
end of the lifecycle.
missing_dir is reachable by ordinary use: renaming a project folder is not an error
state, and a workspace that auto-registers new subdirectories will happily add the new
name alongside the orphaned old one. Every rename leaves a permanent duplicate.
I am happy to open a PR for whichever shape you prefer. The two designs differ in ways
worth settling before code: whether /api/repos should mutate workspace config at all,
and whether a missing_dir entry whose index data still exists on disk should be removed
silently or warn first.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.