Skip to content

Latest commit

 

History

History
167 lines (132 loc) · 5.86 KB

File metadata and controls

167 lines (132 loc) · 5.86 KB

cursorfy

Chat agent for any FastAPI app. Built on the Cursor SDK. The agent runs in your project directory, reads source code, queries data files, edits code.

Quick start

uv add cursorfy
export CURSOR_API_KEY=crsr_...
from fastapi import FastAPI
import cursorfy

app = FastAPI()
cursorfy.mount(app)       # adds POST /api/chat + /cursorfy/static/*
<script defer src="/cursorfy/static/chat.js"></script>

[ ASK ] button appears. Press A to open, Esc to close, T for light/dark toggle.

CLI

cursorfy init                  # scaffold a dashboard from data in cwd
cursorfy init --run            # also start uvicorn after
cursorfy init --model claude-opus-4-7

API

cursorfy.mount(app)              # function call
@cursorfy.enable                 # decorator on factory
app = cursorfy.attach(FastAPI()) # chained

All take the same kwargs:

kwarg default purpose
cwd auto Folder the agent runs against
model "composer-2.5" Default Cursor model
valid_models 6 builtin ids Allowed in the dropdown
preamble builtin System prompt ({cwd} substituted)
api_key $CURSOR_API_KEY / .env Override env var
prefix "" Route prefix
static_path "/cursorfy/static" JS/CSS mount path

What the agent gets

  1. Every file in cwd via Cursor tools (read_file, grep, terminal, edit_file). Any format: CSV, parquet, JSON, sqlite, Excel. Uses DuckDB for SQL across mixed formats.
  2. A screenshot of the page the user is looking at.
  3. This file (AGENTS.md), appended to the system prompt.

Architecture

Browser
  ├ chat.js    [ ASK ] FAB + floating panel, SSE stream
  └ POST /api/chat  →  ChatHandler
                          ├ AsyncClient.launch_bridge(workspace=cwd)
                          ├ AsyncAgent.create / resume (LRU by session_id)
                          └ thinking/tool/answer events

Repo layout

cursorfy/
├── __init__.py        # mount() / enable / attach (widget API)
├── chat.py            # ChatHandler, agent cache, SSE
├── init/              # cursorfy init scaffolder
│   ├── __init__.py    # CLI entry, init_command, SCAFFOLD_PROMPT loader
│   └── scaffold_prompt.md
└── static/
    ├── chat.js        # widget
    └── chat.css       # light/dark, --cursorfy-* vars
examples/                            # all data is real and citable
├── taxi/              # NYC Yellow Taxi (parquet + zone CSV, DuckDB)
├── github/            # Top 30 OSS repos (CSV, polars, GitHub Search API)
├── sp500/             # S&P 500 5y close + SPY holdings (CSV, polars, yfinance)
├── co2/               # OWID global CO2 emissions (CSV, polars)
├── olympics/          # Paris 2024 + Tokyo + Rio medals (CSV, polars)
└── movies/            # MovieLens latest-small (4 CSVs, polars joins)
assets/
├── make_tiles.py          # playwright tile capture (all examples)
└── tiles/                 # one PNG per example, for the README gallery

docs/ is git-ignored; it's a local scratchpad for launch copy and work-in-progress screenshots, not shipped with the package.

Examples conventions

Each example matches the same shape so the agent only has to learn the template once. Tufte rules apply.

  • Module docstring is a story-led headline + a Run: block with port.
  • 4 KPI tiles + 2-3 Plotly charts + a sortable table.
  • A second table is fine in place of a chart when the data is ranked.
  • JS data injected via json.dumps().
  • CSS uses var(--cursorfy-*) throughout; charts re-theme on toggle.
  • AGENTS.md per example documents schema, real findings, common questions, and the chart conventions. The agent reads it on every session.
  • File budgets: app.py under 220 lines; data files under 1 MB.

Chart rules (the same rules the scaffolder bakes in)

The scaffolder enforces Tufte. The chat agent must too when adding charts.

  • One accent color (var(--cursorfy-cyan)); var(--cursorfy-coral) for negatives only.
  • No rainbow palettes. No pie / donut / 3D / gauge / radar.
  • No hex colors anywhere; read CSS vars at runtime via getComputedStyle.
  • Tables for ranked lists up to 20 items; charts for trends and distributions.
  • 2-5 series on a chart? Cyan-to-muted ramp via color-mix(), never new families.
  • 6+ series? Small multiples.
  • Scatter with >10 points? Hover-only labels (no text collisions).
  • Faint gridlines only; no axis line; no tick marks; tight margins.
  • displayModeBar:false always. Bar chart y-axis starts at zero.
  • Tooltips full-precision via hovertemplate.

Style rules (same lifecycle)

  • Body font Poppins; UI labels (KPI labels, chart titles, table th) inherit it. Monospace only on numeric values (.stat-value, td.num).
  • Never set font-family at the table level; only on td.num. That bug drags column headers and text cells like "Manhattan" into monospace, which clashes with the Poppins KPI labels above.
  • Sharp corners (no border-radius).
  • All colors via cursorfy CSS variables; never hex.

The full scaffold prompt lives in cursorfy/init/scaffold_prompt.md; it's the source of truth and is what every cursorfy init user runs.

Theming

Override these CSS variables:

:root {
    --cursorfy-bg:     #001926;
    --cursorfy-card:   #0a2936;
    --cursorfy-text:   #ffffff;
    --cursorfy-muted:  #7ba3b8;
    --cursorfy-subtle: #4a6d7c;
    --cursorfy-cyan:   #62e4fb;
    --cursorfy-coral:  #ff6b6b;
    --cursorfy-shadow: 0 12px 32px rgba(0, 0, 0, 0.55);
}

All tints derived via color-mix(). Change --cursorfy-cyan, everything follows.

Production

  • Agent has read/write access to the project directory. Don't put secrets next to it.
  • Set CURSOR_API_KEY via your platform's secret manager. Never commit it.
  • First message takes 2-5s (cold start). Follow-ups resume the agent.