Skip to content

Commit fcadbe2

Browse files
committed
Refactor project documentation
1 parent d899328 commit fcadbe2

13 files changed

Lines changed: 920 additions & 638 deletions

AGENTS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ Rules:
1010
- If graphify-out/wiki/index.md exists, use it for broad navigation instead of raw source browsing.
1111
- Read graphify-out/GRAPH_REPORT.md only for broad architecture review or when query/path/explain do not surface enough context.
1212
- After modifying code, run `graphify update .` to keep the graph current (AST-only, no API cost).
13-
- For deploy/ops questions, check README.md's "Production deployment" section before re-deriving from scripts/.
14-
- When code changes affect setup, deploy, or architecture, update README.md to match.
13+
- For deploy/ops questions, check docs/deployment.md before re-deriving from scripts/.
14+
- Keep documentation changes scoped: update README.md for product positioning and headline capabilities, docs/getting-started.md for local setup, docs/architecture.md for system design, and docs/deployment.md for production operations.
1515
- For UI design-system questions (theming, component conventions, shadcn primitives), check ui/DESIGN.md before re-deriving from source.
1616
- When adding/changing UI components, variants, or design tokens under ui/src/, update ui/DESIGN.md to match.
1717

CLAUDE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ Rules:
88
- If graphify-out/wiki/index.md exists, use it for broad navigation instead of raw source browsing.
99
- Read graphify-out/GRAPH_REPORT.md only for broad architecture review or when query/path/explain do not surface enough context.
1010
- After modifying code, run `graphify update .` to keep the graph current (AST-only, no API cost).
11-
- For deploy/ops questions, check README.md's "Production deployment" section before re-deriving from scripts/.
12-
- When code changes affect setup, deploy, or architecture, update README.md to match.
11+
- For deploy/ops questions, check docs/deployment.md before re-deriving from scripts/.
12+
- Keep documentation changes scoped: update README.md for product positioning and headline capabilities, docs/getting-started.md for local setup, docs/architecture.md for system design, and docs/deployment.md for production operations.
1313
- For UI design-system questions (theming, component conventions, shadcn primitives), check ui/DESIGN.md before re-deriving from source.
1414
- When adding/changing UI components, variants, or design tokens under ui/src/, update ui/DESIGN.md to match.
1515

README.md

Lines changed: 96 additions & 633 deletions
Large diffs are not rendered by default.

docs/agent-tooling.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Agent tooling
2+
3+
The authoritative rules for AI coding agents are [AGENTS.md](../AGENTS.md) and [CLAUDE.md](../CLAUDE.md), which are kept in sync. This guide explains the repository-specific tools referenced by those rules.
4+
5+
## Documentation ownership
6+
7+
When behavior changes, update the most specific guide:
8+
9+
- Product positioning and headline capabilities: `README.md`
10+
- Local setup: `docs/getting-started.md`
11+
- Architecture and system flows: `docs/architecture.md`
12+
- Production releases: `docs/deployment.md`
13+
- UI components, variants, and design tokens: `ui/DESIGN.md`
14+
15+
This keeps the root README useful as a project landing page while ensuring operational instructions stay close to their audience.
16+
17+
## Graphify knowledge graph
18+
19+
The generated graph in `graphify-out/` maps code, documentation, symbols, communities, and cross-file relationships. Prefer a scoped query over reading the complete graph report.
20+
21+
### Install
22+
23+
```bash
24+
uv tool install graphifyy
25+
ollama pull gemma4:31b-cloud
26+
```
27+
28+
For Graphify's OpenAI-compatible extraction API:
29+
30+
```bash
31+
export OLLAMA_BASE_URL=http://localhost:11434/v1
32+
export OLLAMA_API_KEY=ollama
33+
export GRAPHIFY_OLLAMA_MODEL=gemma4:31b-cloud
34+
```
35+
36+
Do not reuse an embedding URL that omits `/v1`.
37+
38+
### Commands
39+
40+
| Task | Command |
41+
|---|---|
42+
| Ask about the codebase | `graphify query "How does billing work?"` |
43+
| Explain one concept | `graphify explain "ResearchState"` |
44+
| Find a relationship | `graphify path "endpoints" "outbox"` |
45+
| Refresh code structure | `graphify update .` |
46+
| Full semantic rebuild | `./scripts/graphify-rebuild.sh` |
47+
| Incremental Markdown rebuild | `./scripts/graphify-rebuild.sh --incremental` |
48+
| Use the local 8B model | `./scripts/graphify-rebuild.sh --local` |
49+
| Regenerate report and HTML | `graphify cluster-only .` |
50+
51+
Generated outputs include `graphify-out/graph.json`, `graphify-out/GRAPH_REPORT.md`, and `graphify-out/graph.html`.
52+
53+
### Git hooks
54+
55+
```bash
56+
graphify hook install
57+
./scripts/install-graphify-post-commit.sh
58+
```
59+
60+
The first hook refreshes AST data after code commits. The repository hook starts an incremental semantic extraction after Markdown commits. Follow its log with:
61+
62+
```bash
63+
tail -f ~/.cache/graphify-rebuild.log
64+
```
65+
66+
Skip the semantic hook once with `GRAPHIFY_SKIP_HOOK=1 git commit`. Reinstall the repository hook after reinstalling Graphify hooks.
67+
68+
## Production deployment
69+
70+
When asked to ship to production, agents follow `.cursor/skills/deploy-prod/SKILL.md` and the [deployment runbook](deployment.md). That workflow covers the Cloud Run backend, Vercel UI, smoke verification, and rollback behavior.
71+
72+
## LangSmith diagnosis
73+
74+
When given a LangSmith run URL or UUID, agents use the configured `langsmith` SDK and credentials from `src.config.settings`; they never request, print, or hand-load the API key. The investigation should identify the root cause, failing node or span, relevant source location, and a suggested fix.
75+

docs/architecture.md

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# Architecture
2+
3+
Cortex is a stateful research and retrieval platform built around four cooperating paths: research execution, routed chat, asynchronous resource ingestion, and session-scoped persistence.
4+
5+
## System context
6+
7+
```mermaid
8+
flowchart TB
9+
user["Researcher"]
10+
11+
subgraph cortex["Cortex application"]
12+
direction TB
13+
ui["React workspace"] --> api["FastAPI API and SSE streaming"]
14+
api --> research["LangGraph research workflow"]
15+
api --> chat["ReAct-lite chat routing"]
16+
api --> ingestion["Transactional ingestion outbox"]
17+
end
18+
19+
user --> ui
20+
research --> ai["LLM, search, and retrieval providers"]
21+
chat --> ai
22+
research --> data["Supabase and Neo4j"]
23+
chat --> data
24+
ingestion --> jobs["Inngest workers"]
25+
jobs --> data
26+
27+
api -. telemetry .-> observe["LangSmith and LangFuse"]
28+
jobs -. telemetry .-> observe
29+
```
30+
31+
## Research execution
32+
33+
```mermaid
34+
flowchart LR
35+
query["User query"] --> api["Research endpoint"]
36+
api --> search["Search"]
37+
search -->|"continue"| retrieve["Retrieve and parse"]
38+
search -->|"abort"| abort["Abort"]
39+
retrieve -->|"ok"| memory["GraphRAG context"]
40+
retrieve -->|"empty"| empty["Empty result"]
41+
memory --> rerank["Rerank"]
42+
rerank --> summarize["Summarize"]
43+
summarize --> report["Generate report"]
44+
report --> stream["SSE stream"]
45+
stream --> done["End"]
46+
abort --> done
47+
empty --> done
48+
```
49+
50+
Search, retrieval, memory context, reranking, summarization, and report generation are separate graph nodes. The graph represents empty and aborted execution explicitly instead of collapsing every non-happy path into a generic exception.
51+
52+
## Chat routing
53+
54+
```mermaid
55+
flowchart LR
56+
message["User message"] --> context["Available local context"]
57+
context --> router["Schema-validated ReAct-lite router"]
58+
router -->|"answer_direct"| direct["Direct answer"]
59+
router -->|"answer_from_rag"| rag["Grounded RAG answer"]
60+
router -->|"web_search"| web["Web search"]
61+
router -->|"fetch_url"| fetch["Fetch URL"]
62+
router -->|"ask_clarifying"| clarify["Clarifying question"]
63+
```
64+
65+
Routing policy:
66+
67+
- Greetings and other social turns normally resolve directly.
68+
- Weak or empty RAG context does not automatically trigger web search.
69+
- Web search is selected for external, fresh, or otherwise web-dependent information.
70+
- A URL in the message or history is available context, not an automatic fetch instruction.
71+
- Direct URL fetching happens only when inspecting the resource is necessary.
72+
- Agent chat, workspace chat, and streaming/non-streaming endpoints use the same policy.
73+
74+
Workspace and agent document collections are deny-by-default: Cortex retrieves them only when the router explicitly selects `answer_from_rag`. Session attachments remain available as explicitly scoped resources. A routing failure after one structured-output repair returns `router_error` and does not retrieve documents.
75+
76+
## Reliable ingestion
77+
78+
```mermaid
79+
flowchart LR
80+
upload["Upload resource"] --> api["Upload endpoint"]
81+
api --> tx["Atomic database RPC"]
82+
tx --> resource["Resource row"]
83+
tx --> job["Queued ingestion job"]
84+
tx --> event["Pending outbox event"]
85+
dispatcher["Outbox dispatcher"] --> claim["Claim event"]
86+
claim --> publish["Publish to Inngest"]
87+
publish --> worker["Idempotent ingestion worker"]
88+
worker --> ingest["Ingest signed storage URL"]
89+
ingest --> artifacts["GraphRAG artifacts"]
90+
claim -->|"send error"| retry["Backoff and retry"]
91+
```
92+
93+
Resource creation, job creation, and the intent to publish are committed together. The dispatcher claims outbox rows before publishing to Inngest, and the worker claims a queued job before processing it. Retries therefore preserve the event intent without allowing duplicate workers to process the same terminal job.
94+
95+
## Persistence and isolation
96+
97+
- Supabase provides Postgres persistence, authentication, and object storage.
98+
- Research sessions and retrieved context are scoped to the authenticated user.
99+
- Neo4j stores document chunks, vector embeddings, and graph relationships used for retrieval.
100+
- Redis accelerates auth, search, and session hot paths but degrades gracefully when unavailable.
101+
102+
## Key engineering decisions
103+
104+
### Transactional outbox instead of direct dispatch
105+
106+
A direct `database write → queue API call` creates a dual-write failure window: the process can crash after saving the job but before publishing its event. Cortex records the resource, job, and outbox intent in one Supabase transaction. A separate dispatcher publishes and retries independently, avoiding a distributed transaction between Postgres and Inngest.
107+
108+
### Model-directed routing instead of fixed heuristics
109+
110+
Whether a turn needs RAG, the web, a URL fetch, clarification, or no tool at all depends on intent and conversation context. A validated model decision keeps that policy consistent across chat surfaces. The optional fine-tuned router can offload this frequent classification step to a smaller model; see [Router fine-tuning](router-fine-tuning.md).
111+
112+
### Explicit graph outcomes instead of a linear pipeline
113+
114+
An empty search result is not the same as a crashed provider call. Explicit graph edges preserve the distinction so the API, UI, and telemetry can report accurate outcomes and recovery behavior.
115+
116+
## Related documentation
117+
118+
- [Getting started](getting-started.md)
119+
- [Production deployment](deployment.md)
120+
- [Observability](observability.md)
121+
- [Model evaluation](model-evaluation.md)
122+
- [UI design system](../ui/DESIGN.md)

docs/billing.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Billing
2+
3+
Cortex uses Stripe Hosted Checkout, signed webhooks, and the customer portal for subscription management.
4+
5+
## Configuration
6+
7+
Required variables:
8+
9+
- `STRIPE_SECRET_KEY`
10+
- `STRIPE_WEBHOOK_SECRET`
11+
- `STRIPE_PRO_PRICE_ID`
12+
- `STRIPE_SUCCESS_URL`
13+
- `STRIPE_CANCEL_URL`
14+
- `STRIPE_PORTAL_RETURN_URL`
15+
16+
Store production secret values in Google Secret Manager. See [Production configuration](env-vars-production.md).
17+
18+
## Webhook setup
19+
20+
Register the endpoint in **Stripe Dashboard → Developers → Webhooks**:
21+
22+
```text
23+
https://<cloud-run-url>/api/billing/webhook
24+
```
25+
26+
Subscribe to:
27+
28+
- `checkout.session.completed`
29+
- `customer.subscription.created`
30+
- `customer.subscription.updated`
31+
- `customer.subscription.deleted`
32+
33+
The signing secret shown by Stripe must match `STRIPE_WEBHOOK_SECRET` in Secret Manager.
34+
35+
## Subscription flow
36+
37+
```mermaid
38+
flowchart LR
39+
ui["Upgrade button"] --> checkout["Create checkout session"]
40+
checkout --> stripe["Stripe Hosted Checkout"]
41+
stripe --> webhook["Signed webhook"]
42+
webhook --> verify["Verify signature"]
43+
verify --> sync["Upsert user subscription"]
44+
sync --> usage["Usage endpoint"]
45+
usage --> quota["Quota guards"]
46+
```
47+
48+
Webhook events are the authoritative source for subscription state. The backend verifies the Stripe signature before updating `user_subscriptions`; research and chat quota guards then read the synchronized subscription and usage state.
49+

0 commit comments

Comments
 (0)