Skip to content

Latest commit

 

History

History
48 lines (31 loc) · 2.61 KB

File metadata and controls

48 lines (31 loc) · 2.61 KB

Contributing to Counterpoint Engine

Setup

Follow "Running it locally" in the README. You'll need Docker for Redis/Neo4j/Qdrant even if you run the API and worker natively.

Before opening a PR

Backend

cd backend
pip install -r requirements.txt
pytest

All 23 tests should pass without a live Redis/Neo4j/Qdrant/Groq connection — LLM calls, the scraper, and the stores are mocked at the boundary. If you add a service or agent, add tests that mock its external dependency the same way.

Frontend

cd frontend
npm install
npm run lint
npm run build

npm run build runs the TypeScript compiler as part of the Next.js build — a type error fails the build, not just the lint step.

Code style

  • Backend: standard library logging, no bare except:, Pydantic models for anything crossing a process boundary (API request/response, WebSocket events, Celery task payloads). No stub functions — either implement it or don't add it.
  • Frontend: components stay client ("use client") only when they need state, effects, or browser APIs. Server Components by default. No localStorage — Redis is the only cross-request state.
  • No em dashes in copy shown to users (README prose is fine, in-app copy isn't). Keep in-app strings short and specific instead of generic ("Fetched Reuters: Nvidia earnings" not "Loading...").

Commit messages

Imperative mood, one line, no ticket-number cargo culting: Add confidence threshold to critic prompt, not Fixed stuff.

Reporting bugs / requesting features

Use the issue templates under .github/ISSUE_TEMPLATE/. For bugs, include the job ID from the Agent Terminal header if the bug happened mid-run — it's how the Redis-buffered event log gets tied back to what you saw.

Architecture decisions worth knowing before you change them

  • All cross-process state lives in Redis, not in-process memory. The FastAPI web service and the Celery worker are separate processes (separate Render services in production) and never call each other directly.
  • The WebSocket relay is dumb on purpose. It doesn't know anything about LangGraph or the swarm — it subscribes to a Redis pub/sub channel keyed by job ID and forwards whatever JSON shows up. If you add a new event type, add it to app/models/schemas.py, publish it from wherever it happens, and it'll reach the frontend without touching websocket_manager.py.
  • Agents don't call each other. They're pure async def run(state, emit) -> dict functions wired together in app/agents/graph.py. If you're tempted to have the Scraper call the Critic directly, put that logic in the graph's routing instead.