Create Agent-Context wiki page for fractafrag
parent
845143a489
commit
44892e604c
1 changed files with 205 additions and 0 deletions
205
Agent-Context.-.md
Normal file
205
Agent-Context.-.md
Normal file
|
|
@ -0,0 +1,205 @@
|
||||||
|
# Agent Context
|
||||||
|
|
||||||
|
| Meta | Value |
|
||||||
|
|------|-------|
|
||||||
|
| **Repo** | `xpltdco/fractafrag` |
|
||||||
|
| **Language** | Python 3.12 (API), TypeScript (Frontend), Node.js (Renderer/MCP) |
|
||||||
|
| **Framework** | FastAPI + SQLAlchemy 2 (async) + React 18 + Vite |
|
||||||
|
| **Entry Point** | `services/api/app/main.py` |
|
||||||
|
| **Test Command** | `make test` or `docker compose exec api pytest tests/ -v` |
|
||||||
|
| **Build Command** | `docker compose build` |
|
||||||
|
| **Compose Services** | 8 (nginx, frontend, api, mcp, renderer, worker, postgres, redis) |
|
||||||
|
| **Database** | PostgreSQL 16 + pgvector |
|
||||||
|
| **Cache/Queue** | Redis 7 (Celery broker, token blocklist) |
|
||||||
|
| **Last Updated** | 2026-04-04 |
|
||||||
|
|
||||||
|
## File Index (Read These First)
|
||||||
|
|
||||||
|
| Priority | File | Purpose |
|
||||||
|
|----------|------|---------|
|
||||||
|
| 1 | `services/api/app/main.py` | FastAPI app setup, lifespan, CORS, router registration |
|
||||||
|
| 2 | `services/api/app/config.py` | Pydantic Settings — all env vars |
|
||||||
|
| 3 | `services/api/app/models/models.py` | All SQLAlchemy ORM models (14 tables) |
|
||||||
|
| 4 | `services/api/app/schemas/schemas.py` | Pydantic request/response schemas |
|
||||||
|
| 5 | `services/api/app/middleware/auth.py` | JWT auth, password hashing, dependencies |
|
||||||
|
| 6 | `services/api/app/routers/shaders.py` | Shader CRUD, versioning, fork, search |
|
||||||
|
| 7 | `services/api/app/routers/feed.py` | Personalized feed, trending, tag affinity |
|
||||||
|
| 8 | `services/api/app/routers/votes.py` | Voting + Wilson hot score calculation |
|
||||||
|
| 9 | `services/api/app/routers/desires.py` | Bounty board (create, list, fulfill) |
|
||||||
|
| 10 | `services/api/app/routers/auth.py` | Register, login, refresh, logout |
|
||||||
|
| 11 | `services/api/app/routers/users.py` | Profile, BYOK keys |
|
||||||
|
| 12 | `services/api/app/worker/__init__.py` | Celery tasks (render, embed, cluster, generate) |
|
||||||
|
| 13 | `services/api/app/services/embedding.py` | TF-IDF + SVD vectorizer (512-dim) |
|
||||||
|
| 14 | `services/api/app/services/clustering.py` | pgvector cosine nearest-neighbor |
|
||||||
|
| 15 | `services/api/app/services/glsl_validator.py` | Static GLSL syntax analysis |
|
||||||
|
| 16 | `services/api/app/database.py` | Async SQLAlchemy engine + sessions |
|
||||||
|
| 17 | `services/api/app/redis.py` | Async Redis client singleton |
|
||||||
|
| 18 | `services/mcp/server.py` | MCP tools for AI agents |
|
||||||
|
| 19 | `services/renderer/server.js` | Express + Puppeteer rendering pipeline |
|
||||||
|
| 20 | `docker-compose.yml` | Service orchestration |
|
||||||
|
| 21 | `db/init.sql` | Full PostgreSQL schema + indexes |
|
||||||
|
|
||||||
|
## Dependency Map
|
||||||
|
|
||||||
|
```
|
||||||
|
docker-compose.yml
|
||||||
|
├── nginx (routes to frontend, api, mcp, renders)
|
||||||
|
├── frontend (React SPA, Vite)
|
||||||
|
├── api (FastAPI)
|
||||||
|
│ ├── app/main.py
|
||||||
|
│ │ ├── app/routers/*.py (10 router modules)
|
||||||
|
│ │ ├── app/middleware/auth.py (JWT)
|
||||||
|
│ │ └── app/middleware/rate_limit.py
|
||||||
|
│ ├── app/database.py → PostgreSQL (asyncpg)
|
||||||
|
│ ├── app/redis.py → Redis
|
||||||
|
│ ├── app/models/models.py (ORM)
|
||||||
|
│ ├── app/schemas/schemas.py (Pydantic)
|
||||||
|
│ └── app/services/
|
||||||
|
│ ├── embedding.py (TF-IDF + SVD)
|
||||||
|
│ ├── clustering.py (pgvector cosine)
|
||||||
|
│ ├── glsl_validator.py
|
||||||
|
│ ├── renderer_client.py → renderer:3100
|
||||||
|
│ └── byok.py (encryption)
|
||||||
|
├── worker (Celery, reuses api image)
|
||||||
|
│ └── app/worker/__init__.py
|
||||||
|
│ ├── render_shader → renderer:3100
|
||||||
|
│ ├── process_desire → embedding + clustering
|
||||||
|
│ └── ai_generate → external LLM APIs
|
||||||
|
├── mcp (FastMCP)
|
||||||
|
│ └── server.py → api:8000 (internal)
|
||||||
|
├── renderer (Express + Puppeteer)
|
||||||
|
│ └── server.js → /renders volume
|
||||||
|
├── postgres (pgvector/pgvector:pg16)
|
||||||
|
│ └── db/init.sql (bootstrap schema)
|
||||||
|
└── redis (redis:7-alpine)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Modification Patterns
|
||||||
|
|
||||||
|
### To add a new API endpoint:
|
||||||
|
1. Create/edit router in `services/api/app/routers/`
|
||||||
|
2. Add Pydantic schemas in `services/api/app/schemas/schemas.py`
|
||||||
|
3. Register router in `services/api/app/main.py` if new file
|
||||||
|
4. Add `Depends(get_current_user)` for auth, `Depends(get_db)` for database
|
||||||
|
|
||||||
|
### To modify the database schema:
|
||||||
|
1. Edit `db/init.sql` (for new installs)
|
||||||
|
2. Edit ORM model in `services/api/app/models/models.py`
|
||||||
|
3. Create Alembic migration: `docker compose exec api alembic revision --autogenerate -m "change"`
|
||||||
|
4. Apply: `docker compose exec api alembic upgrade head`
|
||||||
|
|
||||||
|
### To add a Celery task:
|
||||||
|
1. Define in `services/api/app/worker/__init__.py`
|
||||||
|
2. Use sync DB (psycopg2, not asyncpg) — Celery is sync
|
||||||
|
3. Enqueue from router: `my_task.delay(args)`
|
||||||
|
|
||||||
|
### To add an MCP tool:
|
||||||
|
1. Add function in `services/mcp/server.py` with `@mcp.tool()`
|
||||||
|
2. Call API internally via httpx to `http://api:8000/api/v1/...`
|
||||||
|
|
||||||
|
## Gotchas
|
||||||
|
|
||||||
|
1. **Async vs Sync DB** — The API uses `asyncpg` (async SQLAlchemy). The Celery worker uses `psycopg2` (sync). Don't mix them — worker tasks must create their own sync engine/session.
|
||||||
|
|
||||||
|
2. **Celery task imports** — The worker image is built from the same Dockerfile as the API. Tasks are defined in `app/worker/__init__.py`. The Celery app must be importable as `app.worker`.
|
||||||
|
|
||||||
|
3. **System user** — UUID `00000000-0000-0000-0000-000000000001` is the platform system account. It's created by `db/init.sql`. System-generated shaders use this author. Don't delete it.
|
||||||
|
|
||||||
|
4. **GLSL validation** — The validator in `glsl_validator.py` does static analysis only (no GPU compilation). It checks for `mainImage` entry point, balanced braces, banned extensions, and infinite loop patterns. A shader can pass validation but still fail to render.
|
||||||
|
|
||||||
|
5. **Render status** — Shaders go through: `pending` → `rendering` → `ready` or `failed`. The feed only shows shaders with `render_status='ready'`. A newly published shader won't appear in the feed until the worker renders it.
|
||||||
|
|
||||||
|
6. **JWT refresh rotation** — On every `/refresh` call, the old refresh token is blocklisted in Redis. If a client uses the same refresh token twice, the second attempt fails (preventing replay attacks). The blocklist entries have TTL matching the refresh token lifetime (30 days).
|
||||||
|
|
||||||
|
7. **pgvector cosine** — The `<=>` operator returns cosine distance (0 = identical, 2 = opposite). Similarity = 1 - distance. The clustering threshold (0.82 similarity) means distance < 0.18.
|
||||||
|
|
||||||
|
8. **Embedding dimensions** — All vectors are 512-dimensional. This is hardcoded in the TF-IDF + SVD pipeline and in the PostgreSQL `vector(512)` column types. Changing it requires rebuilding all embeddings and altering the column type.
|
||||||
|
|
||||||
|
9. **CORS** — Currently set to `allow_origins=["*"]`. This must be restricted before production deployment.
|
||||||
|
|
||||||
|
10. **Init SQL vs Alembic** — `db/init.sql` bootstraps the schema on first PostgreSQL startup. For schema changes after initial deployment, use Alembic migrations. The init.sql and ORM models must stay in sync manually.
|
||||||
|
|
||||||
|
## MCP Tools (for AI Agents)
|
||||||
|
|
||||||
|
The MCP server at `/mcp/*` exposes these tools:
|
||||||
|
|
||||||
|
| Tool | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `browse_shaders(query, tags, shader_type, sort, limit)` | Search/browse shaders |
|
||||||
|
| `get_shader(shader_id)` | Get full shader with GLSL source |
|
||||||
|
| `get_shader_versions(shader_id)` | Version history |
|
||||||
|
| `get_shader_version_code(shader_id, version_number)` | Specific version code |
|
||||||
|
| `submit_shader(title, glsl_code, ...)` | Create new shader |
|
||||||
|
| `update_shader(shader_id, glsl_code, ...)` | Update shader (new version) |
|
||||||
|
| `get_trending(limit)` | Trending shaders |
|
||||||
|
| `get_similar_shaders(shader_id, limit)` | Similar by tag overlap |
|
||||||
|
| `get_desire_queue(min_heat, limit)` | Browse bounties |
|
||||||
|
| `fulfill_desire(desire_id, shader_id)` | Mark bounty fulfilled |
|
||||||
|
|
||||||
|
### GLSL Shader Format (Shadertoy-compatible WebGL2)
|
||||||
|
|
||||||
|
```glsl
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||||
|
vec2 uv = fragCoord / iResolution.xy;
|
||||||
|
fragColor = vec4(uv, 0.5 + 0.5 * sin(iTime), 1.0);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Available uniforms:** `iTime` (float), `iResolution` (vec3), `iMouse` (vec4)
|
||||||
|
|
||||||
|
## Verification Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Start all services
|
||||||
|
make up
|
||||||
|
|
||||||
|
# Check service health
|
||||||
|
docker compose ps
|
||||||
|
|
||||||
|
# Run API tests
|
||||||
|
make test
|
||||||
|
|
||||||
|
# Lint Python code
|
||||||
|
docker compose exec api ruff check app/ tests/
|
||||||
|
|
||||||
|
# Database shell
|
||||||
|
make db-shell
|
||||||
|
|
||||||
|
# View logs
|
||||||
|
make logs
|
||||||
|
|
||||||
|
# Rebuild after changes
|
||||||
|
make build && make up
|
||||||
|
```
|
||||||
|
|
||||||
|
## Architecture Summary
|
||||||
|
|
||||||
|
```
|
||||||
|
8-service Docker Compose stack:
|
||||||
|
|
||||||
|
nginx:80 (reverse proxy)
|
||||||
|
├── / → frontend:5173 (React SPA)
|
||||||
|
├── /api/* → api:8000 (FastAPI)
|
||||||
|
├── /mcp/* → mcp:3200 (FastMCP for AI agents)
|
||||||
|
└── /renders/* → static volume (shader thumbnails)
|
||||||
|
|
||||||
|
api:8000 (FastAPI, async)
|
||||||
|
├── JWT auth + bcrypt passwords
|
||||||
|
├── SQLAlchemy 2 async → PostgreSQL
|
||||||
|
├── Redis (token blocklist, rate limits)
|
||||||
|
└── Enqueues Celery tasks
|
||||||
|
|
||||||
|
worker (Celery, sync)
|
||||||
|
├── render_shader → renderer:3100
|
||||||
|
├── process_desire → embed + cluster
|
||||||
|
└── Periodic: feed cache, bounty expiry
|
||||||
|
|
||||||
|
renderer:3100 (Puppeteer + Chromium)
|
||||||
|
└── GLSL → WebGL → screenshot → /renders
|
||||||
|
|
||||||
|
postgres:5432 (pgvector)
|
||||||
|
└── 14 tables, HNSW indexes, trigram search
|
||||||
|
|
||||||
|
redis:6379
|
||||||
|
└── Celery broker/backend, JWT blocklist
|
||||||
|
```
|
||||||
Loading…
Add table
Reference in a new issue