changelog
Every release documented. Code lives at github.com/legate-labs/legate (AGPL-3.0).
Ships a Content-Security-Policy in Report-Only mode plus a violation-collecting endpoint at /api/csp-report. The browser does not block anything yet — it streams what *would* have been blocked into a Postgres table so the policy can be tightened against real traffic before enforce mode flips on.
- ▸Content-Security-Policy-Report-Only header on every response with a curated baseline: WalletConnect + Vercel analytics in connect-src, fonts allowlisted via Google's CDN, image-src widened to https: for token logos and OG previews. frame-ancestors aligned to the route's X-Frame-Options ('none' on /cli-auth, 'self' elsewhere)
- ▸New POST endpoint /api/csp-report accepts both the legacy csp-report wrapper and the Reporting API array shape; rows persist to a new csp_violations Postgres table with directive/blocked-uri/document-uri/source-file/line-column metadata
- ▸New repo helper lib/repos/csp-violations.ts: insertCspViolation() and groupRecentCspViolations() (grouped count + last-seen per (directive, blocked-uri) pair) ready for an admin readout in a later release
- ▸Loose IP-keyed rate limit on /api/csp-report (200/min) that silently returns 204 over the cap — browsers retry on non-204 responses, which would amplify the very thing we're rate-limiting
- ▸Enforce mode flip — gated on at least one full week of policy data plus a wallet/sign/research full-flow regression pass. Aiming for v3.3.1 after observation
- ▸Admin readout of violations — groupRecentCspViolations() is wired but not yet surfaced under /admin; revisit when the policy is close to enforce
Two small but visible fixes to how links to legatehq.com unfurl on Twitter, Slack, LinkedIn, and Discord: the canonical host stops 307-redirecting the OG image, and the OG image itself is now a quieter wordmark composition that reads cleanly at thumbnail size.
- ▸OG canonical URL: metadataBase and openGraph.url were hardcoded https://www.legatehq.com — since apex is now primary and www. 307-redirects, Twitterbot fetched the redirect as text/plain and cached an empty Card. Both literals flipped to the apex; b/[id] and other surfaces were already correct
- ▸OG image refreshed from the P-block + wordmark + constellation backdrop to a quieter wordmark-only composition (large Fraunces "Legate" over a subtle radial gradient, with "THE RESEARCH SWARM" as the eyebrow). 1200x630 declared, rendered at 2x for retina
Baseline web security headers across every route, loose rate limits on the auth endpoints, and a responsible-disclosure path at /.well-known/security.txt. Curated CSP is queued behind a Report-Only roll-out for the next minor.
- ▸Five baseline response headers shipped via a withSecurity() helper in the platform proxy: X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin, Permissions-Policy disabling camera/microphone/geolocation/interest-cohort, HSTS tightened to max-age=63072000; includeSubDomains, and X-Frame-Options: SAMEORIGIN globally (with DENY preserved on /cli-auth)
- ▸Loose IP-keyed rate limit on /api/auth/nonce (60/min) and /api/auth/verify (30/min) — prevents nonce-table flooding and verify brute-force without hampering retries on flaky wallets
- ▸Responsible-disclosure path at /.well-known/security.txt routing to hello@legatehq.com
- ▸Content-Security-Policy: needs a curated connect-src list against the wallet + analytics surface; rolling out behind a Report-Only header first to collect real violation data before enforce
- ▸HSTS preload: permanent commitment to HTTPS for the whole subtree — defer until six months of stable HTTPS-only behaviour are observed
- ▸Durable rate-limit store (Vercel KV / Upstash): the in-memory bucket survives per-instance only; cross-instance cap is looser than advertised
Production hardening plus the operational surfaces a live product needs: a health endpoint with a live status pill, a private usage dashboard, an on-brand 404, and a security sweep across auth, payments, and every external API call.
- ▸Public health endpoint /api/health — timeout-raced Neon round-trip, returns 200/503; backs a live status pill on the landing footer + research header (polls every 60s)
- ▸Private admin dashboard at /admin — wallet-gated usage view: total runs, unique wallets, 24h/7d activity, partial-run count, recent runs, and top wallets, with numbered pagination (25/page)
- ▸On-brand custom 404 page (terminal/compass aesthetic) replacing the default Next.js not-found
- ▸SIWE sign-in is now bound to the server domain + carries an expiry; JWT verification pinned to HS256
- ▸Auth-nonce consumption made atomic (single compare-and-swap) to close a replay race
- ▸Research is attributed only to the cryptographically-verified session — the client-supplied payer header is no longer trusted, and /api/research now requires sign-in
- ▸On-chain USDC payment verification before a tx is ever stored (active when paid mode returns)
- ▸Snapshot GraphQL queries parameterized; all external-API params now format-validated + URL-encoded
- ▸Rate limiter keyed on the platform-trusted client IP instead of a spoofable forwarded header
Briefings became shareable and the history surface grew up: every run now has a public read-only link, history gained working actions + per-session delete, and a systemic JSONB read bug that silently emptied shared briefings was fixed.
- ▸Public shareable briefing links — every research run gets a read-only /b/[id] URL (no login, unguessable UUID, OG + Twitter preview cards)
- ▸Per-session delete (owner-scoped) + working copy-markdown / copy-link actions on every briefing card
- ▸/history#id deep links auto-expand and scroll to the target briefing
- ▸Floating back-to-top button on long briefings
- ▸Shared + history briefings rendered empty — every briefing_json row was a double-encoded JSONB scalar string, so the body read back as a string and lost its fields; now coerced on read
- ▸Sidebar + history stuck on 'loading…' for wallets without a session — both now prompt sign-in on 401, and the sidebar re-fetches automatically after SIWE sign-in
- ▸Hero example queries refreshed to 2026-current topics across tokens / chains / protocols / narratives
Full visual rebuild + pipeline overhaul. Briefings are now data-rich for every topic type — narratives and comparisons get topic decomposition, protocol/chain paths pull native-token data, and confidence theater is gone in favor of explicit Data Gaps.
- ▸v5 hybrid terminal UI across landing, research workspace, history, settings
- ▸LEGATE ANSI pixel-shadow wordmark (cyan→deep-blue gradient + breathing glow)
- ▸Read Mode toggle for briefings — wide measure, 1.75 line-height, agent sub-blocks collapse (default ON for new users)
- ▸Topic decomposition: narrative & comparison topics auto-fan-out into 3–5 concrete sub-asset dossiers (e.g. "memecoin szn?" → DOGE/SHIB/PEPE/WIF/BONK)
- ▸Animated 5-phase pipeline visualization in /#method — probe-color pulse + per-phase caption
- ▸Cycling natural-language prompt placeholder + categorized example chips (// tokens · // chains · // protocols · // narratives)
- ▸Scrollable briefing container with custom cyan-gradient scrollbar (kept landing height consistent regardless of briefing length)
- ▸Protocol path probe enrichment — token via CoinGecko + DexScreener pairs + Etherscan contract meta + project-filtered yields
- ▸Chain path native L1 token lookup (Solana → SOL coin snapshot, Berachain → BERA, etc.)
- ▸Lenis smooth scroll for landing momentum + anchor jumps
- ▸SSH commit signing — every push to main now arrives with Verified badge
- ▸Sticky workspace statusline with legate://research/<slug> breadcrumb + ⌘K commands + ? help
- ▸Section markers § (silcrow magazine) → // (code-comment style) across all surfaces
- ▸Brand mark in nav/footer/sidebar now uses real logo image (was P› text prefix)
- ▸P› gradient text prefix kept only for prompt-style status lines (terminal grammar)
- ▸Synthesizer prompt no longer requires a Confidence Assessment section — readers judge from explicit Data Gaps + Data Freshness table + inline citations
- ▸Fear & Greed Index fetched once per research run (was 2 duplicate calls — analyst at limit=14, sentinel at limit=7)
- ▸Section header copy reflects new transparency: "freshness timestamps, explicit gap notes — no confidence theater, just data you can verify."
- ▸Numeric confidence scores (0-100) — were LLM-stochastic ±10pt and biased against briefings with more honest data caveats
- ▸Fraunces serif editorial typography (magazine-spread aesthetic)
- ▸Star-field constellation background animation (replaced with breathing hairline grid)
- ▸Dead components: star-field.tsx, flow-graph.tsx, findings-card.tsx, report-drawer.tsx (legacy editorial-era components no longer imported)
- ▸SIWE wallet-sign popup state stuck forever at "awaiting wallet signature…" — useEffect dependency self-retrigger bug zeroed the cancelled flag before the wallet promise resolved. Replaced with useRef in-flight guard + mountedRef lifecycle. Added skip/retry escape buttons for stuck popups.
- ▸402 Payment Required on first research after wallet connect — NEXT_PUBLIC_X402_FREE_MODE env var was unset, defaulting to paid mode without x402 wired
- ▸Box-drawing characters (╔╗╚╝═║) rendering broken in LEGATE wordmark — next/font/google subsets to Latin only, stripping U+2500-U+257F glyphs. Switched to raw <link> Google Fonts CSS endpoint (serves multi-range woff2 with box drawing intact)
- ▸EtherFi protocol briefing had only 2 $-value mentions despite being a top-3 LRT protocol — protocol path was missing token + DEX pair lookups. Now hits CG /coins/ether-fi + DexScreener ETHFI search + project-filtered yields. Backtest shows 7× more hard data per briefing.
- ▸Narrative briefings (memecoin szn?, AI agents, DePIN) returned 0 dollar-values — narrative path only had sector-level aggregates. Decomposition now spawns 3-5 sub-asset dossiers in parallel. Backtest shows 25 sources fired (vs 9 previously) and 11-13 $-values per briefing.
LLM provider migrated off OpenRouter (gpt-4o-mini) onto a dedicated OpenAI-compatible reasoning model, and paid mode was paused — free during beta. Same five agents over 13 live APIs; cleaner stack underneath.
- ▸LLM provider: OpenRouter (openai/gpt-4o-mini) → a dedicated OpenAI-compatible reasoning model
- ▸NEXT_PUBLIC_X402_FREE_MODE flag — bypasses x402 micropayment paywall during beta (sends X-PAYER-ADDRESS header instead of signed authorization)
- ▸x402 micropayment-per-research flow — code paths kept, gated behind NEXT_PUBLIC_X402_FREE_MODE=false. Resume planned at GA exit.
- ▸All 5 agents (Commander → Scout → Analyst → Sentinel → Synthesizer) and all 13 data sources
- ▸Briefing markdown shape + freshness table + SIWE wallet auth + research session persistence
Legate went public on legatehq.com with editorial-celestial design language. Free beta active. 5-agent pipeline (Commander → Scout → Analyst → Sentinel → Synthesizer) wired up against 13 live data sources. Repo flipped public.
- ▸5-agent research pipeline orchestrated via lib/probes/pipeline.ts (sequential probe execution: Commander emits queries → Scout/Analyst/Sentinel fetch data → Synthesizer merges)
- ▸13 live data sources: CoinGecko, CoinMarketCap, DefiLlama, DexScreener, GeckoTerminal, Binance, Etherscan, Solscan, GetXAPI (Twitter), Reddit, Snapshot, Tavily, Fear & Greed Index
- ▸x402 micropayment paywall on Base (USDC, settles ~6 seconds, paused during beta)
- ▸SIWE (Sign-In With Ethereum) wallet auth + JWT session + Postgres research session persistence
- ▸Magazine-spread landing with Fraunces serif typography, star-field constellation animation, magazine-style demo briefings
- ▸Brand identity locked: Mariner's Compass constellation theme, cyan-blue logo, @legate X handle (Blue Verified), AGPL-3.0 license, legatehq.com domain
- ▸Repo migrated to legate-labs/legate (fresh public push, no hackathon-era PR history carried over)