Allow removal of local folders from a Cowork project's context

Status Open
Maintainer reply None cached
Activity 28 comments · opened Mar 27, 2026

Preflight Checklist

  • [x] I have searched existing requests and this feature hasn't been requested yet
  • [x] This is a single feature request (not multiple features)

Problem Statement

When a local folder is added to a Cowork project's context, there is no way to remove it from within the UI. If the folder was added by mistake, is no longer relevant to the project, or contains files that should no longer be in scope, there's nothing you can do. You can't delete the project entirely and start again either.

This is a basic project management function that would make Cowork projects more useful for ongoing or evolving work.

It is also relevant to reducing data exposure and privacy risks.

Proposed Solution

Expected behaviour: a remove or unlink option should appear alongside the folder listing in the project context panel, allowing users to detach a folder without affecting the folder itself or the rest of the project.

Alternative Solutions

Allow users to delete projects in Cowork.

Priority

High - Significant impact on productivity

Feature Category

CLI commands and flags

Use Case Example

_No response_

Additional Context

_No response_

View original on GitHub ↗

28 Comments

shifthappens · 5 months ago

I totally agree. It's a basic security feature too. Files no longer relevant or off limits by claude should be excluded at any point. the user should be in control what claude can access at any time without starting from scratch and losing important memories and scheduled tasks etc.

konradbr · 4 months ago

Agreed +1

shifthappens · 4 months ago

Workaround: edit file "spaces.json" buried in a couple of UUID folders under '/Users/$user/Library/Application Support/Claude/local-agent-mode-sessions'. Here you'll find the "folders" array per project. Delete any folders Claude should no longer have access to and save the file. Beware of syntax. Relaunch Claude. It did the trick for me.

To quickly discover where the spaces.json file lives, preview any memory file in your project in claude, click the "show in finder" icon in the top right corner and move ± 2 levels up from there.

peterstahel85 · 4 months ago
Workaround: edit file "spaces.json" buried in a couple of UUID folders under '/Users/$user/Library/Application Support/Claude/local-agent-mode-sessions'. Here you'll find the "folders" array per project. Delete any folders Claude should no longer have access to and save the file. Beware of syntax. Relaunch Claude. It did the trick for me. To quickly discover where the spaces.json file lives, preview any memory file in your project in claude, click the "show in finder" icon in the top right corner and move ± 2 levels up from there.

THANK YOU FOR YOUR ATTENTION TO THIS IMPORTANT MATTER (no really thank you)

huouer · 3 months ago

This kind of complete mess must be made by AI coder.

BlackArrowsDev · 3 months ago
Workaround: edit file "spaces.json" buried in a couple of UUID folders under '/Users/$user/Library/Application Support/Claude/local-agent-mode-sessions'. Here you'll find the "folders" array per project. Delete any folders Claude should no longer have access to and save the file. Beware of syntax. Relaunch Claude. It did the trick for me. To quickly discover where the spaces.json file lives, preview any memory file in your project in claude, click the "show in finder" icon in the top right corner and move ± 2 levels up from there.

THIS WORKED. But Anthropic team, there needs to be a way to clear the initial project folder or select an alternate.

<img width="1509" height="1125" alt="Image" src="https://github.com/user-attachments/assets/1e41949c-9d73-4609-ac77-6ec9a43e9123" />
<img width="1369" height="955" alt="Image" src="https://github.com/user-attachments/assets/109c0cdb-8a99-4303-a2e4-9337ba2caff9" />

Depot404 · 3 months ago

18/05/2026 — still no basic “delete folder” feature.
It’s hard to understand how a company capable of building frontier AI models can leave such a trivial UX limitation unresolved for this long.
This isn’t a complex systems problem, it’s a basic file management action. At this point it feels more neglected than difficult.

jlieffort · 3 months ago

Agree

LawyerinTO · 3 months ago

+1
Agree. I ran into this today on the Cowork desktop app. I created a new project and designated a parent folder as context. Because I didn't say "existing project', Cowork mounted both a parent folder and a new nested subfolder of the same path to a project's context. I can't delete Cowork's new folder.

The only workarounds I was given were (1) start a brand new Cowork project and re-add just the folder I want, or (2) wipe the entire LevelDB store, which clears all app state and forces re-auth. Both are disproportionate to the ask, which is just "let me unlink one folder from this project."

azhawk47 · 3 months ago

Agreed. Just started my first cowork project and now I have this phantom folder I can't get rid of from my context section. This should be a relatively simple fix for anthropic so hopefully someone will get to this and resolve it.

ValeriiTerentev · 3 months ago

It's still unresolved

<img width="692" height="191" alt="Image" src="https://github.com/user-attachments/assets/0a39243b-630f-47ef-8932-c417828c64ed" />

Absrudum · 2 months ago

제목: Cowork 프로젝트 컨텍스트에서 폴더를 제거할 수 없음 (재시작·폴더 삭제 후에도 잔존)
환경: Cowork v1.10628.0, macOS
문제: 프로젝트 컨텍스트("컴퓨터에서")에 추가된 빈 폴더를 제거할 UI가 없음. 컨텍스트 항목에 hover해도 ✕/⋯ 미표시, ⋮ 메뉴·세부사항 수정 모두 폴더 관리 기능 없음. 실제 폴더를 Finder에서 삭제하고 앱을 재시작해도 해당 참조가 목록에 그대로 남음.
기대 동작: 컨텍스트 패널의 각 폴더 옆에 제거/연결 해제 옵션 제공, 그리고 삭제된 폴더의 잔존 참조 자동 정리.
재현: 폴더 연결 → Finder에서 폴더 삭제 → 앱 재시작 → 참조 잔존 확인.

coreyhermanson · 2 months ago

having the same issue

kongfundamentals · 2 months ago
Workaround: edit file "spaces.json" buried in a couple of UUID folders under '/Users/$user/Library/Application Support/Claude/local-agent-mode-sessions'. Here you'll find the "folders" array per project. Delete any folders Claude should no longer have access to and save the file. Beware of syntax. Relaunch Claude. It did the trick for me. To quickly discover where the spaces.json file lives, preview any memory file in your project in claude, click the "show in finder" icon in the top right corner and move ± 2 levels up from there.

Thank you so much! For me it worked... But I'm really surprised that it's not straightforward...
On my Windows laptop, the folder is something like:
"C:\Users\$user$\AppData\Roaming\Claude\local-agent-mode-sessions\" Then I had to search the file "spaces.json" as it was located in a subfolder1\subfolder2.

paradoxbound · 2 months ago

No wonder Nate B Jones is having a Codex moment. This is really bad Anthropic.

Petijaune · 2 months ago

Workaround: remove / repoint local folders in a Cowork project (macOS)

Until there's a UI option, you can fix the folder list directly. Claude Cowork stores each project's attached folders in spaces.json, under:

~/Library/Application Support/Claude/local-agent-mode-sessions/<id>/<id>/spaces.json

The script below edits that file safely — dry-run preview, confirmation, timestamped backup, JSON re-validation with automatic rollback. It never touches your actual folders, only the references.

Usage

  1. Quit the Claude app (Cmd+Q — not just close the window; it rewrites the file on quit).
  2. Save the script (e.g. to ~/Downloads/fix_cowork_folders.py).
  3. Open Terminal and run one of:
# Interactive: list spaces, flag broken folders, offer to remove them
python3 ~/Downloads/fix_cowork_folders.py

# Read-only: just show every space and folder (OK / MISSING)
python3 ~/Downloads/fix_cowork_folders.py --list

# Remove every folder whose path no longer exists on disk
python3 ~/Downloads/fix_cowork_folders.py --prune-missing

# Repoint a folder you moved (replace old path prefix with new)
python3 ~/Downloads/fix_cowork_folders.py --old "$HOME/old/" --new "$HOME/new/"
  1. Reopen Claude — it reloads from the corrected spaces.json.

Notes

  • macOS only (paths + pgrep). Requires Python 3 (preinstalled on recent macOS / Xcode CLT).
  • The script refuses to run while the main app is open. A lingering helper process (e.g. the Chrome native-messaging host) is ignored.
  • Backups are written next to the file as spaces.json.bak-<timestamp>. Delete them once you've confirmed things work.
  • Use at your own risk — it's an unofficial workaround, not an Anthropic-supported feature.

<details>
<summary><b>fix_cowork_folders.py</b> (click to expand)</summary>

#!/usr/bin/env python3
"""
Fix Claude Cowork folder references (macOS).

Claude Cowork has no UI button to remove or repoint a local folder attached to
a project ("space"). When you move or delete a folder on disk, its entry stays
in spaces.json and shows up as an empty/broken folder. This script fixes that.

Modes:
  (no arguments)        Interactive: list every space + folder, flag the broken
                        ones, and offer to remove them.
  --list                Just list spaces and folders (read-only).
  --prune-missing       Remove every folder entry whose path no longer exists.
  --old X --new Y       Repoint: replace path prefix X with Y (e.g. after moving
                        a folder). Removes resulting duplicate entries.

Safety (all modes that write):
  1. Refuses to run while the MAIN Claude desktop app is open (it rewrites the
     file on quit). Helper processes are ignored.
  2. Shows a dry-run plan and asks for confirmation (skip with --yes).
  3. Backs up each file before writing (timestamped .bak next to it).
  4. Re-validates the JSON and rolls back automatically if anything is invalid.

Examples:
  python3 fix_cowork_folders.py
  python3 fix_cowork_folders.py --list
  python3 fix_cowork_folders.py --prune-missing
  python3 fix_cowork_folders.py --old "$HOME/Claude/" --new "$HOME/Cowork/"

Requires: macOS, Python 3.
"""

import argparse
import json
import os
import shutil
import subprocess
import sys
from datetime import datetime

# Claude Desktop stores its data here on macOS.
CLAUDE_DIR = os.path.expanduser("~/Library/Application Support/Claude")


def app_is_running():
    """True only if the MAIN Claude desktop process is running.

    Match the main executable (Claude.app/Contents/MacOS/Claude) and ignore
    helper processes (e.g. the Chrome native-messaging host), which can linger
    after the app is quit and do not hold spaces.json open.
    """
    try:
        out = subprocess.run(
            ["pgrep", "-fl", "Claude.app/Contents/MacOS/"],
            capture_output=True, text=True
        )
    except FileNotFoundError:
        return False  # pgrep missing; don't block
    for line in out.stdout.splitlines():
        if "Helper" in line or "Helpers/" in line or "Frameworks/" in line:
            continue
        if "Claude.app/Contents/MacOS/" in line:
            return True
    return False


def find_spaces_files(base):
    """Locate every spaces.json under the Claude app-data directory."""
    matches = []
    for root, _dirs, files in os.walk(base):
        if "spaces.json" in files:
            matches.append(os.path.join(root, "spaces.json"))
    return matches


def load_files():
    """Read every spaces.json, returning a list of (path, data)."""
    result = []
    for path in find_spaces_files(CLAUDE_DIR):
        try:
            with open(path, "r", encoding="utf-8") as fh:
                result.append((path, json.load(fh)))
        except (json.JSONDecodeError, OSError) as e:
            print(f"!  Skipped (unreadable/invalid): {path}\n   {e}")
    return result


def iter_folders(data):
    """Yield (space_name, folder_dict) for every folder in every space."""
    spaces = data.get("spaces", []) if isinstance(data, dict) else []
    for space in spaces:
        folders = space.get("folders")
        if isinstance(folders, list):
            for f in folders:
                if isinstance(f, dict):
                    yield space.get("name", "?"), f


def transform(obj, old, new, counter):
    """Recursively replace any string value that starts with `old`."""
    if isinstance(obj, dict):
        return {k: transform(v, old, new, counter) for k, v in obj.items()}
    if isinstance(obj, list):
        return [transform(v, old, new, counter) for v in obj]
    if isinstance(obj, str) and obj.startswith(old):
        counter.append((obj, new + obj[len(old):]))
        return new + obj[len(old):]
    return obj


def dedupe_folders(data):
    """Within each space, drop duplicate folder entries sharing the same path."""
    removed = []
    for space in data.get("spaces", []) if isinstance(data, dict) else []:
        folders = space.get("folders")
        if not isinstance(folders, list):
            continue
        seen, kept = set(), []
        for f in folders:
            path = f.get("path") if isinstance(f, dict) else None
            if path is not None and path in seen:
                removed.append((space.get("name", "?"), path))
                continue
            if path is not None:
                seen.add(path)
            kept.append(f)
        space["folders"] = kept
    return removed


def prune_missing(data):
    """Remove folder entries whose path does not exist on disk."""
    removed = []
    for space in data.get("spaces", []) if isinstance(data, dict) else []:
        folders = space.get("folders")
        if not isinstance(folders, list):
            continue
        kept = []
        for f in folders:
            path = f.get("path") if isinstance(f, dict) else None
            if path is not None and not os.path.exists(path):
                removed.append((space.get("name", "?"), path))
                continue
            kept.append(f)
        space["folders"] = kept
    return removed


def apply_and_validate(plans):
    """Backup -> write -> re-validate -> rollback on failure, per (path, data)."""
    ts = datetime.now().strftime("%Y%m%d-%H%M%S")
    for path, new_data in plans:
        backup = f"{path}.bak-{ts}"
        shutil.copy2(path, backup)
        try:
            with open(path, "w", encoding="utf-8") as fh:
                json.dump(new_data, fh, ensure_ascii=False, indent=2)
            with open(path, "r", encoding="utf-8") as fh:
                json.load(fh)  # re-validate what we just wrote
            print(f"OK  {path}\n    backup -> {backup}")
        except Exception as e:
            shutil.copy2(backup, path)
            print(f"FAILED  {path}: {e}\n   Restored from backup, file unchanged.")


def confirm(skip):
    if skip:
        return True
    return input("Apply these changes? [y/N] ").strip().lower() in ("y", "yes")


def cmd_list(files):
    """Read-only: print every space and folder with an OK/MISSING flag."""
    any_folder = False
    for path, data in files:
        print(f"# {path}")
        for name, f in iter_folders(data):
            any_folder = True
            p = f.get("path", "")
            flag = "OK" if os.path.exists(p) else "MISSING"
            print(f"   [{flag:7}] {name}: {p}")
        print()
    if not any_folder:
        print("No folders attached to any space.")


def cmd_prune(files, skip_confirm):
    plans = []
    print("=== Plan (dry-run): remove folders whose path no longer exists ===\n")
    for path, data in files:
        removed = prune_missing(data)
        if removed:
            print(f"# {path}")
            for name, p in removed:
                print(f"   remove from '{name}': {p}")
            print()
            plans.append((path, data))
    if not plans:
        print("Nothing to remove. Every folder path exists on disk.")
        return
    if confirm(skip_confirm):
        apply_and_validate(plans)
        print("\nDone. Restart the Claude app to reload your spaces.")
    else:
        print("Aborted. No file modified.")


def cmd_repoint(files, old, new, skip_confirm):
    plans, missing = [], []
    print("=== Plan (dry-run): repoint paths ===")
    print(f"Replace : {old}  ->  {new}\n")
    for path, data in files:
        changes = []
        new_data = transform(data, old, new, changes)
        dupes = dedupe_folders(new_data)
        if not (changes or dupes):
            continue
        print(f"# {path}")
        for o, n in changes:
            exists = os.path.exists(n)
            if not exists:
                missing.append(n)
            print(f"   {o}\n     -> {n}   [{'OK' if exists else 'MISSING'}]")
        for name, p in dupes:
            print(f"   duplicate removed in '{name}': {p}")
        print()
        plans.append((path, new_data))
    if not plans:
        print(f"Nothing to change. No value starts with: {old}")
        return
    if missing:
        print("!  These new paths do NOT exist on disk (will show as broken):")
        for m in sorted(set(missing)):
            print(f"     {m}")
        print()
    if confirm(skip_confirm):
        apply_and_validate(plans)
        print("\nDone. Restart the Claude app to reload your spaces.")
    else:
        print("Aborted. No file modified.")


def cmd_interactive(files, skip_confirm):
    """Default flow: show everything, then offer to remove the broken folders."""
    cmd_list(files)
    broken = any(
        not os.path.exists(f.get("path", ""))
        for _path, data in files
        for _name, f in iter_folders(data)
    )
    if not broken:
        print("Everything looks good — no broken folder to clean up.")
        return
    print("Some folders point to paths that no longer exist (MISSING above).")
    if input("Remove those broken entries now? [y/N] ").strip().lower() in ("y", "yes"):
        cmd_prune(files, skip_confirm)
    else:
        print("Nothing changed. Tip: use --old/--new to repoint a moved folder "
              "instead of removing it.")


def main():
    parser = argparse.ArgumentParser(
        description="Fix Claude Cowork folder references in spaces.json (macOS).")
    parser.add_argument("--list", action="store_true", help="List spaces and folders only")
    parser.add_argument("--prune-missing", action="store_true",
                        help="Remove folder entries whose path no longer exists")
    parser.add_argument("--old", help="Old path prefix to replace (repoint mode)")
    parser.add_argument("--new", help="New path prefix (repoint mode)")
    parser.add_argument("--yes", action="store_true", help="Skip the confirmation prompt")
    parser.add_argument("--force", action="store_true",
                        help="Run even if the main app seems to be running (risky)")
    args = parser.parse_args()

    if (args.old is None) != (args.new is None):
        sys.exit("X  --old and --new must be used together.")

    if not os.path.isdir(CLAUDE_DIR):
        sys.exit(f"X  Claude data directory not found: {CLAUDE_DIR}\n"
                 "   Is Claude Desktop installed on this Mac?")

    files = load_files()
    if not files:
        sys.exit("X  No spaces.json found (no Cowork projects yet?).")

    # Read-only mode never needs the app to be closed.
    if args.list:
        cmd_list(files)
        return

    if app_is_running() and not args.force:
        sys.exit("X  The main Claude app is running. Quit it (Cmd+Q) and retry, "
                 "or use --force if you are sure it is closed.")

    if args.old is not None:
        cmd_repoint(files, args.old, args.new, args.yes)
    elif args.prune_missing:
        cmd_prune(files, args.yes)
    else:
        cmd_interactive(files, args.yes)


if __name__ == "__main__":
    main()

</details>

mpstat · 1 month ago

+1 on the original ask (unlink option in the project context panel), and on the alternative solution already proposed here (allow deleting Cowork projects), either would let users recover from this without guesswork.
Environment: Windows 11 Pro, Claude Desktop v1.21459.0 (f7518f), Cowork

Ran into this today, plus a more serious related failure. (Windows 11 Pro)
I hit the exact problem described here (no way to unlink a folder from a Cowork project's context), and also confirmed there's no way to delete a Cowork project at all, only Archive, which just hides it from the UI without removing the folder reference or any underlying local data.
More concerning: this isn't just an inconvenience, it caused a full service outage.
As a workaround, I renamed the local folder linked to a project, expecting the project to just show that folder as missing. Instead, the entire Cowork VM service failed to start, "Failed to start Claude's workspace / VM service not running", even when trying to create a brand-new, unrelated project afterward. Archiving the affected project didn't resolve it either. A full computer restart was required to recover.
So the combination of these gaps means a routine action (renaming/moving a folder, something a user could easily do by accident, e.g. via normal file organization) can take down Cowork entirely, with no in-app way to unlink, delete, or otherwise recover the broken project reference short of a system reboot.

ScottFindlater · 1 month ago

+1, with a concrete case showing why this gap is worse than an inconvenience.

I run a curated standards library for my business through Cowork projects. As part of a restructure I renamed a folder, and the old empty folder needed deleting. Simple enough, except the old folder was one of the project's connected folders, and that turned a ten second tidy-up into a dead end:

  1. I delete the empty folder from disk. The desktop app silently recreates it, because it is still a connected root of the project.
  2. I look for a way to disconnect the folder from the project. There isn't one. Folders can be added to a project at any time, but never removed. An add-only permission model is a strange design on its face.
  3. I look for a way to delete the project and rebuild it with the right folders. Not possible either; the only option is archiving.
  4. So the officially available "workaround" is: archive the whole project, rebuild it from scratch, and lose the project's accumulated memory and every session's chat history, because one connected folder became obsolete.

Consider what this means in practice. Connecting a folder is a one-way, permanent grant for the life of the project. If a folder is connected by accident, or later turns out to contain sensitive material, there is no way to withdraw access short of abandoning the project and its history. A permission you can grant but never revoke would not pass review in any other product; it should not exist here. The same assistant inside the session can correctly tell me the folder should go, and then has to watch the app resurrect it every time.

The fix requested in this issue (a remove or unlink option next to each connected folder) would have made my case a non-event. I would ask that it be treated as a data-access control gap, not a convenience enhancement, and prioritised accordingly.

shifthappens · 1 month ago

At this point just ditch cowork completely and work from Claude code exclusively. It’s the same engine underneath the hood and you get far better control over everything. You can use git  version control natively , see context window, switch model and effort in the same session, terminal access and therefore computer control is built in, setup remote control. Memory can be done in md files that are portable across AI vendors so you’re not locked in to Anthropic…Best part of course is that one can easily switch folders if things change.  the code tab is not merely for programmers!

dave-ryan-ai · 1 month ago

Shocked that this is still an issue that has not been resolved. Especially if Anthropic is trying to attract new users, this is the kind of gap that would be a huge turnoff to someone trying to learn how to manage context.

HamiltonAgency · 1 month ago

I too am very disappointed in this. I just purchased a Mac M5 specifically for AI coding and finding more limitations here than from the Windows OS. Anthropotic, please fix this!!!! Looks like I will be configuring for Claude Code moving forward.

ghost-ng · 1 month ago

came here to say this is crazy it's still a problem

psopacua · 1 month ago

Came here to agree with @ghost-ng

earsenio · 1 month ago

Full Disclosure: I'm not a developer. I hit this on one of my own projects where context was becoming stale and bloated with duplicates, needed it fixed, and built a small app with a lot of AI help to fully manage said context (local and cloud). So it's vibecoded, and so is the technical aspect of this comment. Worth knowing before you point it at files you care about.

One thing Claude ran into that I haven't seen mentioned in this thread, useful even if you ignore my tool:

spaces.json isn't the only file. Next to it is remote-session-spaces.json, holding per-session folder grants ({ sessionId, spaceId, folders: [...] }). When a session starts, the folders stored there get unioned with the ones the session brings — so a path you deleted from spaces.json can come back from a stale grant. If you removed a folder, relaunched, and later saw it return, that's probably why. The complete manual fix is to remove the path from both files, with Claude fully quit first.

If you'd rather not hand-edit JSON, mine is MIT and macOS-only: https://github.com/earsenio/cpcm

cpcm health                                                # what's stale, and the command that fixes it
cpcm unlink --space "My Project" --path ~/Wrong --dry-run
cpcm scrub                                                 # drop orphaned session grants

It refuses to run while Claude is open, backs up before writing, re-validates and rolls back if anything looks wrong, and --dry-run shows the diff without changing anything. Build from source — given the above, you should be able to read what you're running.

Thanks to @shifthappens and @Petijaune, whose workarounds got me unstuck in the first place. My app does have an unlink button — but it's still a workaround, not a fix: macOS only, unofficial, you have to quit Claude first, and it'll break whenever the file format changes. A real one inside Cowork is the answer, so please keep this issue open.

pacopreciadorea-gif · 1 month ago

Definitivamente es algo que tienen que mejorar. Además de el reto de hacer aún más intuitiva toda la herramienta.

sbmickeyfin · 22 days ago

If we can add something to a project context it seems super basic that we can remove it too...mistakes were made.

LloydPhillips22 · 13 days ago

Bugs are expected, but it is criminal that there are bugs and feature requests that have been around for many months, considering that Anthropic is nearly a TRILLION dollar company.

graaavydavy · 11 days ago

Hitting a variant of this: my connected folder now shows as 'empty' but the underlying local path doesn't exist on disk anymore (confirmed via ls). The stale reference just sits there in the Context panel with no way to unlink it.