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

Open 💬 17 comments Opened Mar 27, 2026 by peterstahel85

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 ↗

17 Comments

shifthappens · 3 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 · 3 months ago

Agreed +1

shifthappens · 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.

peterstahel85 · 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.

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

huouer · 2 months ago

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

BlackArrowsDev · 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.

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 · 1 month 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 · 1 month ago

Agree

LawyerinTO · 1 month 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 · 1 month 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 · 1 month 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 · 1 month ago

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

coreyhermanson · 1 month ago

having the same issue

kongfundamentals · 1 month 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 · 1 month ago

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

Petijaune · 27 days 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 · 19 hours ago

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