Guides · Five minutes

Quickstart

Paste a document, see findings, forge clarity. By the end of this page you’ll have run a real analysis and applied an AI rewrite.

Pellucid runs in two halves: a fast rule layer and a slower multi-agent layer. The rule layer returns within ~200 ms and gives you the obvious wins (vague adjectives, passive voice, “etc”). The agent layer streams in over the next 5–15 seconds and catches the subtle stuff (untestable claims, hidden assumptions, risk-weighted gaps).

Prerequisites

  • Python 3.12 or newer
  • Node 20 or newer, with pnpm 9
  • An API key for any LiteLLM-compatible provider (xAI, Anthropic, OpenAI, OpenRouter)

Boot the stack

From the repo root:

bash
# 1. Install JS deps
pnpm install

# 2. Install Python deps + the spaCy model
cd apps/api
uv sync
uv run python -m spacy download en_core_web_sm

# 3. Set an LLM key (or do it later in /settings)
cp .env.example .env
# edit .env and set XAI_API_KEY (or any provider — see /docs/byok)

# 4. Boot both servers (from repo root)
cd ../..
pnpm dev:api   # http://localhost:8000
pnpm dev:web   # http://localhost:3000

Hit http://localhost:8000/health to confirm the API is up; you should see {status: ok}.

Paste a document

Open http://localhost:3000, click Try sample document, and paste in your own text — anything from a one-paragraph requirement to a full SRS works. The editor on the left holds the source; the right rail fills with findings as they stream in.

Within roughly 200 ms you’ll see rule-layer findings highlighted inline. Over the next ~10 seconds, the four agents (Lexical, Syntactic, Domain, Risk) report independently, then critique each other. The aggregator merges overlapping spans and weights each finding’s confidence by the level of agreement.

Under the hood — what just happened

The web app called four endpoints, in order:

  1. POST /api/v1/documents — persists the pasted text and returns a document_id.
  2. POST /api/v1/documents/{id}/analyze — opens a Server-Sent Events stream. The first event is rule_findings; subsequent events are per-agent findings, critique votes, and a final aggregated event.
  3. GET /api/v1/debate/{id} — fetches the full debate transcript when the user opens the Debate panel.
  4. POST /api/v1/findings/{id}/rewrite — when the user clicksForge Clarity, returns 2–3 candidate rewrites.

You can do all of this from the command line. Here’s the minimal end-to-end flow:

curl: create + analyze + rewrite
bash
# 1. Create a document
DOC_ID=$(curl -sX POST http://localhost:8000/api/v1/documents \
  -H "Content-Type: application/json" \
  -d '{"content": "The system shall be user-friendly and respond quickly."}' \
  | jq -r .id)

# 2. Open the SSE stream — JSON events stream until "done"
curl -N -X POST http://localhost:8000/api/v1/documents/$DOC_ID/analyze

# 3. Pick a finding id from the stream and forge a rewrite
curl -sX POST http://localhost:8000/api/v1/findings/$FINDING_ID/rewrite | jq .

The SSE event stream

Pellucid streams progress so the UI can light up incrementally instead of making the user wait for the slowest agent. Each event is a JSON object on a single data: line.

EventWhen it firesPayload
rule_findings~200 ms after analyze starts{ findings: Finding[] }
agent_findingsOnce per agent, as each finishes{ agent, findings, reasoning, self_confidence }
critiqueAfter all agents have reported{ votes: CritiqueVote[] }
finalOnce, after aggregation + persistence{ findings, debate }
doneStream complete — close the connection{}
errorPipeline error — terminal{ message: string }

A minimal browser consumer using the standard EventSource API:

EventSource — the browser way
js
// EventSource is GET-only, so use fetch + a streaming reader for POST.
const res = await fetch(`/api/v1/documents/${docId}/analyze`, {
  method: "POST",
});
const reader = res.body.getReader();
const decoder = new TextDecoder();
let buf = "";

for (;;) {
  const { value, done } = await reader.read();
  if (done) break;
  buf += decoder.decode(value, { stream: true });

  // SSE frames are separated by a blank line.
  let i;
  while ((i = buf.indexOf("\n\n")) >= 0) {
    const frame = buf.slice(0, i);
    buf = buf.slice(i + 2);
    const event = /^event:\s*(.+)$/m.exec(frame)?.[1] ?? "message";
    const data = /^data:\s*(.+)$/m.exec(frame)?.[1] ?? "";
    handle(event, JSON.parse(data));
  }
}

function handle(event, payload) {
  if (event === "rule_findings") render(payload.findings);
  if (event === "final") replaceWith(payload.findings);
}

Forge Clarity — your first rewrite

Pick any finding (the right rail in the web app, or any item from thefinal event payload) and POST its id to the rewrite endpoint. The response holds 2–3 candidates, each with a one-sentence rationale.

POST /api/v1/findings/find_abc123/rewrite — example response
json
{
  "finding_id": "find_abc123",
  "candidates": [
    {
      "text": "The system shall present a labelled control for every primary action visible at all times.",
      "rationale": "Replaces 'user-friendly' with a measurable affordance: labelled, primary, visible."
    },
    {
      "text": "The system shall complete every user-initiated action within 200 ms at the 95th percentile.",
      "rationale": "Promotes 'respond quickly' to a numeric latency target with a percentile."
    }
  ]
}

Next steps

  • Bring your own key — swap in Anthropic, OpenAI, or OpenRouter without touching code.
  • API reference — every endpoint with request/response examples.
  • Webhooks — receive an analysis.completed POST in Slack, Discord, or your own service when the pipeline finishes.
  • Browser & VS Code extensions — run Pellucid against any page or any markdown file in your editor.