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

Closed
#2,234 2 comments 0 reactions 1 assignee View on GitHub

@rishu685 is already working on this.

Since Sep 18, 2026.

bug help wanted
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:

  1. 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.

  2. No workspace endpoint can edit the config. routers/workspace.py is read-only
    apart from POST /api/workspace/sync; nothing exposes the workspace remove that
    the CLI has. So this is not "the UI forgot to call it" — there is nothing to call.

  3. The UI promises the affordance anyway. The sidebar renders a missing pill 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 attentionSentence nags 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

  1. Have a workspace at a root with .repowise-workspace.yaml listing several repos.

  2. Rename one of the member directories on disk (here: Click-to-PoShPush 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.

  3. repowise serve from the workspace root, open the UI.

  4. Sidebar shows click-to-posh with a missing pill; its tooltip says to open Workspace
    to remove it. The Workspace page lists it with no actions.

  5. 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 a ws:<alias> id, and drops the entry from
    .repowise-workspace.yaml rather than looking for a database row; or
  • a dedicated endpoint (DELETE /api/workspace/repos/{alias}) that wraps the same code
    path as repowise workspace remove, with a Remove action wired to it in
    actionsFor for missing_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
    upstream main @ 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.