Thesis
by Bilaltariq98
README.md
# Thesis
Self-hosted per-ticker research workspace for retail investors. Capture content from anywhere via the PWA share sheet. The workspace exposes an MCP server so your own agent (Claude, ChatGPT, Codex CLI) does the synthesis. Single-user MVP — your data stays in your Cloudflare account.
> Research aid, not advice. The agent writes; you decide.
## Architecture
```
┌─────────────────────────────────────────────────────────────┐
│ Browser / Mobile │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ PWA (Vite + React + Tailwind) │ │
│ │ - Web Share Target - Workspace tabs │ │
│ │ - Tiptap rich text - Component renderer │ │
│ └────────────────────┬─────────────────────────────────┘ │
└───────────────────────┼─────────────────────────────────────┘
│ /api/* /mcp
┌───────────────────────▼─────────────────────────────────────┐
│ Cloudflare Worker (Hono) │
│ ┌───────────────────────────────┐ ┌──────────────────┐ │
│ │ Workspace Durable Object │ │ WorkspaceAgent │ │
│ │ SQLite + embedding BLOB │ │ DO (Slice 4) │ │
│ │ 30 MCP tools │ │ nightly cron │ │
│ └───────────────────────────────┘ └──────────────────┘ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Data providers │ │
│ │ Yahoo Stooq EDGAR Finnhub FRED │ │
│ └───────────────────────────────────────────────────────┘ │
│ ┌──────────────┐ ┌────────────┐ ┌──────────────────────┐ │
│ │ R2 (docs) │ │ KV cache │ │ CF AI Gateway │ │
│ └──────────────┘ └────────────┘ └──────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Future:
┌─────────────────────────┐
│ Auth app (Slice 5) │
│ better-auth + Postgres │
│ Docker → Fly.io │
└─────────────────────────┘
```
## Quick start
```bash
git clone <repo> && cd invest
npm install
cp apps/worker/.dev.vars.example apps/worker/.dev.vars
# Edit apps/worker/.dev.vars — set THESIS_BEARER_TOKEN, optionally FINNHUB_API_KEY + FRED_API_KEY
# Terminal 1 — worker on :8787
npm run dev:worker
# Terminal 2 — PWA on :5173 (proxies /api and /mcp to :8787)
npm run dev:pwa
```
Open http://localhost:5173. Add a bearer token in **Settings** (use the value from `.dev.vars`).
### Connect an agent (BYOA)
`GET /api/mcp-info` returns the MCP endpoint, tool list, and auth instructions. The Settings page renders the same info with copy-ready URLs.
- **Streamable HTTP** (preferred): `POST /mcp`, `GET /mcp`
- **Legacy SSE**: `GET /mcp/sse`, `POST /mcp/messages`
- **Auth**: `Authorization: Bearer <token>` or `?token=<token>`
## Env vars
All secrets go in `apps/worker/.dev.vars` for local dev. See [`apps/worker/.dev.vars.example`](apps/worker/.dev.vars.example).
| Var | Required | Notes |
|---|---|---|
| `THESIS_BEARER_TOKEN` | Yes | Shared secret for all API + MCP requests |
| `FINNHUB_API_KEY` | Optional | Free at finnhub.io — enables fundamentals, earnings, news |
| `FRED_API_KEY` | Optional | Free at fred.stlouisfed.org — enables macro tiles |
| `STOOQ_API_KEY` | Optional | 2025 captcha gate — skip to use Yahoo fallback |
| `ANTHROPIC_API_KEY` | Slice 4 | Required for embedded agent nightly runs |
| `CF_AIG_TOKEN` | Slice 4 | Cloudflare AI Gateway token |
| `CF_ACCOUNT_ID` | Slice 4 | Your CF account ID |
| `AGENT_MONTHLY_TOKEN_CAP` | Optional | Default 200000 tokens/month per workspace |
## Slices shipped
Full decision log and slice history: [`docs/roadmap/GRILL-ME.md`](docs/roadmap/GRILL-ME.md)
| Slice | Description | Status |
|---|---|---|
| W0–W5 | Foundation, authorship, synthesis, lenses, evidence, data | ✅ |
| Slice 0 | Stabilisation, Stooq doc, EDGAR retry, theme-color | ✅ |
| Slice 1 | Composition primitive — `layout_json` + `set_layout` MCP | ✅ |
| Slice 1.5 | Full slot map + extended component vocab | 🔄 |
| Slice 2 | Retrieval — embeddings (BLOB cosine), `retrieve` tool, backfill | ✅ |
| Slice 3 | Temporal — `catch_up`, `reactivate_check`, Catch Up UI | ✅ |
| Slice 4 | Embedded agent — WorkspaceAgent DO, nightly cron, AI Gateway | ✅ |
| Slice 5 | Auth — better-auth, Dockerised auth app | Designing |
| Slice 6 | Chat surface | Designing |
| Slice 7 | Cross-ticker Vectorize tier | Designing |
## Smoke tests
Categorised smoke tests live in [`smoke/`](smoke/README.md).
```bash
# All Playwright specs (UI + E2E)
npm run smoke
# Individual shell scripts (worker API — no browser needed)
bash smoke/ingestion/capture.smoke.sh
bash smoke/claims/claims.smoke.sh
bash smoke/agent/agent.smoke.sh # needs ANTHROPIC_API_KEY
```
## Deploy
### Cloudflare Worker + PWA
```bash
# 1. Build PWA into apps/pwa/dist
npm run build:pwa
# 2. Set production secrets (one-time)
cd apps/worker
wrangler secret put THESIS_BEARER_TOKEN
wrangler secret put ANTHROPIC_API_KEY
wrangler secret put CF_AIG_TOKEN
wrangler secret put FINNHUB_API_KEY
wrangler secret put FRED_API_KEY
# 3. Deploy worker + PWA assets
wrangler deploy
```
The Worker serves the PWA from the same origin. `/share-target`, `/mcp`, and `/api/*` are all first-party.
Full deployment guide including auth-app Docker target, DNS, and post-deploy smoke checks: [`docs/deployment.md`](docs/deployment.md).
## Tech stack
| Layer | Tech |
|---|---|
| Worker runtime | Cloudflare Workers + Durable Objects (SQLite) |
| API framework | Hono |
| MCP | Hand-rolled JSON-RPC over HTTP + SSE (30 tools) |
| PWA | Vite 5 + React 18 + Tailwind 3 |
| Rich text | Tiptap |
| Embeddings | Workers AI `bge-small-en-v1.5` (384-dim, BLOB cosine) |
| Agent | Plain Durable Object (`WorkspaceAgent`) + CF AI Gateway |
| Documents | R2 + `document_captures` join table |
| Shared types | `packages/shared` (Zod) |
## Contributing
1. Read [`docs/STATUS.md`](docs/STATUS.md) — current state + forward plan
2. Read [`docs/architecture/v2-embedded-agent.md`](docs/architecture/v2-embedded-agent.md) — v2 design
3. Run `npm run typecheck` before pushing
4. Add smoke coverage for new endpoints in `smoke/`
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues