# HUMAN.md

Guidance for working effectively with Claude Code on this repository.

## Understand the Layers Before Asking

This codebase has distinct concerns that Claude handles best when you name the layer explicitly:

- **Strategy logic** — `services/paper-executor/src/strategy/`
- **Execution & scheduling** — `services/paper-executor/src/worker.rs`, `runner.rs`
- **API endpoints** — `services/api/src/handlers/`
- **Database models & queries** — `crates/swym-dal/src/`
- **Historical ingestion** — `services/ingest-binance/`
- **Live market data** — `services/market-worker/`
- **Dashboard UI** — `dashboard/src/`

If you say "add X to the system" without naming a layer, Claude will have to infer — and may guess wrong. Say "add X to the API handler" or "add X to the paper executor strategy" instead.

## Be Specific About What You Want Changed

Claude avoids over-engineering. It will implement exactly what you ask — no more, no less. Vague prompts produce minimal scaffolding. Specific prompts produce working implementations.

| Vague | Better |
|---|---|
| "improve the strategy" | "add a configurable minimum spread threshold to SimpleSpread that skips trades below it" |
| "show more data on the dashboard" | "add a trades-per-minute sparkline to the run detail page using the existing market data" |
| "fix the ingestion" | "the ingest-binance parser is misclassifying trade side — describe what you see in parser.rs and what should change" |

## Providing Context for Database Work

sqlx validates queries at compile time against a live database (`DATABASE_URL`). When asking for database changes, say:

- Whether you need a new migration or just a new query on existing schema
- The table names involved (Claude can look them up in `crates/swym-dal/src/models/`)
- Whether this is a new model, a new repo method, or a change to an existing one

Example: "Add a `notes` text field to `paper_runs`. I need a migration, a model change in swym-dal, and a new optional field in the API create handler."

## Adding a New Trading Strategy

The strategy system is the most complex part of the executor. Give Claude:

1. A name for the strategy
2. What market signal it reacts to (spread, momentum, volume, etc.)
3. What config fields it needs (thresholds, periods, etc.)
4. How it should size positions

Then Claude can model it after `SimpleSpread` or `SwyStrategy` and wire it into the `strategy_config` dispatch in `runner.rs`.

## Dashboard Work

The dashboard is React 19 + TypeScript + Vite + TanStack Query. API responses flow through `dashboard/src/api/`. When asking for UI changes:

- Name the page or component (e.g. "the run detail page", "the market subscriptions table")
- Describe the data source (existing API endpoint, or does one need to be added?)
- If you want a chart, say what library you want or let Claude pick from what's already used

## Asking Claude to Explore Before Acting

For unfamiliar subsystems, ask Claude to explain before it changes anything:

> "Read `services/paper-executor/src/runner.rs` and explain how a run moves from `queued` to `complete` before making any changes."

This gives you a chance to correct Claude's understanding and produces better implementations.

## Constraints Claude Tracks Automatically

These are real constraints that will cause build or runtime failures — Claude knows about them but will do better if you don't contradict them:

- **barter-rs is a local path dependency** at `../../barter-rs/barter-rs/`. Don't ask Claude to add it from crates.io.
- **sqlx compile-time checks** require `DATABASE_URL` to be set. If you ask Claude to add queries without a running DB, the build will fail.
- **Services use `FOR UPDATE SKIP LOCKED`** for concurrency safety in the executor. Don't simplify that away.
- **Migrations run automatically** on service startup via `run_migrations()`. There's no separate migration step.

## Specifying Scope: What NOT to Change

Claude respects explicit scope limits. If you only want a change in one service:

> "Only change `services/paper-executor/`. Don't touch swym-dal or the API."

Or if you want a focused change without refactoring:

> "Add the field without refactoring the surrounding code."

## Common High-Value Prompt Patterns

**New API endpoint:**
> "Add a `GET /paper-runs/:id/trades` endpoint to swym-api that returns the market trades that occurred during a run's time window for its configured instruments. Add the repo method to swym-dal."

**New strategy config field:**
> "Add a `max_position_size: Decimal` field to `SwyStrategy`'s config. Default it to 1.0. Enforce it in the position sizing logic in `swym_strategy.rs`."

**Backfill investigation:**
> "Look at `ingest-binance/src/fetcher.rs` and explain how it decides between monthly and daily files. Then tell me what would need to change to support hourly files."

**Dashboard data display:**
> "Add a summary card to the run list page showing total completed runs, total failed runs, and aggregate PnL across all runs. Use the existing `/api/paper-runs` endpoint."

**Migration + model change:**
> "Add a `tags` text array column to `paper_runs`. Write the migration, update the model in swym-dal, expose it in the API response, and filter by tag in the list endpoint."

## What Claude Won't Do Without Being Asked

- It won't add logging, metrics, or observability unless you ask.
- It won't write tests unless you say "write tests for this".
- It won't update the dashboard when you change the API (or vice versa) unless you ask it to do both.
- It won't deploy or run services — it will tell you the command to run.
- It won't commit changes unless you say "commit this".
