Metadata-Version: 2.4
Name: term-pet
Version: 0.2.0
Summary: A terminal pet companion that monitors Claude Code sessions
Project-URL: Homepage, https://github.com/paulrobello/tpet
Project-URL: Documentation, https://github.com/paulrobello/tpet/blob/main/README.md
Project-URL: Source, https://github.com/paulrobello/tpet
Project-URL: Issues, https://github.com/paulrobello/tpet/issues
Author-email: Paul Robello <probello@gmail.com>
Maintainer-email: Paul Robello <probello@gmail.com>
License: MIT License
        
        Copyright (c) 2026 Paul Robello
        
        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.
License-File: LICENSE
Keywords: ai,ascii,claude,llm,ollama,pet,terminal,tui
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: End Users/Desktop
Classifier: Intended Audience :: Other Audience
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: MacOS
Classifier: Operating System :: Microsoft :: Windows :: Windows 10
Classifier: Operating System :: Microsoft :: Windows :: Windows 11
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Terminals
Classifier: Typing :: Typed
Requires-Python: >=3.13
Requires-Dist: claude-agent-sdk>=0.2.87
Requires-Dist: google-genai>=2.7.0
Requires-Dist: numpy>=2.4.6
Requires-Dist: openai>=2.38.0
Requires-Dist: pillow>=12.2.0
Requires-Dist: pydantic>=2.13.4
Requires-Dist: python-dotenv>=1.2.2
Requires-Dist: pyyaml>=6.0.3
Requires-Dist: rich>=15.0.0
Requires-Dist: typer>=0.26.3
Requires-Dist: watchdog>=6.0.0
Requires-Dist: xdg-base-dirs>=6.0.2
Description-Content-Type: text/markdown

# TPET - Terminal Pet Companion

A terminal pet that monitors your Claude Code sessions and generates personality-driven commentary. Runs in a tmux pane with ASCII art animation and Rich rendering.

## Table of Contents

* [About](#about)
* [Screenshots](#screenshots)
* [Features](#features)
   * [Core Capabilities](#core-capabilities)
   * [Art Modes](#art-modes)
   * [Technical Excellence](#technical-excellence)
* [Prerequisites](#prerequisites)
* [Installing using uv (recommended)](#using-uv)
* [Installing using pipx](#pipx)
* [Installing for dev mode](#installing-for-dev-mode)
   * [Building the macOS desktop pet](#building-the-macos-desktop-pet)
* [Usage](#usage)
* [CLI Reference](#cli-reference)
   * [Global flags](#global-flags)
   * [tpet new](#tpet-new)
   * [tpet details](#tpet-details)
   * [tpet art](#tpet-art)
   * [tpet run](#tpet-run)
   * [Legacy flags](#legacy-flag-style)
* [Configuration](#configuration)
   * [Pipeline provider configuration](#pipeline-provider-configuration)
   * [General configuration reference](#general-configuration-reference)
* [Environment Variables](#environment-variables)
* [How It Works](#how-it-works)
* [Development](#development)
* [Contributing](#contributing)
* [License](#license)

[![PyPI](https://img.shields.io/pypi/v/term-pet)](https://pypi.org/project/term-pet/)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/term-pet.svg)](https://pypi.org/project/term-pet/)
![Runs on Linux | MacOS | Windows](https://img.shields.io/badge/runs%20on-Linux%20%7C%20MacOS%20%7C%20Windows-blue)
![Arch x86-64 | ARM | AppleSilicon](https://img.shields.io/badge/arch-x86--64%20%7C%20ARM%20%7C%20AppleSilicon-blue)
![PyPI - License](https://img.shields.io/pypi/l/term-pet)

## Screenshots

**ASCII mode — live commentary**

<img src="https://raw.githubusercontent.com/paulrobello/term-pet/main/pet-ascii-screenshot.png" alt="ASCII mode live session" width="600">

**ASCII mode — pet details card**

<img src="https://raw.githubusercontent.com/paulrobello/term-pet/main/pet-ascii-details-screenshot.png" alt="ASCII mode details card" width="600">

**Sixel mode — live commentary**

<img src="https://raw.githubusercontent.com/paulrobello/term-pet/main/pet-sixel-screenshot.png" alt="Sixel mode live session" width="600">

**Sixel mode — pet details card**

<img src="https://raw.githubusercontent.com/paulrobello/term-pet/main/pet-sixel-details-screenshot.png" alt="Sixel mode details card" width="600">

## About

I really liked the idea of the Claude Code buddy so I created my own that supports infinite variations and customization. It even supports watching plain files and commenting on them!

tpet is a CLI application that creates a unique AI-generated pet creature. The pet displays in your terminal using Rich Live rendering, monitors your Claude Code session JSONL files (or plain text files) via watchdog, and produces in-character commentary about your coding sessions.

Built with [Typer](https://typer.tiangolo.com/), [Rich](https://github.com/Textualize/rich), and the [Claude Agent SDK](https://github.com/anthropics/claude-agent-sdk).

[!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://buymeacoffee.com/probello3)

## Features

### Core Capabilities
- **AI-Generated Pets**: Each pet is unique -- name, personality, ASCII art, backstory, and stats all generated by the LLM
- **Personality-Driven Stats**: HUMOR, PATIENCE, CHAOS, WISDOM, SNARK -- generated to match the creature's character and clamped by rarity tier
- **Rarity System**: Common, Uncommon, Rare, Epic, and Legendary tiers determine stat ranges and display colors
- **Session Monitoring**: Watches Claude Code JSONL sessions via watchdog or follows plain text files with `--follow`
- **In-Character Commentary**: Session events trigger personality-driven reactions influenced by the pet's stats
- **Idle Chatter**: When nothing is happening, your pet comments on its own

### Art Modes
- **ASCII (default)**: Character art generated by the LLM, displayed with Rich
- **Sixel Art**: AI-generated sprites rendered as ANSI half-block characters (requires API key)
- **macOS Desktop**: Native AppKit window with your pet walking on your desktop, perching on other apps' window edges, reacting to session events with a speech bubble. See [`macos_desktop/`](macos_desktop/). Requires Swift 5.9+ and macOS 12+. Build once with `make desktop`, then `tpet --art-mode macos-desktop`. Each invocation spawns its own pet — the tray paw icon shows which session and cwd it belongs to.
- **Custom Base Images**: Supply your own idle frame image with `--base-image`

### Technical Excellence
- **No API Key Required**: Commentary and pet generation use your Claude Code subscription via the Agent SDK
- **Per-Pipeline Providers**: Independently configure the provider/model for profile generation, commentary, and image art
- **Multiple Providers**: Claude (Agent SDK), Ollama, OpenAI, OpenRouter, and Google Gemini for any pipeline
- **Non-Blocking Commentary**: Background `ThreadPoolExecutor` keeps the 4fps display smooth during LLM calls
- **YAML Persistence**: Human-readable config and profiles via Pydantic serialization
- **XDG Compliance**: Config and data paths follow XDG base directory conventions

## Prerequisites
* Install and authenticate [Claude Code](https://docs.anthropic.com/en/docs/claude-code) (required for default commentary and pet generation)
* Install Python 3.13 or newer
  * [https://www.python.org/downloads/](https://www.python.org/downloads/) has installers for all platforms
  * On macOS with Homebrew: `brew install python@3.13`

## Using uv

The recommended way to install tpet. If you don't have uv installed:
```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
```

### PyPi install
```bash
uv tool install term-pet
```

To upgrade:
```bash
uv tool install term-pet -U --force
```

### Installing / running using uvx
```bash
uvx --from term-pet tpet
```

### Source install from GitHub
```bash
uv tool install git+https://github.com/paulrobello/tpet
```

To upgrade:
```bash
uv tool install git+https://github.com/paulrobello/tpet -U --force
```

## pipx

### Installing
If you don't have pipx installed:
```bash
pip install pipx
pipx ensurepath
```

### PyPi install
```bash
pipx install term-pet
```

To upgrade an existing installation:
```bash
pipx install term-pet --force
```

### Source install from GitHub
```bash
pipx install git+https://github.com/paulrobello/tpet
```

To upgrade:
```bash
pipx install git+https://github.com/paulrobello/tpet --force
```

## Installing for dev mode

Clone the repo and install in editable mode with `uv`:
```bash
git clone https://github.com/paulrobello/tpet
cd tpet
uv tool install --editable .
```

The installed `tpet` command stays linked to your working tree — edits in `src/` take effect immediately without reinstalling.

To force-refresh after pulling changes:
```bash
uv tool install --editable . --force
```

To uninstall:
```bash
uv tool uninstall term-pet
```

### Building the macOS desktop pet

`--art-mode macos-desktop` spawns a native AppKit binary (`Deskpet`) alongside your tpet session. The Swift sources live in [`macos_desktop/`](macos_desktop/) and must be built once before first use; the Python install does **not** build them automatically.

Requirements:
* macOS 12 or newer
* Swift 5.9+ (ships with recent Xcode / Command Line Tools — `xcode-select --install`)

Build (release):
```bash
make desktop
```

This runs `swift build -c release` inside `macos_desktop/`, producing `macos_desktop/.build/release/Deskpet`.

How tpet finds the binary, in order:

1. `$DESKPET_BIN` — explicit path, useful for testing custom builds.
2. The repo-local release build at `macos_desktop/.build/release/Deskpet` (or the arch-suffixed `…/arm64-apple-macosx/release/Deskpet` / `…/x86_64-apple-macosx/release/Deskpet`). The lookup is anchored to the repo containing `src/tpet/renderer/macos_desktop.py`, so an editable install (`uv tool install --editable .`) keeps it working from any cwd.
3. A `deskpet` binary on `$PATH`.

Run it:
```bash
tpet --art-mode macos-desktop
# or, during development:
make dev
```

Clean Swift build artifacts:
```bash
make desktop-clean
```

## Usage

tpet uses subcommands for distinct operations. The old flag-based style (`--new`, `--details`, `--gen-art`, etc.) still works for backward compatibility.

```bash
# Subcommand style (preferred)
tpet run                        # Start the live pet display (default if no subcommand)
tpet run --follow /path/to/file # Follow a plain text file instead of Claude sessions
tpet new                        # Generate a new pet
tpet new -y                     # Generate without confirmation
tpet new -C "make it a dragon"  # Generate with custom criteria
tpet details                    # Show full pet card
tpet details --backstory        # Show card with backstory
tpet art                        # Generate graphical art for the current pet
tpet art --art-mode sixel-art  # Generate sixel art specifically

# Flag style (backward-compatible)
tpet                            # Start the pet (watches Claude Code sessions)
tpet --new                      # Generate a new pet
tpet --details                  # Show full pet card
tpet --gen-art                  # Generate graphical art
tpet --reset                    # Delete current pet
tpet --reset -y                 # Delete without confirmation
tpet --dump-config              # Show current config
tpet --project /path/to/repo    # Use project-specific pet
tpet --dry-run                  # Validate config and exit
tpet --regen-art                # Regenerate ASCII art for current pet
```

## CLI Reference

### Global flags

| Flag | Short | Description |
|------|-------|-------------|
| `--version` | | Show version |
| `--debug` | `-D` | Enable debug logging |
| `--verbose` | `-v` | Increase verbosity (stackable) |
| `--project` | `-p` | Project directory |
| `--config-dir` | `-c` | Config directory override |

### tpet new
Generate a new pet.

| Flag | Short | Description |
|------|-------|-------------|
| `--create-prompt` | `-C` | Custom criteria for pet generation |
| `--create-prompt-file` | `-F` | File containing custom criteria |
| `--yes` | `-y` | Bypass confirmation prompts |
| `--seed` | `-s` | Random seed for pet generation (defaults to current time) |

### tpet details
Show the pet details card.

| Flag | Short | Description |
|------|-------|-------------|
| `--backstory` | `-b` | Include backstory in card |

### tpet art
Generate graphical art for the current pet.

| Flag | Short | Description |
|------|-------|-------------|
| `--art-mode` | `-a` | Art display mode: `ascii` or `sixel-art` |
| `--art-provider` | `-P` | Image art provider: `openai`, `gemini`, or `openrouter` |
| `--art-model` | | Model for image art generation |
| `--art-width` | `-W` | Max percentage of terminal width for art (1-100) |
| `--art-prompt` | | Custom prompt for image generation |
| `--base-image` | | Custom image to use as idle frame (forces OpenAI edits) |

### tpet run
Start the live pet display (default mode).

| Flag | Short | Description |
|------|-------|-------------|
| `--follow` | `-f` | Follow a plain text file instead of Claude sessions |
| `--watch-dir` | `-w` | Session watch directory override |
| `--commentary-provider` | | Commentary LLM provider: `claude`, `ollama`, `openai`, `openrouter`, or `gemini` |
| `--commentary-model` | | Model for commentary generation |
| `--comment-interval` | `-i` | Min seconds between comments |
| `--idle-chatter-interval` | `-I` | Seconds between idle chatter |
| `--max-comments` | `-M` | Max comments per session |
| `--sleep-threshold` | `-s` | Seconds before sleep animation |
| `--art-mode` | `-a` | Art display mode: `ascii` or `sixel-art` |
| `--log-level` | `-l` | Log level override |
| `--show-session` | | Show resolved session directory and file, then exit |

### Legacy flag-style

The root `tpet` command accepts all flags from every subcommand for backward compatibility. For example, `tpet --new`, `tpet --details`, `tpet --gen-art`, `tpet --reset`, `tpet --regen-art`, `tpet --dump-config`, and `tpet --dry-run` all continue to work as before.

## Configuration

Config file: `~/.config/tpet/config.yaml`

```yaml
# Per-pipeline LLM provider configuration
profile_provider_config:
  provider: claude
  model: claude-haiku-4-5

commentary_provider_config:
  provider: claude
  model: claude-haiku-4-5

image_art_provider_config:
  provider: openai
  model: gpt-image-1.5

# Timing
comment_interval_seconds: 30
idle_chatter_interval_seconds: 300
max_comments_per_session: 0
max_comment_length: 150
max_idle_length: 100
sleep_threshold_seconds: 120

# Animation
idle_duration_seconds: 3.0
reaction_duration_seconds: 0.5
sleep_duration_seconds: 60.0
ascii_art_frames: 6

# Display
art_mode: ascii
art_max_width_pct: 40
art_size: 120
halfblock_size: 48
bubble_placement: bottom

# Art processing
chroma_tolerance: 30
art_dir_path: art
art_prompt: ""

# Logging
log_level: WARNING
log_file: debug.log
```

### Pipeline provider configuration

Each pipeline (`profile_provider_config`, `commentary_provider_config`, `image_art_provider_config`) independently configures its own LLM provider:

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `provider` | string | `claude` | LLM provider: `claude`, `ollama`, `openai`, `openrouter`, or `gemini` |
| `model` | string | *(provider default)* | Model override (empty = provider default) |
| `base_url` | string | *(provider default)* | API base URL override (empty = provider default) |
| `api_key_env` | string | *(provider default)* | Environment variable name for the API key |

Provider defaults:

| Provider | Text default model | Image default model | Default base URL |
|----------|-------------------|---------------------|------------------|
| `claude` | `claude-haiku-4-5` | *(n/a)* | Agent SDK (no URL) |
| `ollama` | `llama3.2` | *(n/a)* | `http://localhost:11434/v1` |
| `openai` | `gpt-4o` | `gpt-image-1.5` | `https://api.openai.com/v1` |
| `openrouter` | `anthropic/claude-haiku-4-5` | `openai/dall-e-3` | `https://openrouter.ai/api/v1` |
| `gemini` | `gemini-2.5-flash` | `gemini-2.5-flash` | Google Genai client |

### General configuration reference

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `comment_interval_seconds` | float | `30.0` | Minimum seconds between event-triggered comments |
| `idle_chatter_interval_seconds` | float | `300.0` | Seconds of inactivity before idle chatter |
| `max_comments_per_session` | int | `0` | Maximum comments per run (0 = unlimited) |
| `max_comment_length` | int | `150` | Character limit for event comments |
| `max_idle_length` | int | `100` | Character limit for idle chatter |
| `log_level` | string | `WARNING` | Log verbosity: `DEBUG`, `INFO`, `WARNING`, `ERROR` |
| `log_file` | string | `debug.log` | Log filename (written inside the config directory) |
| `sleep_threshold_seconds` | int | `120` | Inactivity seconds before sleep animation |
| `idle_duration_seconds` | float | `3.0` | Seconds per idle animation frame cycle |
| `reaction_duration_seconds` | float | `0.5` | Duration of the reaction animation |
| `sleep_duration_seconds` | float | `60.0` | Duration of each sleep animation cycle |
| `ascii_art_frames` | int | `6` | Number of animation frames per pet |
| `art_mode` | string | `ascii` | Display mode: `ascii` or `sixel-art` |
| `art_max_width_pct` | int | `40` | Percentage of terminal width allocated to the art panel |
| `art_size` | int | `120` | Target pixel height for art sprites (multiple of 6) |
| `halfblock_size` | int | `48` | Target pixel height for sixel-art half-blocks (must be even) |
| `chroma_tolerance` | int | `30` | Chroma key removal tolerance for background removal |
| `art_dir_path` | string | `art` | Subdirectory name under config dir for art files |
| `art_prompt` | string | `""` | Custom prompt override for image generation (empty = auto-generate) |
| `bubble_placement` | string | `bottom` | Speech bubble position: `top`, `right`, or `bottom` |

Pet profiles are stored at:
* Global: `~/.config/tpet/profile.yaml`
* Per-project: `<project>/.tpet/profile.yaml`

## Environment Variables

API keys for graphical art generation and third-party providers are read from environment variables. The recommended approach is to place them in `~/.config/tpet/.env`, which tpet loads automatically on every startup.

| Variable | Required for | Description |
|----------|-------------|-------------|
| `OPENAI_API_KEY` | `provider: openai` | OpenAI API key for text or image generation |
| `GEMINI_API_KEY` | `provider: gemini` | Google Gemini API key for text or image generation |
| `OPENROUTER_API_KEY` | `provider: openrouter` | OpenRouter API key for any pipeline |

Example `~/.config/tpet/.env`:

```bash
OPENAI_API_KEY=sk-proj-...
GEMINI_API_KEY=AIza...
OPENROUTER_API_KEY=sk-or-...
```

No API key is required for the default `claude` provider or for ASCII art mode -- the Claude provider uses your Claude Code subscription via the Agent SDK. Ollama runs locally and requires no key.

## How It Works

1. On first run, tpet generates a unique pet using the LLM (name, personality, ASCII art, backstory)
2. Stats (HUMOR, PATIENCE, CHAOS, WISDOM, SNARK) are personality-driven -- generated by the LLM to match the creature's character, then clamped to the rarity range
3. The pet's rarity (Common/Uncommon/Rare/Epic/Legendary) determines stat ranges and display colors
4. By default, tpet monitors your Claude Code session's JSONL files via watchdog (use `--follow` to watch a plain text file instead)
5. Session events trigger in-character commentary influenced by the pet's personality and stats
6. The pet animates through a 6-frame cycle: idle, idle-shift, blink, blink-shift, react, and sleep. Blink frames are generated programmatically by compositing the idle pose with closed eyes from the sleep frame
7. On exit, tpet prints a session summary showing total comments, API calls, token counts, and estimated cost

## Development

```bash
make checkall   # Run all checks (fmt, lint, typecheck, test)
make test       # Run tests only
make lint       # Lint with ruff
make fmt        # Format with ruff
make typecheck  # Type check with pyright
```

### Dev mode
From repo root:
```bash
make dev
```

## Contributing

Please ensure that all pull requests are formatted with ruff, pass ruff lint and pyright.
You can run the make target `checkall` to ensure the pipeline will pass with your changes.

The easiest way to setup your environment:

With uv installed:
```bash
uv tool install pre-commit
```

With pipx installed:
```bash
pipx install pre-commit
```

From repo root:
```bash
pre-commit install
pre-commit run --all-files
```

After running the above, all future commits will auto run pre-commit. Pre-commit will fix what it can and show what remains to be fixed.

## License

MIT -- see [LICENSE](LICENSE) for details.
