# pi-charles

[English](./README.md) | [中文](./README.zh-CN.md)

**Charles Proxy analysis tools for the [pi](https://pi.dev) coding agent.**

npm package: [`pi-charles`](https://www.npmjs.com/package/pi-charles)

Design principle: tools only fetch, filter, and present data. Reasoning stays with the agent.

## How it works

### Checkpoint timeline

Each `harvest_data()` call:

1. Exports the current Charles session
2. Keeps only entries newer than the last harvest (by `times.start` millis)
3. Stores them in an in-memory **ARCHIVE**
4. Appends a **checkpoint** on the timeline
5. Clears the Charles session and restarts recording (keeps exports small)

Use `load_checkpoint(n)` to jump back to any historical window. All filter tools then operate on that window.

### Resource placeholders

Image / JS / CSS / binary bodies are replaced with placeholders like `[image/png 45.2KB]`. The agent sees type and size, then calls `get_raw_data` only when needed.

### Keyword interlock

If `filter_by_keyword` matches more than 30 entries, you must call `check_keyword_exists` first. This avoids dumping large bodies into the context window.

## Prerequisites

Charles Proxy running with Web Interface enabled: **Proxy → Web Interface Settings**

- Enable **Web interface**
- Default is **no user/password** (anonymous). Set via `/charles` or `CHARLES_USER`/`CHARLES_PASS` env vars.

## Install

### npm (recommended)

```bash
pi install npm:pi-charles
```

### Git

```bash
pi install git:github.com/geebos/pi-charles
pi install git:github.com/geebos/pi-charles@v1.0.0
```

### GitHub Packages (optional)

Published as `@geebos/pi-charles` (scoped for the registry):

```bash
# ~/.npmrc
# @geebos:registry=https://npm.pkg.github.com
# //npm.pkg.github.com/:_authToken=YOUR_GITHUB_TOKEN

pi install npm:@geebos/pi-charles
```

### Local development

```bash
git clone https://github.com/geebos/pi-charles.git
cd pi-charles
npm install
pi -e ./extensions/index.ts
# or
pi install ./
```

## Configuration: `/charles`

Configure the Charles connection from inside pi (English UI copy):

```text
/charles              Open settings UI (TUI)
/charles show         Show current settings
/charles test         Test Charles connection
/charles reset        Reset to defaults
/charles set user <v> Set username
/charles set pass <v> Set password
/charles set host <v> Set proxy host
/charles set port <v> Set proxy port
```

| Setting | Default | Description |
| --- | --- | --- |
| Username | (empty) | Charles Web Interface username (optional) |
| Password | (empty) | Charles Web Interface password (optional) |
| Proxy host | `control.charles` | Host where the Charles HTTP proxy listens |
| Proxy port | `80` | Port where the Charles HTTP proxy listens |

Settings are saved to `~/.pi/agent/extensions/pi-charles/config.json` and apply immediately.

Priority: **environment variables > config file > defaults**.

## Tools

### Harvest

| Tool | Description |
| --- | --- |
| `harvest_data(fresh_start?)` | Incremental harvest + checkpoint. `fresh_start=true` inserts a reset point |
| `load_recording(file_path)` | Load a local `.chlsj` recording |

### Timeline

| Tool | Description |
| --- | --- |
| `list_checkpoints()` | List all checkpoints |
| `load_checkpoint(checkpoint_id)` | Switch the visible window to a checkpoint |

### Overview

| Tool | Description |
| --- | --- |
| `summarize_traffic()` | Host / path / status / method distribution |

### Filters

| Tool | Description |
| --- | --- |
| `filter_by_host(host_keyword)` | Filter by host |
| `filter_by_path(path_keyword)` | Filter by URL path |
| `filter_by_method(method)` | Filter by HTTP method |
| `filter_by_status(status_code)` | Filter by HTTP status |
| `check_keyword_exists(keyword)` | Probe keyword locations; unlocks `filter_by_keyword` |
| `filter_by_keyword(keyword)` | Entries containing the keyword (preview) |
| `filter_by_encryption(threshold?)` | Shannon-entropy scan for likely encrypted bodies |

### Detail / environment

| Tool | Description |
| --- | --- |
| `get_raw_data(entry_id)` | Full raw entry |
| `set_throttling(preset?)` | Enable / disable Charles throttling (auto-restored on session end) |

## Typical workflow

```text
harvest_data()
summarize_traffic()
filter_by_host("api.xxx")
filter_by_encryption()
get_raw_data(entry_id)
```

Switch analysis target:

```text
harvest_data({ fresh_start: true })
# trigger the target action in the app
harvest_data()
```

Rewind history:

```text
list_checkpoints()
load_checkpoint({ checkpoint_id: 2 })
filter_by_keyword({ keyword: "sign" })
```

## Environment variables

| Variable | Default | Description |
| --- | --- | --- |
| `CHARLES_USER` | `pi-charles` | Web Interface username |
| `CHARLES_PASS` | `123456` | Web Interface password |
| `CHARLES_PROXY_HOST` | `127.0.0.1` | Proxy host |
| `CHARLES_PROXY_PORT` | `8888` | Proxy port |

## Publishing

Pushing a version tag runs two workflows (tag-only; no double-fire with Releases):

| Workflow | Registry | Package name |
| --- | --- | --- |
| **Publish to npm** | npmjs.com | `pi-charles` |
| **github-publish** | GitHub Packages | `@geebos/pi-charles` |

```bash
git tag v1.0.0
git push origin v1.0.0
```

Manual re-publish of an existing tag: Actions → workflow → **Run workflow** → enter `v1.0.0`.

### npm Trusted Publishing (no token)

`Publish to npm` uses [Trusted Publishing](https://docs.npmjs.com/trusted-publishers) (OIDC). Do **not** set `NPM_TOKEN`.

Configure once on npmjs.com → **pi-charles** → **Settings** → **Trusted Publisher**:

| Field | Value |
| --- | --- |
| Provider | GitHub Actions |
| Organization or user | `geebos` |
| Repository | `pi-charles` |
| Workflow filename | `publish-npm.yml` |
| Allowed actions | `npm publish` |

Requirements: Node 24 / npm ≥ 11.5.1 (set in the workflow), `permissions.id-token: write`.

### GitHub Packages

Uses the automatic `GITHUB_TOKEN` with `packages: write`. No extra secret.

## Credits

Migrated from the Python FastMCP project
[tianhetonghua/Charles-mcp-server](https://github.com/tianhetonghua/Charles-mcp-server)
to a TypeScript [pi](https://pi.dev) package.

## License

[MIT](./LICENSE)
