Metadata-Version: 2.4
Name: keepspace-clean
Version: 1.1.0
Summary: Keepspace Clean: a local-first AI disk cleaner MCP server (macOS & Windows). Default read-only, plan-then-confirm, everything to Trash, auditable.
Author: d7huang
License: MIT License
        
        Copyright (c) 2026 d7huang
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://github.com/d7huang/keepspace-disk-cleaner-mcp
Project-URL: Repository, https://github.com/d7huang/keepspace-disk-cleaner-mcp
Project-URL: Issues, https://github.com/d7huang/keepspace-disk-cleaner-mcp/issues
Keywords: keepspace,mcp,cache,cleanup,trash,macos,windows
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Operating System :: MacOS
Classifier: Operating System :: Microsoft :: Windows
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: mcp<3.0,>=2.0
Requires-Dist: send2trash<3.0,>=1.8
Provides-Extra: dev
Requires-Dist: pytest<10,>=8.0; extra == "dev"
Dynamic: license-file

<!-- mcp-name: io.github.d7huang/keepspace-disk-cleaner-mcp -->

# Keepspace Clean

> **Keep what matters. Clear what doesn't.**

**Keepspace** is a local-first AI disk organizer. **Keepspace Clean** is its
first stage: a **safety-first**, whitelist-based disk cache cleanup server for
the [Model Context Protocol](https://modelcontextprotocol.io) (MCP), so an AI
assistant can explain where your disk space went before anything is touched.
Supports **macOS** and **Windows** only.

**Status: public Beta.** [中文文档](README.zh-CN.md)

At a glance:

- Analyzes disk usage, scans a built-in cache whitelist, and explains findings.
- **Read-only by default** — execution must be switched on deliberately.
- **Never permanently deletes**; approved items only go to the system Trash.
- **Never scans your personal files** — no Desktop / Downloads / Documents, no
  document contents, nothing leaves your machine.

> Default read-only → strict whitelist → scan → plan → **client-side tool
> approval by the user** → move to Trash → auditable. Everything you delete
> goes to the system Trash / Recycle Bin via `send2trash`; nothing is ever
> permanently deleted.

## Design principles

1. **Default read-only.** 5 of 6 tools never modify anything. `execute_cleanup_plan`
   is disabled by default and only becomes enabled when the environment variable
   `DISK_CLEANER_ENABLE_EXECUTION` is explicitly set (see "Execution gate" below).
2. **Strict whitelist.** Cleanup is limited to low-risk, rebuildable cache
   directories declared in `rules.py`. Callers can never pass a path.
3. **Scan → plan → approve → execute.** `create_cleanup_plan` produces a
   one-time, 10-minute-expiring plan with a random `confirmation_token`; only
   `execute_cleanup_plan` can move files. The `confirmation_token` only binds the
   call to one valid plan — it does **not** prove the user saw anything. User
   consent is delegated to MCP tool approval (or the client's own confirmation
   UI, which must use `readOnlyHint` / `destructiveHint` annotations): the client
   must show the pending destructive action to the user and obtain explicit
   approval before each execution.
4. **Trash only.** Everything goes through `send2trash`. No permanent delete,
   no `rm -rf` fallback, no auto-emptying of the Trash. Disk space is only
   freed after the user empties the Trash manually.
5. **Auditable.** Every tool call is appended to a local audit log readable via
   the read-only `get_operation_history` tool. No sensitive content is logged.

## Tools

All tools return structured JSON and accept an optional `lang` parameter
(`"zh"` / `"en"` / `"auto"`, default follows the system locale).

| Tool | Read-only | Description |
|---|---|---|
| `get_disk_usage` | ✅ | Capacity / used / free / free % for a local volume or drive letter. |
| `scan_cleanable_items` | ✅ | Scans built-in whitelist caches above a size threshold. Returns per-item `item_id`, size, risk, `requires_app_closed`, … Scanning is resumable: per-directory failures are reported, never fatal. |
| `create_cleanup_plan` | ✅ | Builds a one-time plan from whitelist `item_id`s (max 20). Re-validates every item (existence, size, whitelist root, no symlink). |
| `execute_cleanup_plan` | ❌ | The only mutating tool, **disabled by default** (see "Execution gate"). Requires `plan_id` + `confirmation_token`; marked `destructiveHint` + `readOnlyHint=false` so tool-approval clients must ask the user before calling. Re-validates paths, sizes, file counts, mtimes and related app processes, then moves to Trash via `send2trash`. |
| `get_trash_usage` | ✅ | Total size of the system Trash / Recycle Bin. No emptying. |
| `get_operation_history` | ✅ | Last `limit` audit records. |

### Example flow

```
get_disk_usage()                                    # what's the state of the disk
scan_cleanable_items(min_size_mb=50, max_items=30)  # what is reclaimable (whitelist; size estimation must be complete)
create_cleanup_plan(item_ids=["pip_cache_macos", …])# plan + confirmation_token (read-only)
# → client shows the pending destructive action to the user and gets approval
execute_cleanup_plan(plan_id="…", confirmation_token="…")  # needs DISK_CLEANER_ENABLE_EXECUTION=1
get_operation_history(limit=20)                     # what happened
```

`execute_cleanup_plan` returns `bytes_actually_freed: 0` and a message about
emptying the Trash — moving to Trash does **not** free disk space.

## Platforms & whitelist

- **macOS:** pip, npm, yarn, Homebrew download cache, CocoaPods, Playwright
  browsers, Xcode DerivedData, Chrome cache, Edge cache.
- **Windows:** pip, npm, yarn, Playwright, Chrome cache, Edge cache.

Everything else is **out of scope** for V1: whole Temp, whole Chrome user-data
directory, chat software, browser profiles, Downloads / Desktop / Documents /
Photos, cloud sync directories, Git repos, AI model directories, system
directories.

## Execution gate

`execute_cleanup_plan` is the only tool that can move files, and it is **disabled
by default**. The server runs pure read-only unless the operator explicitly sets:

```bash
export DISK_CLEANER_ENABLE_EXECUTION=1   # or true / yes / on
```

Without the variable (or with `0` / `false` / `off`), `execute_cleanup_plan`
returns the structured error `EXECUTION_DISABLED`. Even when enabled, every
execution still requires both:

1. a valid, unexpired, unused plan bound to the submitted `confirmation_token`
   (this token proves the plan once existed, **not** that the user approved it), and
2. **client-side tool approval**: a tool-approval-capable MCP client must present
   the destructive action (via `readOnlyHint=false` / `destructiveHint=true`) to
   the user and obtain explicit consent before the call is sent.

## Security model

Path safety is enforced centrally in `disk_cleaner/safety.py`
(`validate_cleanup_path`) at scan, plan, and execute time:

- symlinks rejected (checked before resolving),
- rule roots and `allowed_root` escapes rejected,
- protected directories rejected (system dirs as subtrees; user home and
  sensitive folders via exact/ancestor checks),
- re-validation immediately before any move.

`execute_cleanup_plan` never falls back to permanent deletion if
`send2trash` fails; the item is simply reported as failed.
See [SECURITY.md](SECURITY.md) for the full model.

## Structured error codes

Failures look like:

```json
{"success": false,
 "error": {"code": "PLAN_EXPIRED", "message": "...", "recoverable": true}}
```

| Code | Meaning |
|---|---|
| `UNSUPPORTED_PLATFORM` | Linux or other unsupported OS. |
| `INVALID_ARGUMENT` | Bad parameter (range, type, …). |
| `INVALID_ITEM_ID` | `item_id` not in the whitelist. |
| `PATH_NOT_ALLOWED` | Target outside whitelist root / protected dir. |
| `SYMLINK_REJECTED` | Target is a symlink. |
| `SCAN_PERMISSION_DENIED` | Cannot read a location without elevation; no auto-elevation. |
| `PLAN_NOT_FOUND` | Unknown `plan_id`. |
| `PLAN_EXPIRED` | Plan older than 10 minutes. |
| `PLAN_ALREADY_USED` | Plan already executed. |
| `CONFIRMATION_FAILED` | `confirmation_token` mismatch. |
| `ITEM_CHANGED` | Item changed (size / file count / mtime / path) or disappeared since planning. |
| `APP_RUNNING` | A related app process is still running (or its state is undetectable) for a `requires_app_closed` item; close it and retry. |
| `SIZE_ESTIMATION_INCOMPLETE` | Some entries could not be read, so the size estimate is incomplete; item is not put into a plan. |
| `EXECUTION_DISABLED` | `DISK_CLEANER_ENABLE_EXECUTION` is not set; execution is off in pure read-only mode. |
| `MOVE_TO_TRASH_FAILED` | `send2trash` failed. |
| `PARTIAL_SUCCESS` | Some items succeeded, some failed. |

Python exceptions or absolute local paths are never exposed to the AI client.

## Installation

Requires Python 3.10+.

```bash
pip install keepspace-clean
```

Or from a checkout, for development:

```bash
python3 -m venv .venv && source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install -e .
```

Dependencies are pinned in `pyproject.toml` (tested with Python 3.11.9,
`mcp 2.1.1`, `send2trash 2.1.0`; see `requirements.txt`):

- `mcp>=2.0,<3.0`
- `send2trash>=1.8,<3.0`

> Note: the server uses the official high-level entry
> `from mcp.server.mcpserver import MCPServer` (verified importable and runnable
> with mcp 2.1.1). `mcp.server.fastmcp.FastMCP` is **not** available in this
> environment and is not used.

## MCP client configuration

Static example connection configuration lives in
[`examples/client-config.json`](examples/client-config.json). The root
`server.json` is **not** a client config anymore: it is the MCP Registry
publishing manifest placeholder (see below).

```json
{
  "mcpServers": {
    "keepspace-clean": {
      "command": "/absolute/path/to/.venv/bin/python",
      "args": ["-m", "disk_cleaner.server"],
      "env": {
        "DISK_CLEANER_ENABLE_EXECUTION": "0"
      }
    }
  }
}
```

Set `DISK_CLEANER_ENABLE_EXECUTION` to `1` only if you deliberately want to
allow cleanup execution (see "Execution gate"). Leaving it unset defaults to
pure read-only.

### MCP Registry publishing

`server.json` is the **executable** MCP Registry publishing manifest for this
project (`$schema`, `name: io.github.d7huang/keepspace-disk-cleaner-mcp`,
`title`, `description`, `version`, `repository`, `packages` …). It is already
filled with a `pypi` package entry (`keepspace-clean` `1.1.0`, `stdio`
transport) and validates against the `2025-12-11` registry schema. It is
**not** used for local client configuration (see the example above).

The Registry name, the repository URL and the `<!-- mcp-name: ... -->` comment
at the top of this README must stay identical:
`io.github.d7huang/keepspace-disk-cleaner-mcp`.

To publish (not done yet):

1. Publish the `keepspace-clean` package to PyPI (version must match
   `server.json` / `pyproject.toml`, currently `1.1.0`).
2. Run `mcp-publisher publish server.json`.

### Audit log location

- macOS: `~/Library/Application Support/keepspace-clean/audit.jsonl`
- Windows: `%APPDATA%\keepspace-clean\audit.jsonl`

## Development & tests

```bash
pip install -e ".[dev]"
python -m pytest tests/ -v
```

The suite covers rules (whitelist), path safety (symlink / escape / protected
dirs), scanning, the full plan lifecycle (availability, expiry, one-time use,
confirmation), and execution (success / ITEM_CHANGED / symlink rejection /
partial success). Run with `pytest` from the project root.

## Roadmap

Keepspace Clean is the first stage of Keepspace. Later stages (a desktop app,
inbox-style file organization, information distillation) are **not implemented
today** and are not part of this release.

## Open core

Keepspace is an **open core** project. The safety foundation — the protocol
layer, whitelist rules, path validation, planning and the Trash executor — is
open source, because a tool that asks for your trust must be auditable. AI
judgement, habit models, knowledge distillation and the desktop app are not
part of this repository. See [docs/OPEN-CORE.md](docs/OPEN-CORE.md).

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md). New cache locations are welcome;
changes that weaken the safety rules are not.

## License

[MIT](LICENSE) © 2026 d7huang

The Keepspace name is a mark of d7huang — see [TRADEMARK.md](TRADEMARK.md).
Forks are welcome under the MIT licence, but please choose your own name.
