Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .claude/commands/rtw-help.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
description: Show all RTW commands and domain primer
argument-hint: [topic]
model: haiku
allowed-tools: Read, Glob, Grep
---

# RTW Command Help

Show available commands and optionally provide a domain primer.

## Step 1: List All Commands

Read the YAML frontmatter `description:` field from each file in `.claude/commands/rtw-*.md`. Organize into two categories:

**Domain Workflow** (interactive, for trip planning):
- `/rtw-plan` — [read description from frontmatter]
- `/rtw-search` — [read description from frontmatter]
- `/rtw-analyze` — [read description from frontmatter]
- `/rtw-booking` — [read description from frontmatter]
- `/rtw-compare` — [read description from frontmatter]
- `/rtw-lookup` — [read description from frontmatter]

**Developer Tools** (fast, for project health):
- `/rtw-verify` — [read description from frontmatter]
- `/rtw-status` — [read description from frontmatter]
- `/rtw-setup` — [read description from frontmatter]
- `/rtw-help` — [read description from frontmatter]

Show the typical workflow:
```
Plan → Search → Verify (D-class) → Analyze → Book
```

## Step 2: Topic Deep Dive (if argument provided)

If `$ARGUMENTS` contains a topic keyword, provide a brief primer:

**"domain"** or **"basics"**: Explain oneworld Explorer RTW tickets, Rule 3015, ticket types (DONE/LONE), tariff conferences (TC1/TC2/TC3), and the booking process (call AA desk).

**"carriers"**: List oneworld carriers relevant to RTW: BA, QF, CX, JL, AA, QR, IB, AY, MH, RJ, SriLankan, FJ, LATAM. Note which have high/low YQ surcharges.

**"ntp"**: Explain BA New Tier Points — how they're earned on RTW tickets, which segments earn most, and the NTP calculation formula.

**"verify"** or **"dclass"**: Explain D-class availability, ExpertFlyer, what D0-D9 means, and how the verify command works.

If no argument, just show the command list.
130 changes: 130 additions & 0 deletions .claude/commands/rtw-init.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
---
description: First-time credential and environment setup
allowed-tools: Bash(python3 *), Bash(uv *), Bash(which *), Bash(echo *), AskUserQuestion, Read, Write
---

# RTW Optimizer — First-Time Initialization

Check all required credentials and services, guide the user through setting up anything missing.

## Step 1: Check Python & Dependencies

Run: `python3 --version` and check output contains "3.11" or higher.

If Python is missing or too old, stop and explain the requirement.

Run: `uv sync` to ensure all dependencies are installed.

## Step 2: Check SerpAPI Key

Run: `python3 -c "import os; key = os.environ.get('SERPAPI_API_KEY', ''); print('configured' if key else 'missing')"`

**If configured**: Report "SerpAPI: configured" and move on.

**If missing**: Explain to the user:

```
SerpAPI is used for Google Flights pricing searches.
Free tier: 100 searches/month at https://serpapi.com

To set up:
1. Sign up at https://serpapi.com (free account)
2. Copy your API key from the dashboard
```

Use AskUserQuestion:
- header: "SerpAPI"
- question: "Do you have a SerpAPI key to configure?"
- options:
- label: "Yes, I have a key"
description: "I'll paste my API key"
- label: "Skip for now"
description: "I'll set it up later. Google Flights pricing won't work."
- multiSelect: false

If "Yes": Ask the user to provide their key, then instruct them:

```
Add this to your shell profile (~/.zshrc or ~/.bashrc):

export SERPAPI_API_KEY=your_key_here

Then restart your terminal or run: source ~/.zshrc
```

Write the export line for them. Run:
`python3 -c "import os; os.environ.get('SERPAPI_API_KEY') or print('Note: key will be available after restarting terminal')"`

If "Skip": Note that `/rtw-search` will work without pricing data (uses `--skip-availability`), and `/rtw-scrape` won't work.

## Step 3: Check ExpertFlyer Credentials

Run: `python3 -m rtw login status --json 2>/dev/null || echo '{"has_credentials": false}'`

Parse the JSON output.

**If has_credentials is true**: Report "ExpertFlyer: configured (username)" and move on.

**If missing**: Explain to the user:

```
ExpertFlyer is used for D-class seat availability checking.
Requires a paid subscription at https://www.expertflyer.com

This is optional — the optimizer works without it, but you won't
be able to verify which flights actually have D-class seats available.
```

Use AskUserQuestion:
- header: "ExpertFlyer"
- question: "Do you have an ExpertFlyer account to configure?"
- options:
- label: "Yes, set up now"
description: "I have an ExpertFlyer account and want to store credentials"
- label: "Skip for now"
description: "I don't have ExpertFlyer. D-class verification won't work."
- multiSelect: false

If "Yes": Run `python3 -m rtw login expertflyer` which will interactively prompt for email and password, store them in the system keyring, and test the login.

If the login test succeeds, also check if Playwright's Chromium is installed:
Run: `python3 -c "from playwright.sync_api import sync_playwright; print('installed')" 2>/dev/null || echo "missing"`

If Playwright Chromium is missing:
Run: `uv run playwright install chromium`

If "Skip": Note that `/rtw-verify` (D-class) won't work, but all other commands function normally.

## Step 4: Quick Smoke Test

Run: `python3 -m rtw --help > /dev/null 2>&1 && echo "CLI: working" || echo "CLI: broken"`

Run: `uv run pytest -x -q -m "not slow and not integration" 2>&1 | tail -3`

## Step 5: Summary

Present a status dashboard:

```
RTW Optimizer — Initialization Complete
========================================
Python: [version]
Dependencies: installed
SerpAPI: [configured / not configured]
ExpertFlyer: [configured (email) / not configured]
Playwright: [installed / not installed]
Tests: [N passed]

Available features:
[✓ or ✗] Route search with pricing (needs SerpAPI)
[✓ or ✗] D-class verification (needs ExpertFlyer + Playwright)
[✓] Itinerary validation (always available)
[✓] Cost estimation (always available)
[✓] NTP calculation (always available)
[✓] Booking script generation (always available)
```

Suggest next step based on what's configured:
- If everything configured: "You're all set! Run `/rtw-plan` to start planning your trip."
- If SerpAPI only: "Run `/rtw-plan` to start planning. Add ExpertFlyer later for D-class checks."
- If nothing configured: "The core optimizer works without external services. Run `/rtw-plan` to start."
60 changes: 60 additions & 0 deletions .claude/commands/rtw-setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
description: Set up development environment
allowed-tools: Bash(uv *), Bash(python3 *), Bash(which *), Read
---

# Environment Setup

First-time setup wizard for the RTW Optimizer. Run each step and report status.

## Step 1: Install Dependencies

Run: `uv sync`

If this fails, check:
- Is `uv` installed? (`which uv`)
- Is Python 3.11+ available? (`python3 --version`)

Report: installed package count or error.

## Step 2: Verify CLI

Run: `python3 -m rtw --help`

Confirm the CLI loads and shows the command list. If it fails, suggest `uv sync` or check Python version.

Report: pass/fail with command count.

## Step 3: Optional — Playwright for ExpertFlyer

Check if Playwright is installed: `python3 -c "import playwright" 2>/dev/null`

If not installed, mention:
"Optional: For D-class availability checking via ExpertFlyer, install Playwright:"
```
uv run playwright install chromium
```

This is only needed for the `verify` command. Skip if not using ExpertFlyer.

## Step 4: Quick Test Run

Run: `uv run pytest -x -q -m "not slow and not integration" 2>&1 | tail -5`

Report: tests passed/failed.

## Summary

```
Setup Complete
==============
Dependencies: [installed]
CLI: [working — N commands]
Playwright: [installed / not installed (optional)]
Tests: [N passed]
```

Suggest next step:
- If no ExpertFlyer credentials: "Run `python3 -m rtw login expertflyer` to set up D-class checking"
- If no trip state: "Run `/rtw-plan` to start planning your RTW trip"
- If returning user: "Run `/rtw-status` to see where you left off"
56 changes: 56 additions & 0 deletions .claude/commands/rtw-status.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
description: Show project status and trip planning state
model: haiku
allowed-tools: Bash(git *), Bash(python3 -m rtw*), Bash(uv run pytest*), Bash(ls *), Bash(wc *), Bash(cat *), Read
---

# Project Status Dashboard

Show a quick orientation dashboard. Keep output compact and scannable.

## Step 1: Git Status

Run: `git branch --show-current` and `git log --oneline -5`

Show current branch and last 5 commits.

## Step 2: Test Count

Run: `uv run pytest --collect-only -q 2>&1 | tail -1`

Show total test count.

## Step 3: ExpertFlyer Credentials

Run: `python3 -m rtw login status --json 2>/dev/null || echo '{"has_credentials": false}'`

Show whether ExpertFlyer credentials are configured.

## Step 4: Trip Planning State

Check if `.claude/rtw-state.local.md` exists. If it does, read it and show:
- Current stage (planning, search-complete, analyzed, booking-ready)
- Origin, ticket type, cities

If no state file, show "No active trip plan. Run `/rtw-plan` to start."

## Step 5: Last Search

Check if `~/.rtw/last_search.json` exists. If it does, show its age (file modification time) and a 1-line summary.

If the file is older than 24 hours, note: "Search results are stale — consider re-running `/rtw-search`."

## Report Format

```
RTW Optimizer Status
====================
Branch: [branch-name]
Tests: [N] collected
ExpertFlyer: [configured / not configured]
Trip state: [stage or "no active plan"]
Last search: [age, summary or "none"]

Recent commits:
[last 5 commits]
```
43 changes: 43 additions & 0 deletions .claude/commands/rtw-verify.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
description: Run tests and lint checks
model: haiku
allowed-tools: Bash(uv run pytest*), Bash(uv run ruff*), Bash(ruff *)
---

# Project Verification

Run the test suite and lint checks. Report a clear pass/fail summary.

## Step 1: Run Tests

Run: `uv run pytest -x -q`

Capture the output. Note:
- Total tests passed/failed/skipped
- If any failures, show the first failure with file path and assertion

## Step 2: Run Lint

Run: `ruff check rtw/ tests/`

Capture the output. Note:
- Total errors found (or clean)
- If errors, show the first 5 with file:line and rule code

## Step 3: Report Summary

Present a compact checklist:

```
Project Verification
====================
Tests: [PASS NN passed] or [FAIL NN passed, NN failed]
Lint: [PASS clean] or [FAIL NN errors]
```

If everything passes, say "All clear — safe to commit."

If anything fails:
- Show the specific failures
- Suggest the fix command (e.g., `ruff check --fix rtw/` for auto-fixable lint)
- For test failures, suggest running the specific test file with `-x -v` for details
15 changes: 15 additions & 0 deletions .claude/rules/rules-engine.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
paths:
- "rtw/rules/**"
---

# Rules Engine Guidelines

- NEVER invent or guess fare rule constraints. All rules derive from IATA Rule 3015.
- Before modifying any rule, read `docs/01-fare-rules.md` for the authoritative source text.
- For optimization context, see `docs/12-rtw-optimization-guide.md`.
- Each rule is a function in a separate file: `segments.py`, `carriers.py`, `direction.py`, etc.
- Rules return a list of `RuleResult` with severity: `error` (blocks validation) or `warning` (informational).
- The validator (`rtw/validator.py`) builds a `ValidationContext` then calls each rule. Rules do NOT call each other.
- Continent assignments use `rtw/continents.py` overrides (e.g., Egypt = EU_ME, Guam = Asia). Never hardcode continent for an airport.
- Test rule changes with: `uv run pytest tests/test_rules/ -x`
16 changes: 16 additions & 0 deletions .claude/rules/testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
paths:
- "tests/**"
---

# Testing Conventions

- NEVER use mocks for API responses or domain logic. Tests use real data from `tests/fixtures/`.
- Mocks are ONLY acceptable for: system keyring access, ExpertFlyer HTTP sessions, and external service credentials.
- Test files mirror source structure: `rtw/cost.py` → `tests/test_cost.py`, `rtw/rules/segments.py` → `tests/test_rules/test_segments.py`
- Use `pytest.approx()` for floating-point comparisons (costs, distances, percentages).
- Fixtures live in `tests/fixtures/` as YAML files. Load them with `Path(__file__).parent / "fixtures" / "name.yaml"`.
- Mark slow tests with `@pytest.mark.slow`, integration tests with `@pytest.mark.integration`.
- Run focused: `uv run pytest tests/test_cost.py -x` (one file, stop on first failure).
- Run fast: `uv run pytest -m "not slow and not integration" -x`
- All models are Pydantic v2 — test serialization with `model_dump(mode="json")` and `model_validate(data)`.
23 changes: 23 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"permissions": {
"allow": [
"Bash(uv run pytest*)",
"Bash(uv run ruff*)",
"Bash(uv sync*)",
"Bash(python3 -m rtw*)",
"Bash(python3 -c *)",
"Bash(ruff *)",
"Bash(git *)",
"Bash(which *)",
"Bash(ls *)",
"Bash(cat *)",
"Bash(head *)",
"Bash(wc *)"
],
"deny": [
"Bash(rm -rf *)",
"Bash(git push --force*)",
"Bash(git reset --hard*)"
]
}
}
Loading
Loading