Metadata-Version: 2.4
Name: yo-claude
Version: 0.0.3
Summary: Keep your Claude session alive and get reminded before it resets
Author-email: Daniel Murrell <dsmurrell@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/dsmurrell/yo-claude
Project-URL: Repository, https://github.com/dsmurrell/yo-claude.git
Project-URL: Issues, https://github.com/dsmurrell/yo-claude/issues
Keywords: claude,anthropic,cli,productivity,rate-limit
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Utilities
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: tomli>=2.0.0; python_version < "3.11"
Dynamic: license-file

# yo-claude

**Start your Claude session refresh early to avoid mid-work interruptions**

A tiny tool that watches your Claude session window, says "yo" to start a new one as soon as the old one expires, and reminds you before a window with unused capacity resets.

## What this does

Claude has a session-based rate limit with a ~5 hour window. If you're deep in flow when the timer expires, you get interrupted. Annoying.

**The problem:** Your session timer only starts when you send your first message:

![Session not started](has-not-started.png)

**The solution:** yo-claude sends a "yo" whenever no session window is running, so the timer starts early:

![Session timer running](starts-after-first-send.png)

This way, the cooldown happens during idle time instead of interrupting your deep work.

## What this doesn't do

- Increase your quota
- Guarantee uninterrupted sessions
- Break any rules

It just automates something you could do manually.

## Requirements

- Python 3.9+
- [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) installed and authenticated

## Installation

```bash
pip install yo-claude
```

Or with pipx (recommended):

```bash
pipx install yo-claude
```

## Usage

### Quick start

```bash
# Check the session and send a yo if none is running
yo-claude

# Force send a yo regardless of session state
yo-claude send

# Show session usage, reset time and scheduler status
yo-claude status
```

### Run automatically in the background

```bash
# Install the background scheduler
yo-claude install

# Check it's working
yo-claude status

# Remove when you don't want it anymore
yo-claude uninstall
```

This uses your OS's native scheduler:
- **macOS**: LaunchAgent
- **Linux**: systemd user timer
- **Windows**: Task Scheduler

All user-level, no root/admin required, easily removable.

### View logs

```bash
yo-claude logs
yo-claude logs -n 50  # last 50 entries
```

## Configuration

Config file: `~/.yo-claude/config.toml`

Create one with defaults:

```bash
yo-claude config --create
```

Options:

```toml
# How often to check session status (minutes)
check_interval = 2

# Notify when session resets within this many minutes (0 = disabled)
reminder_threshold = 60

# Only send reminder if usage is below this percentage
reminder_max_pct = 80

# Path to claude CLI (auto-detected if not set)
# claude_path = "/usr/local/bin/claude"

# Fallback: send a yo after this many minutes if /usage shows no session window
# yo_interval = 301
```

### Why check every 2 minutes?

Checking is free: it runs `claude -p /usage`, which reads your session status without spending tokens. Checking often means a new window starts within a couple of minutes of the old one expiring, including right after your computer wakes from sleep.

## How it works

1. The scheduler wakes every `check_interval` minutes
2. Runs `claude -p /usage` to read how much of the session you've used and when it resets
3. If the session has expired → sends `claude -p "yo"` to start a new window
4. If the session resets within `reminder_threshold` minutes and you've used less than `reminder_max_pct`% → shows one desktop alert per reset ("use it or lose it!")
5. If no session window is shown → sends a yo, unless one was sent within `yo_interval` minutes
6. If `/usage` fails → does nothing and tries again at the next check

## Files

Everything lives in `~/.yo-claude/`:

```
~/.yo-claude/
  config.toml    # Your configuration (optional)
  state.json     # Last yo timestamp
  yo-claude.log  # What happened and when
```

## Cost

Each "yo" is ~15-20 tokens, and yo-claude only sends one when no session is running: at most ~5 per day, usually fewer. The `/usage` checks cost nothing. Completely negligible.

## Manual setup (if you prefer)

If you'd rather use your own scheduler:

```bash
# The only command you need to run periodically
yo-claude run
```

Or skip the package entirely:

```bash
claude -p "yo"
```

That's literally all this tool automates.

## Uninstalling

```bash
# Remove the scheduler
yo-claude uninstall

# Uninstall the package
pip uninstall yo-claude

# Optionally remove config/state
rm -rf ~/.yo-claude
```

## Development

### Building and uploading to PyPI

```bash
# Bump version in pyproject.toml and src/yo_claude/__init__.py first
./build_and_upload.sh
```

You'll need a PyPI API token. Create one at https://pypi.org/manage/account/token/ and either enter it when prompted (username: `__token__`, password: your token) or save it to `~/.pypirc`:

```ini
[pypi]
username = __token__
password = pypi-XXXXX...
```

### Running tests

The tests replace the `claude` CLI with a fake and use a temp home directory, so they never touch your real session or `~/.yo-claude`:

```bash
pip install pytest
pytest
```

### Installing from source

```bash
git clone https://github.com/dsmurrell/yo-claude.git
cd yo-claude
pip install -e .
```

## Gotchas

- **pyenv shim issues**: If you see `/Users/you/.pyenv/shims/yo-claude` instead of the actual binary, run `pyenv rehash` after installing.
- **macOS permission dialogs**: On first run, macOS may ask for permission to access Documents or Apple Music. This is the `claude` CLI (a Node.js app) triggering macOS sandbox checks. Click through them - they only appear once.
- **macOS Login Items**: The scheduler shows as "python3.x - Item from unidentified developer" in System Settings → General → Login Items. This is normal for Python-based LaunchAgents.

## Platform notes

### macOS

The scheduler appears in System Settings → General → Login Items as "python3.x - Item from unidentified developer". This is normal for Python-based LaunchAgents.

`yo-claude install` automatically detects and saves your claude path, so it works even if you installed Claude Code via nvm or Homebrew.

### Linux

Uses systemd user timers. Should work out of the box, but **not yet tested**. If you're on Linux, please test and report issues or submit fixes!

### Windows

Uses Task Scheduler. Should work, but **not yet tested**. If you're on Windows, please test and report issues or submit fixes!

## License

MIT

## FAQ

**Does this eat into my quota?**

Barely. At most ~5 yos per day at ~20 tokens each = ~100 tokens, and the `/usage` checks are free. Less than a single short question.

**What if I also use Claude via the web?**

Both count toward the same session. yo-claude reads the real session state, so it only sends a yo when no session is running.

**Is this cheating?**

No. You're just automating the act of sending a trivial message. The same limits apply.

**Why Python?**

Readable, auditable, runs everywhere. The entire codebase is a few hundred lines.

**What if Claude changes their session window?**

yo-claude reads the reset time from `claude -p /usage`, so it follows whatever window Claude reports.

**What if my computer was asleep?**

When it wakes, the scheduler runs within a couple of minutes, sees that the session has expired, and sends a yo. You're back in sync.

**The scheduler can't find claude but it works in my terminal?**

`yo-claude install` should auto-detect your claude path. If it didn't work, set it manually in `~/.yo-claude/config.toml`:

```toml
claude_path = "/full/path/to/claude"
```

Find your path with `which claude`, then run `yo-claude uninstall && yo-claude install`.
