Metadata-Version: 2.4
Name: gdrive-organizer
Version: 0.1.0b12
Summary: AI-powered Google Drive organizer CLI — scan, classify, review, apply, rollback
Project-URL: Homepage, https://github.com/papa-channy/google-drive-manager
Project-URL: Repository, https://github.com/papa-channy/google-drive-manager
Project-URL: Issues, https://github.com/papa-channy/google-drive-manager/issues
Project-URL: Documentation, https://github.com/papa-channy/google-drive-manager/tree/main/docs
Author-email: papa-channy <papa.channy@gmail.com>
License: Apache-2.0
License-File: LICENSE
Keywords: ai,automation,cli,file-management,google-drive,organizer
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: System :: Filesystems
Classifier: Topic :: Utilities
Classifier: Typing :: Typed
Requires-Python: >=3.12
Requires-Dist: fastapi>=0.115
Requires-Dist: google-api-python-client>=2.150
Requires-Dist: google-auth-httplib2>=0.2
Requires-Dist: google-auth-oauthlib>=1.2
Requires-Dist: httpx>=0.27
Requires-Dist: jinja2>=3.1
Requires-Dist: keyring>=25.7.0
Requires-Dist: openai>=2.31.0
Requires-Dist: pydantic-settings>=2.5
Requires-Dist: pydantic>=2.9
Requires-Dist: rich>=13.0
Requires-Dist: typer>=0.12
Requires-Dist: uvicorn>=0.30
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Provides-Extra: e2e
Requires-Dist: pytest-playwright>=0.5; extra == 'e2e'
Description-Content-Type: text/markdown

# gdrive-organizer

**AI-powered Google Drive organizer for technical users.**

Scan your entire Drive with a single flat-crawl API call, classify files with AI (xAI Grok), review a generated execution plan, dry-run it, apply it, and roll back if anything looks wrong. All from the CLI, with an optional local web viewer for visual inspection.

**Status**: Beta for technical users

---

## Why this exists

Large Google Drive accounts get messy fast. Manual cleanup is slow, repetitive, and risky. One bad bulk operation can make things worse.

`gdrive-organizer` automates the grunt work while keeping you in control:

```
scan --> classify --> review plan --> dry-run --> apply --> rollback
```

AI suggests changes. You review them before anything touches your Drive.

---

## Key features

- **Flat-crawl scanner** -- one `files.list` call fetches everything, tree is reconstructed in memory (~100x fewer API calls than recursive folder queries)
- **AI classification** -- xAI Grok analyzes file metadata and suggests renames, moves, and folder structures via configurable presets
- **Plan/Apply separation** -- AI output becomes a reviewable JSON plan, never directly mutates your Drive
- **Dry-run** -- preview exactly what will change before committing
- **Rollback** -- undo applied plans with proper ordering and untrash semantics
- **Readonly OAuth mode** -- scan and inspect without granting write access
- **Local web viewer** -- FastAPI dashboard for visual plan review, tree exploration, duplicate detection, and permission audit
- **Incremental sync** -- Changes API integration for fast re-scans
- **Safety by default** -- atomic snapshot writes, advisory locking, session-gated viewer mutations, LLM response validation

---

## Quick Start

### Prerequisites

- Python 3.12+
- A Google Cloud Platform project with Drive API enabled (free)
- An xAI API key for AI classification ([console.x.ai](https://console.x.ai))

### 1. Install

```bash
# macOS / Linux — Homebrew tap
brew tap papa-channy/tap
brew install gdrive-organizer

# Any platform — isolated install via pipx (recommended)
pipx install gdrive-organizer

# Any platform — pip
pip install gdrive-organizer
```

> For development or contributing, install from source instead:
> ```bash
> git clone https://github.com/papa-channy/google-drive-manager.git
> cd google-drive-manager
> uv sync --all-extras
> ```

### 2. Set up Google OAuth

You need a GCP OAuth client credential. This is a one-time setup:

1. Create a GCP project at [console.cloud.google.com](https://console.cloud.google.com)
2. Enable the **Google Drive API**
3. Configure OAuth consent screen (External, testing mode)
4. Create an OAuth client ID (Desktop app) and download `credentials.json`
5. Place it in the config directory:

```bash
mkdir -p ~/.config/gdrive-organizer
cp ~/Downloads/credentials.json ~/.config/gdrive-organizer/
```

> See [docs/04-USER-GUIDE.md](docs/04-USER-GUIDE.md) for detailed step-by-step GCP setup with screenshots.

### 3. Authenticate

```bash
gdrive-organizer auth login
# Browser opens -> select Google account -> authorize -> done
```

### 4. Scan your Drive

```bash
gdrive-organizer scan
# Scanning Google Drive...
# Page 1: 1000 files (total: 1000)
# ...
# Scan complete: 1,282 files, 314 folders
```

### 5. Explore what you have

```bash
gdrive-organizer tree --depth 3     # folder tree
gdrive-organizer stats              # file type breakdown
gdrive-organizer permissions        # sharing audit
```

### 6. Classify with AI and review

```bash
# Register your xAI API key (stored in system keychain)
gdrive-organizer config api-key set

# Generate a classification plan
gdrive-organizer classify

# Review the plan
gdrive-organizer plan show
```

### 7. Dry-run first, then apply

```bash
# Preview changes without touching Drive
gdrive-organizer plan apply --dry-run

# Apply the approved selection from the viewer (default)
gdrive-organizer plan apply

# Bypass the approved subset and force the latest full plan
gdrive-organizer plan apply --latest-plan

# Roll back if needed
gdrive-organizer plan rollback
```

`plan apply` and `plan show` now prefer `approved-plan.json` when it exists. A fresh `classify` run automatically invalidates any older approval, and a real apply archives the consumed approval as history.

### 8. Visual inspection (optional)

```bash
gdrive-organizer view
# Opens http://127.0.0.1:8765 in your browser
```

---

## Screenshots

The local viewer renders your Drive state, AI-generated plan, and applied-plan history.

**Dashboard** — storage overview, indexed counts, quick actions:

![Dashboard](docs/assets/viewer-dashboard.png)

**Plan Review** — name/type filters, bulk actions, approved-subset banner, last-applied panel, and per-op before/after diff:

![Plan Review](docs/assets/viewer-plan.png)

**Explorer** — in-memory file tree from the flat-crawl scanner:

![Explorer](docs/assets/viewer-explorer.png)

**Permissions** — public / domain / specific-user / private breakdown with a list of exposed files:

![Permissions](docs/assets/viewer-permissions.png)

> Screenshots are generated from synthetic data by `scripts/capture_screenshots.py`.
> Re-run after viewer UI changes to refresh them.

---

## CLI Reference

```
gdrive-organizer auth login|status|logout
gdrive-organizer scan [--folder ID] [--incremental] [--no-filter]
gdrive-organizer tree [--depth N]
gdrive-organizer stats
gdrive-organizer permissions
gdrive-organizer classify [--preset migration|second-brain|custom] [--prompt-file PATH]
gdrive-organizer plan show [--latest-plan] [--phase N] [--per-phase N]
gdrive-organizer plan apply [--dry-run] [--verbose] [--force] [--latest-plan] [-y]
gdrive-organizer plan rollback [-y]
gdrive-organizer view [--port N]
gdrive-organizer config show
gdrive-organizer config set KEY VALUE
gdrive-organizer config api-key set|show|delete
gdrive-organizer config exclude --show|--add-folder PATTERN|--remove-folder PATTERN|--add-ext .EXT|--add-name PATTERN|--reset
gdrive-organizer cat FILE_ID
gdrive-organizer export FILE_ID [--mime-type TYPE]
gdrive-organizer create-folder NAME [--parent ID]
```

---

## CLI vs Viewer

`gdrive-organizer` is **CLI-first**. The local web viewer is a review surface, not a full application.

| Use the CLI for | Use the viewer for |
|-|-|
| Authentication, scanning, classification | Visual tree exploration |
| Applying and rolling back plans | Plan review with checkboxes |
| Configuration and operational control | Duplicate detection |
| Scripting and automation | Permission audit dashboard |

The viewer runs locally (`127.0.0.1` only) and has session-gated mutation controls. It is intentionally secondary to the CLI.
When you approve a subset in the viewer, the CLI treats that approved subset as the default execution source until it is applied or invalidated by a newer full plan.

---

## Safety Model

This project is designed around **automation with guardrails**.

| Feature | What it does |
|-|-|
| Plan/Apply separation | AI output becomes a reviewable plan, not direct mutations |
| Approved subset authority | Viewer approval becomes the default CLI apply/show source |
| LLM validation boundary | AI responses are validated before becoming executable operations |
| `--dry-run` | Preview all changes without touching Drive |
| Rollback | Undo applied plans with correct ordering and untrash semantics |
| Readonly OAuth | Scan and inspect without write credentials |
| Atomic snapshot writes | Local state files are written atomically to prevent corruption |
| Advisory snapshot locking | Reduces concurrent write races |
| Viewer session gates | Viewer mutations require confirmation and session tokens |
| Localhost-only viewer | Web UI binds to `127.0.0.1` by default |

**Important**: Once you explicitly run `plan apply`, the tool performs real Google Drive mutations. Always use `--dry-run` first, and use `--latest-plan` only when you intentionally want to bypass the approved subset.

---

## Trust, Privacy, and Data Handling

- **OAuth credentials** are stored locally in `~/.config/gdrive-organizer/`
- **API keys** are stored in your system keychain (via `keyring`)
- **Directories** are created with `0700` permissions on POSIX systems
- **Snapshots** are stored locally in `~/.local/share/gdrive-organizer/`
- **The viewer** binds to localhost only
- **During classification**, file metadata (names, paths, types, sizes) is sent to the configured AI provider (xAI). File contents are **not** sent by default
- **No telemetry or analytics** are collected

If you want to explore your Drive without any data leaving your machine, skip the `classify` step -- `scan`, `tree`, `stats`, and `permissions` are fully local operations.

---

## Classification Presets

| Preset | Description |
|-|-|
| `migration` | Analyzes existing folder structure, organizes into time-series archive with folder shortcuts |
| `second-brain` | Extracts multi-tag classifications from text content, organizes by topic and timeline |
| `custom` | Uses your own prompt file via `--prompt-file` |

```bash
gdrive-organizer classify --preset second-brain
gdrive-organizer classify --preset custom --prompt-file my-rules.txt
```

---

## Configuration

```bash
gdrive-organizer config show            # View current settings
gdrive-organizer config set KEY VALUE   # Update a setting
gdrive-organizer config api-key set     # Register xAI API key
gdrive-organizer config api-key delete  # Remove API key
```

Key settings:

| Setting | Default | Description |
|-|-|-|
| `llm_model` | `grok-4-1-fast-non-reasoning` | AI model for classification |
| `viewer_port` | `8765` | Local viewer port |
| `scan_page_size` | `1000` | Files per API page |
| `batch_size` | `100` | Operations per batch (max 100) |
| `write_rate_limit` | `3.0` | Max writes/sec to Drive API |
| `oauth_readonly` | `false` | Use readonly OAuth scope |

---

## Development

```bash
git clone https://github.com/papa-channy/google-drive-manager.git
cd google-drive-manager
uv sync --all-extras

# Using justfile (requires just: https://github.com/casey/just)
just test          # Run tests (210 tests)
just lint          # Lint with ruff
just fmt           # Format with ruff
just check         # All of the above
just start         # Start viewer in background
just stop          # Stop viewer
just               # List all available commands
```

See [CONTRIBUTING.md](CONTRIBUTING.md) for development workflow details.

---

## Current Limitations

This is a working beta. Known limitations:

- **OAuth testing mode**: Refresh tokens expire after 7 days (Google restriction for unverified apps). Re-run `auth login` to refresh.
- **Memory**: Full scan loads all file metadata into memory. Drives with 1M+ files may need more RAM.
- **AI classification**: Requires an xAI API key. Without it, scan/tree/stats/permissions still work.
- **Content-based classification**: Currently classifies by metadata only (name, path, type, size). Content export for deeper analysis is on the roadmap.
- **Google Workspace files**: No MD5 checksums available, so duplicate detection falls back to name+size heuristics.

These are maturity limitations, not safety concerns. The core scan-classify-review-apply workflow is stable and tested.

---

## Troubleshooting

### "Token has been expired or revoked"

Google OAuth tokens in testing mode expire after **7 days**. This is a Google restriction for unverified apps.

```bash
gdrive-organizer auth logout
gdrive-organizer auth login
```

### "Rate limit exceeded" during plan apply

Google Drive enforces ~3 writes/sec. The tool handles this automatically with exponential backoff, but if it persists:

```bash
gdrive-organizer config set write_rate_limit 2.0   # lower the rate
gdrive-organizer config set batch_size 50           # smaller batches
```

### "Snapshot is stale" warning

If your scan is older than the configured freshness window (default: 60 minutes), the tool warns before applying. Options:

```bash
gdrive-organizer scan --incremental    # fast re-scan via Changes API
gdrive-organizer plan apply --force    # override freshness check (use carefully)
```

### "File not found (404)" during apply

A file was deleted or moved in Drive after your last scan. Re-scan and re-classify:

```bash
gdrive-organizer scan
gdrive-organizer classify
```

### Safe first run recommendation

If this is your first time using the tool, try the readonly exploration path first:

```bash
gdrive-organizer config set oauth_readonly true
gdrive-organizer auth login           # grants read-only access
gdrive-organizer scan
gdrive-organizer tree --depth 3
gdrive-organizer stats
```

Once comfortable, switch to full mode for classification and plan execution:

```bash
gdrive-organizer config set oauth_readonly false
gdrive-organizer auth logout
gdrive-organizer auth login           # re-authenticate with write access
```

### credentials.json not found

Download it again from GCP Console -> APIs & Services -> Credentials -> your OAuth client -> Download JSON. See [docs/04-USER-GUIDE.md](docs/04-USER-GUIDE.md) for the full GCP setup walkthrough.

---

## Roadmap

Near-term:
- Content-based classification (export + analyze file text)
- Performance benchmarks at larger Drive sizes
- Homebrew formula
- Screenshots and demo assets for documentation

Contributions welcome -- see [CONTRIBUTING.md](CONTRIBUTING.md).

---

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.

---

## Project Structure

```
src/gdrive_organizer/
  cli.py              # Typer CLI entry point
  config.py           # Pydantic Settings
  auth/oauth.py       # Google OAuth flow + readonly mode
  scanner/            # Flat crawl, tree reconstruction, permissions
  store/              # JSON snapshot, Changes API sync
  ai/                 # xAI classifier, naming engine, plan generator
  executor/           # Batch API, rate limiter, rollback
  viewer/             # FastAPI local dashboard + templates
  utils/              # Retry, logging
```

---

## License

[Apache License 2.0](LICENSE)
