cfb-picks

stale personal private

CFB Handicapping

README

# Ken's CFB Handicapper Backend (FastAPI)

Real-time middleware that fetches **live odds** (The Odds API) and **team data** (CFBD) and applies **Ken's custom handicapping rules** (injuries > situational > matchup > big plays > weather triggers > ratings delta).

## 1) Setup

### Prereqs
- Python 3.11+
- API keys:
  - CFBD: https://collegefootballdata.com/key
  - The Odds API: https://the-odds-api.com/

### Install
```bash
python -m venv .venv
source .venv/bin/activate  # Windows: .venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env
# Edit .env to add your keys
```

### Run locally
```bash
uvicorn app.main:app --reload --port 8000
# Test:
curl "http://127.0.0.1:8000/health"
```

## 2) Configuration
Edit `app/config.yaml` to tweak weights, thresholds, and your philosophy. The defaults reflect Ken's priors: heavy **injury weighting**, **situational**, **matchups**, explicit **big plays** factor, weather as **trigger-only**, no ATS for sides, totals trends as **tiebreaker**.

## 3) Deploy (Render example)
- Push this folder to a new GitHub repo
- Create a **Web Service** on Render
  - Build command: `pip install -r requirements.txt`
  - Start command: `uvicorn app.main:app --host 0.0.0.0 --port $PORT`
  - Add environment variables:
    - `CFBD_KEY`
    - `ODDS_KEY`
    - `PRIMARY_BOOK_KEYWORD` (e.g., `DraftKings`)
    - `ALLOWED_BOOKS` (comma list)
- Copy the deployed URL (e.g., `https://ken-cfb.onrender.com`)

## 4) Connect as a Custom GPT Action
- Open **ChatGPT → Create a GPT → Configure → Actions → Add API schema**
- Upload `openapi.yaml`
- Replace `https://YOUR_DEPLOY_URL` with your deployed base URL.
- Save.

Now your GPT can call:
```
GET /analyze?home=Georgia&away=Alabama&date=2025-11-08
```
It will return:
- Selected book lines (spread, total, moneyline)
- Model line & total per your config
- Edges in points vs book
- **Unit-sized recommendations** based on your 1u/2u rules

## 5) Injuries, Situational, Big Plays (Inputs)
The `/analyze` e

…(truncated for upload size)

STATUS

---
type: project-status
project: cfb-picks
last_updated: 2026-04-27
---

# STATUS — cfb-picks

*The freshest file. Answers "where am I on this project?" Updated at the end of every substantive session.*

---

## Current state

<One short paragraph: what state is the project in right now? Mid-build? Shipped MVP? Stalled waiting on something? Be concrete.>

## In progress

- [ ] <What's actively being worked on. If nothing, write "Nothing in flight.">

## Next up

1. <The next thing to pick up when work resumes.>
2. <The thing after that, if obvious.>

## Blocked / waiting on

<External dependencies, decisions you need from someone, vendor responses, etc. "Nothing blocking" is a fine answer.>

## Known issues

<Bugs you know about but haven't fixed, edge cases not yet handled, debt you've taken on. Be specific so future-you doesn't get blindsided.>

## Recent wins

- 2026-04-27: <What was completed in the last session or two. Concrete, with dates.>

## Last session recap

*2026-04-27* — <One paragraph: what got done, what was learned, anything surprising. Read this first when picking up the project after a break.>

DECISIONS

---
type: project-decisions
project: cfb-picks
last_updated: 2026-04-27
---

# DECISIONS — cfb-picks

*Architectural and scope choices. Append-only log. Each entry is a decision that shouldn't be re-litigated without new information. If you find yourself reopening a decision, either add a new entry that overrides the old (and say why) or leave both so the history is visible.*

---

## How to use this file

Each decision gets a dated entry with: what was decided, why, what was considered instead, and what would change our mind. Never delete entries — if a decision is reversed, add a new one that supersedes it.

---

## 2026-04-27 — <Short decision title>

**Decision:** <what we chose>

**Context:** <the problem or question that forced a choice>

**Alternatives considered:** <what else was on the table and why we passed>

**Reasoning:** <why this option won>

**Would reconsider if:** <what new information would flip this>

---

## 2026-04-27 — <Short decision title>

**Decision:**

**Context:**

**Alternatives considered:**

**Reasoning:**

**Would reconsider if:**

---

<!-- Append new entries at the top. Older decisions remain below. -->

MEMORY

---
type: project-memory
project: cfb-picks
last_updated: 2026-04-27
---

# MEMORY — cfb-picks

*Standing facts, preferences, and accumulated context. Long-lived — not "what I did yesterday" (that's STATUS.md). Update when you learn something worth keeping.*

---

## Purpose and scope

<Why this app exists, who uses it, what problem it solves. 2-3 sentences max.>

## Domain knowledge

<Rules of the domain that Claude should know before making changes. For tax apps: the specific IRS rules this module implements, state conformity notes, edge cases. For non-tax apps: business rules, workflows, naming conventions specific to this app's world.>

## User preferences discovered

<Things Ken has said he prefers, or patterns that work / don't work. Example: "Ken prefers server-rendered HTML over SPAs for internal tools." "Don't auto-format tax return numbers with commas on input, only on display.">

## Integrations and external systems

<APIs, webhooks, third-party services this app talks to. Auth patterns, rate limits, quirks.>

## Gotchas and lessons learned

<The things that have bitten us. Non-obvious behavior, debugging dead-ends, environment quirks. Write these when they happen so the next session doesn't repeat the mistake.>

## Data model highlights

<Key tables/models and what's non-obvious about them. Don't duplicate the schema — reference it. Focus on the things you'd warn someone about.>

CLAUDE.md

# CLAUDE.md — cfb-picks

*Project-specific rules. User-level conventions come from `~/.claude/CLAUDE.md` — do not duplicate here.*

---

## What this is

<One sentence: what the app does and who it's for. Example: "Django client portal for Ken's CPA practice — lets clients log in, view documents, and message the firm.">

## Tech stack

- **Backend:** <framework + version>
- **Frontend:** <framework or "server-rendered templates">
- **Database:** <Supabase Postgres | SQLite | none>
- **Hosting:** <Render | local only | not deployed>
- **Dependencies:** <Poetry | pip | npm>

## Session startup

<Anything CC must read at session start — specific memory files, design docs, etc. Leave empty if just the four root files.>

## Conventions

- Follow sherpa-family conventions from `~/.claude/CLAUDE.md`.
- <Project-specific rule #1>
- <Project-specific rule #2>

## Do not redesign without asking

<What's working that shouldn't be touched. UI theme, color system, data model, API shape, etc. Be specific.>

## Known constraints

<Integration requirements, compliance rules, client commitments. Tax law accuracy rules, IRS verification, etc.>

Diary mentions

No recent diary mentions for this app.