diff --git a/docs/v3/guides/gmail.mdx b/docs/v3/guides/gmail.mdx
index 2555346b..4129c641 100644
--- a/docs/v3/guides/gmail.mdx
+++ b/docs/v3/guides/gmail.mdx
@@ -76,11 +76,11 @@ First, test without writing to Honcho:
```bash uv
-uv run gmail_to_honcho.py --dry-run --max-threads 5
+uv run honcho_gmail.py --dry-run --max-threads 5
```
```bash python
-python gmail_to_honcho.py --dry-run --max-threads 5
+python honcho_gmail.py --dry-run --max-threads 5
```
@@ -118,12 +118,12 @@ When ready, run without `--dry-run`:
```bash uv
export HONCHO_API_KEY=your_api_key
-uv run gmail_to_honcho.py --workspace gmail-inbox --max-threads 20
+uv run honcho_gmail.py --workspace gmail-inbox --max-threads 20
```
```bash python
export HONCHO_API_KEY=your_api_key
-python gmail_to_honcho.py --workspace gmail-inbox --max-threads 20
+python honcho_gmail.py --workspace gmail-inbox --max-threads 20
```
@@ -134,31 +134,31 @@ Use Gmail search syntax to filter which threads to load:
```bash uv
# Only emails from a specific sender
-uv run gmail_to_honcho.py --query "from:alice@example.com"
+uv run honcho_gmail.py --query "from:alice@example.com"
# Only emails with a label
-uv run gmail_to_honcho.py --label INBOX
+uv run honcho_gmail.py --label INBOX
# Combine filters
-uv run gmail_to_honcho.py --query "after:2024/01/01 has:attachment" --max-threads 50
+uv run honcho_gmail.py --query "after:2024/01/01 has:attachment" --max-threads 50
```
```bash python
# Only emails from a specific sender
-python gmail_to_honcho.py --query "from:alice@example.com"
+python honcho_gmail.py --query "from:alice@example.com"
# Only emails with a label
-python gmail_to_honcho.py --label INBOX
+python honcho_gmail.py --label INBOX
# Combine filters
-python gmail_to_honcho.py --query "after:2024/01/01 has:attachment" --max-threads 50
+python honcho_gmail.py --query "after:2024/01/01 has:attachment" --max-threads 50
```
## CLI Reference
```
-usage: gmail_to_honcho.py [-h] [--workspace WORKSPACE] [--query QUERY]
+usage: honcho_gmail.py [-h] [--workspace WORKSPACE] [--query QUERY]
[--label LABEL] [--max-threads N] [--dry-run]
[--credentials PATH] [--token PATH]
@@ -196,7 +196,7 @@ Use an AI assistant in your inbox? Want to parse out its messages differently? F
## Full Script
-
+
```python
#!/usr/bin/env python3
"""Load Gmail messages into Honcho.
diff --git a/examples/gmail/honcho_gmail.py b/examples/gmail/honcho_gmail.py
index 4e48f25e..6dce60ee 100644
--- a/examples/gmail/honcho_gmail.py
+++ b/examples/gmail/honcho_gmail.py
@@ -30,6 +30,7 @@ from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
SCOPES = ["https://www.googleapis.com/auth/gmail.readonly"]
+PEER_ID_PATTERN = re.compile(r"^[a-zA-Z0-9_-]+$")
def find_credentials() -> str:
@@ -174,7 +175,14 @@ def parse_address_list(header: str) -> list[str]:
def peer_id_from_email(email: str) -> str:
"""Convert email to a valid Honcho peer ID."""
- return email.replace("@", "-").replace(".", "-")
+ peer_id = re.sub(r"[^A-Za-z0-9_-]+", "-", email).strip("-").lower()
+ peer_id = re.sub(r"-{2,}", "-", peer_id)
+ if not peer_id:
+ peer_id = "unknown-peer"
+
+ if not PEER_ID_PATTERN.fullmatch(peer_id):
+ raise ValueError(f"Generated peer ID is invalid: {peer_id!r}")
+ return peer_id
def fetch_thread_messages(service, thread_id: str) -> list[dict]:
@@ -264,7 +272,7 @@ def main():
# Summary
total_msgs = sum(len(v) for v in all_thread_messages.values())
- print(f"\nSummary:")
+ print("\nSummary:")
print(f" Threads: {len(all_thread_messages)}")
print(f" Messages: {total_msgs}")
print(f" Unique participants: {len(seen_peers)}")