Choose a stack to visualize
Render a live architecture diagram for any technology stack, stacked in tiers β hypervisor base layer, then OS, then applications. Every component is annotated with its installed vs. latest version, update severity, and any known CVEs. Pick a sample stack below, or add your own components from the sidebar.
System Architecture
An open-source pipeline for tracking software releases, security advisories, and community signals. The goal is to continuously poll 20+ vendor feeds, package registries, and developer forums; normalise every event into one of two MongoDB collections (versions or reddit); stamp each document with a structured identifier; and expose the full corpus through a typed REST API and a static browser client. No proprietary transforms, no vendor lock-in.
Each section is collapsed by default. Click any heading to expand.
Platform Overview
Six subsystems, two MongoDB collections, one REST API. Arrows show the primary data and control paths.
NVD Β· CVE Β· Patch Tuesday Β· Ubuntu Β· Debian"] SRC2["Browser Releases
Chrome Β· Firefox Β· Safari"] SRC3["Runtimes and Platforms
Node.js Β· Python Β· Linux Kernel Β· Eclipse"] SRC4["Community Signals
Reddit 20+ subreddits Β· Stack Overflow"] end subgraph BOT ["releasetrain-bot Β· Python collector fleet"] BOT_V["Version pollers
15+ release scrapers"] BOT_R["Reddit scraper
PRAW"] BOT_ML["ML labeller
isUpdateRelated Β· positiveScore"] end subgraph STORE ["MongoDB Atlas"] COL_V[("versions")] COL_R[("reddit")] end subgraph SERVER ["releasetrain-server Β· Node and Express"] RT_V["/api/v/*"] RT_R["/api/reddit/*"] RT_AGG["/api/aggregate/*"] end subgraph CLIENT ["releasetrain-client Β· Static JS and HTML"] UI_FEED["Feed and Dashboard"] UI_CVE["CVE View"] UI_GRAPH["Component Graph"] UI_OTHER["Docs Β· Label Β· Archive views"] end subgraph CHAT ["releasetrain-chat Β· Streamlit RAG"] CHAT_EMB["Embeddings
text encoder"] CHAT_LLM["LLM Inference
DigitalOcean GenAI"] CHAT_UI["Chat Interface"] end SRC1 & SRC2 & SRC3 --> BOT_V --> COL_V SRC4 --> BOT_R --> BOT_ML --> COL_R COL_V --> RT_V & RT_AGG COL_R --> RT_R RT_V --> UI_FEED & UI_CVE & UI_GRAPH RT_R --> UI_FEED COL_V & COL_R --> CHAT_EMB --> CHAT_LLM --> CHAT_UI classDef ext fill:#eff6ff,stroke:#cbd5e1,color:#0f172a classDef bot fill:#fffbeb,stroke:#fde68a,color:#0f172a classDef db fill:#f1f5f9,stroke:#e2e8f0,color:#0f172a classDef api fill:#f1f5f9,stroke:#e2e8f0,color:#0f172a classDef ui fill:#f8fafc,stroke:#e2e8f0,color:#0f172a classDef chat fill:#fef2f2,stroke:#fca5a5,color:#0f172a class SRC1,SRC2,SRC3,SRC4 ext class BOT_V,BOT_R,BOT_ML bot class COL_V,COL_R db class RT_V,RT_R,RT_AGG api class UI_FEED,UI_CVE,UI_GRAPH,UI_OTHER ui class CHAT_EMB,CHAT_LLM,CHAT_UI chat
Source Coverage: 20+ release and community feeds
Security and vendor feeds write to the versions collection. Community signals write to the reddit collection.
Data Ingestion and Enrichment Pipeline
Raw signals pass through four stages before landing in MongoDB.
and release pages"] C2["Scrape Reddit
via PRAW"] end subgraph NORM ["Normalise"] N1["Deduplicate
by redditId or versionId"] N2["Parse semver
and release channel"] end subgraph ENRICH ["Enrich"] E1["Predict isUpdateRelated"] E2["Predict positiveScore"] E3["Stamp versionId
YYYYMMDD Β· name Β· version"] E4["Add search tags
and timestamps"] end subgraph STORE ["Store"] S1[("versions")] S2[("reddit")] end C1 --> N2 --> E3 --> E4 --> S1 C2 --> N1 --> E1 --> E2 --> S2 classDef db fill:#f1f5f9,stroke:#e2e8f0,color:#0f172a class S1,S2 db
API Topology: REST route groups and MongoDB dependencies
All REST route groups and the MongoDB collection each reads or writes.
fc Β· fcc Β· stats/by-month"] V2["POST and PUT versions"] end subgraph RED ["/api/reddit/* Β· Reddit"] R1["GET reddit Β· by-subreddit
questions Β· positive Β· cve Β· stats"] R2["POST and PUT reddit"] end subgraph AGG ["/api/aggregate/* Β· Aggregations"] A1["GET v/typeBreakdown Β· v/updateTypeCount
v/classificationSummary Β· v/versionCountByDay"] A2["GET reddit/summary Β· reddit/count
reddit/bySource Β· reddit/bySubreddit Β· reddit/countByDay"] end subgraph SYS ["System"] S1["GET health Β· meta
test/all Β· test/endpoints"] end end DB_V[("versions")] DB_R[("reddit")] CL --> VER & RED & AGG & SYS VER --> DB_V AGG --> DB_V RED --> DB_R classDef db fill:#f1f5f9,stroke:#e2e8f0,color:#0f172a class DB_V,DB_R db
Frontend Views: releasetrain-client
One self-contained index.html served as a static file. Views switch client-side via a ?view= parameter; no per-view page loads. Click a view to expand details.
Feed
/api/v/search, /api/reddit and the /api/aggregate/* per-day endpoints. Vanilla JS; Chart.js is lazy-loaded from a CDN for the activity chart.CVE View
Graph View
Arch View
versionProductType === "Hypervisor"), then OS, then applications β with an "Upgrade now" cluster hoisted out for anything carrying a CVE or a major-version gap. A table mode lists the same data as a drift report.Risk Report
Docs
Account
localStorage. Feeds the Arch view's installed-vs-latest drift annotations.Changelog
package.json and stamped into the page at build time.AI Chat: RAG pipeline with vector search and LLM inference
A Streamlit application (releasetrain-chat) that wraps a retrieval-augmented generation pipeline over both MongoDB collections. At startup it encodes release notes and community posts into a FAISS vector index. At query time it retrieves the top-k most similar documents by cosine similarity, optionally reranked by a cross-encoder, then injects them into an LLM prompt served via DigitalOcean GenAI (Llama 3 or Mistral). Responses include source citations derived from the retrieved documents.
sentence-transformers"] RET["Vector retriever
top k similarity search"] RANK["Reranker
cross encoder scoring"] AUG["Prompt augmenter
release context injection"] LLM["LLM Inference
DigitalOcean GenAI Platform
Llama 3 Β· Mistral"] end subgraph CORPUS ["Knowledge Corpus"] DB_V[("versions")] DB_R[("reddit")] IDX[("FAISS vector index")] end USER --> Q --> RET DB_V & DB_R --> IDX IDX --> RET --> RANK --> AUG --> LLM --> ANS(["Grounded answer
with source citations"]) classDef db fill:#f1f5f9,stroke:#e2e8f0,color:#0f172a classDef chat fill:#fef2f2,stroke:#fca5a5,color:#0f172a class DB_V,DB_R,IDX db class Q,RET,RANK,AUG,LLM chat
Embedding model
sentence-transformers all-MiniLM-L6-v2 or OpenAI text-embedding-3-small. Encodes release notes and Reddit posts into dense 384 or 1536 dimensional vectors indexed in FAISS.
LLM
Served via DigitalOcean GenAI Platform. Llama 3 70B or Mistral 7B receives an augmented prompt containing retrieved release context and returns a grounded, cited answer.
Vector store
FAISS in memory index rebuilt at startup from both collections. Top k cosine similarity retrieval with configurable k (default 10 documents per query).
Retrieval strategy
Hybrid: dense vector search over embeddings plus sparse BM25 keyword match over version IDs and CVE strings. Results merged and reranked before prompt injection.
Request Lifecycle: Version search call path
Canonical read path through the stack for a version search call.
unless start or end param overrides
Health & meta
Endpoints collapsed by default, ordered method-first then route.
GET/api/health
Lightweight health check. No database query.
curl "https://releasetrain.io/api/health"{ "ok": true, "service": "releasetrain", "serverTime": "2026-03-25T17:00:00.000Z" }GET/api/meta
Diagnostics route that pings the database and reports collection names.
curl "https://releasetrain.io/api/meta"{ "ok": true, "dbName": "releasetrain", "ping": { "ok": 1 }, "collections": { "versions": "versions", "users": "users" } }Authentication
Auth at a glance
Stateless JWT auth. Register or log in to get a token, then send it as Authorization: Bearer <token> on any endpoint tagged requires login or admin only. Tokens expire after 7 days.
Endpoints collapsed by default, ordered method-first then route.
POST/api/auth/login
Verify email and password, issue a 7-day JWT, and record lastLoginAt/previousLoginAt on the user document.
curl -X POST "https://releasetrain.io/api/auth/login" -H "Content-Type: application/json" -d '{"email":"user@example.com","password":"correcthorsebattery"}'{ "success": true, "token": "eyJhbGciOi...", "user": { "id": "660c38fce3cba9423e4f8f23", "email": "user@example.com", "role": "user", "name": null, "orgs": [], "inventory": [] } }POST/api/auth/logout
No-op for symmetry: JWTs are stateless, so signing out is purely a client-side token discard. Included so a client can call a real endpoint on sign-out instead of special-casing it.
curl -X POST "https://releasetrain.io/api/auth/logout" -H "Authorization: Bearer YOUR_JWT_TOKEN"{ "success": true }POST/api/auth/register
Create an account. The email domain must be an allowed real provider (Gmail, Outlook, Yahoo, iCloud, ProtonMail, AOL, etc.) or any .edu address, to keep disposable-mail signups out. Password must be at least 8 characters.
curl -X POST "https://releasetrain.io/api/auth/register" -H "Content-Type: application/json" -d '{"email":"user@example.com","password":"correcthorsebattery","name":"Ada Lovelace"}'{ "success": true, "user": { "id": "660c38fce3cba9423e4f8f23", "email": "user@example.com", "role": "user", "name": "Ada Lovelace", "orgs": [], "inventory": [] } }User accounts
Endpoints collapsed by default, ordered method-first then route.
DELETE/api/users/:id
Delete a user account by Mongo ObjectId.
curl -X DELETE "https://releasetrain.io/api/users/660c38fce3cba9423e4f8f23" -H "Authorization: Bearer YOUR_JWT_TOKEN"{ "success": true }GET/api/account/guardrails
The signed-in user's own saved per-guardrail overrides. Only ever contains keys for a guardrail that's actually tier: "optional" (see GET /api/guardrails) and that this user has explicitly set; a guardrail with no saved preference simply isn't a key here, and falls back to the admin default (that same endpoint's own effective field).
curl "https://releasetrain.io/api/account/guardrails" -H "Authorization: Bearer YOUR_JWT_TOKEN"{ "guardrailPrefs": { "vendorCheck": false } }GET/api/users/
Paginated list of all users, password hashes excluded.
curl "https://releasetrain.io/api/users/?limit=50&page=1" -H "Authorization: Bearer YOUR_JWT_TOKEN"{ "total": 214, "data": [ { "_id": "660c38fce3cba9423e4f8f23", "email": "user@example.com", "role": "user", "orgs": [], "inventory": [] } ] }GET/api/users/me
The signed-in user's own profile, password hash excluded. Any bring-your-own provider API key (Anthropic, Groq, Ollama) is returned masked, as a last-4 preview plus a set/not-set flag, never in full.
curl "https://releasetrain.io/api/users/me" -H "Authorization: Bearer YOUR_JWT_TOKEN"{ "_id": "660c38fce3cba9423e4f8f23", "email": "user@example.com", "role": "user", "orgs": [], "inventory": [], "anthropicKeySet": false, "anthropicKeyPreview": null }PUT/api/account/guardrails
Save the signed-in user's own per-guardrail overrides, persisted to their account (not global). Rejects with 400 if any given id is not tier: "optional" (see GET /api/guardrails): a mandatory guardrail can only be changed admin-side, via PUT /api/admin/settings. Returns the same {"guardrailPrefs"} shape reflecting what was actually saved.
curl -X PUT "https://releasetrain.io/api/account/guardrails" -H "Authorization: Bearer YOUR_JWT_TOKEN" -H "Content-Type: application/json" -d '{"guardrailPrefs":{"vendorCheck":false}}'{ "guardrailPrefs": { "vendorCheck": false } }PUT/api/users/:id
Update a user. A user may update their own name, password, provider API keys, orgs (max 2 alphanumeric/dash/underscore slugs) and inventory (installed-versions list, max 300 entries). Only an admin may target another user's ID or change role.
curl -X PUT "https://releasetrain.io/api/users/660c38fce3cba9423e4f8f23" -H "Authorization: Bearer YOUR_JWT_TOKEN" -H "Content-Type: application/json" -d '{"name":"Ada Lovelace","orgs":["pacific"]}'{ "success": true }Bookmarks
Bookmarks at a glance
A signed-in user's saved links. Each bookmark gets a random shareId at creation, letting anyone with the share link view the name/url/orgs without signing in.
Endpoints collapsed by default, ordered method-first then route.
DELETE/api/bookmarks/:id
Delete one of the signed-in user's own bookmarks.
curl -X DELETE "https://releasetrain.io/api/bookmarks/660c38fce3cba9423e4f8f23" -H "Authorization: Bearer YOUR_JWT_TOKEN"{ "success": true }GET/api/bookmarks/
List the signed-in user's own bookmarks, newest first, up to 100.
curl "https://releasetrain.io/api/bookmarks/" -H "Authorization: Bearer YOUR_JWT_TOKEN"{ "data": [ { "_id": "660c38fce3cba9423e4f8f23", "name": "Chrome stable channel", "url": "https://chromereleases.googleblog.com/", "shareId": "a1b2c3d4e5f60718", "orgs": [] } ] }GET/api/bookmarks/share/:shareId
Public lookup of a single bookmark by its share ID. Returns only name, url and orgs, no owner information.
curl "https://releasetrain.io/api/bookmarks/share/a1b2c3d4e5f60718"{ "name": "Chrome stable channel", "url": "https://chromereleases.googleblog.com/", "orgs": [] }POST/api/bookmarks/
Create a bookmark for the signed-in user. Requires name and url; a random shareId is generated and the user's current orgs are snapshotted onto it.
curl -X POST "https://releasetrain.io/api/bookmarks/" -H "Authorization: Bearer YOUR_JWT_TOKEN" -H "Content-Type: application/json" -d '{"name":"Chrome stable channel","url":"https://chromereleases.googleblog.com/"}'{ "success": true, "id": "660c38fce3cba9423e4f8f23", "shareId": "a1b2c3d4e5f60718" }PUT/api/bookmarks/:id
Rename one of the signed-in user's own bookmarks.
curl -X PUT "https://releasetrain.io/api/bookmarks/660c38fce3cba9423e4f8f23" -H "Authorization: Bearer YOUR_JWT_TOKEN" -H "Content-Type: application/json" -d '{"name":"Chrome release blog"}'{ "success": true }Reddit endpoints
Reddit at a glance
Ingestion, listing, subreddit filtering, update-related search, CVE text search, positive-score retrieval, monthly summaries, and single-item fetch/update. Some routes use page/limit paging; others also support cursor-based navigation.
Endpoints collapsed by default, ordered method-first then route.
GET/api/iot
Specialized Reddit view for IoT-style subreddits, with optional update-related filtering.
curl "https://releasetrain.io/api/iot?limit=100&page=1"GET/api/reddit
List Reddit docs, newest first. Supports page/limit, cursor paging, monthly filtering, and update-related filtering.
curl "https://releasetrain.io/api/reddit?limit=25&page=1&showCount=true"{ "data": [ { "title": "...", "created_utc": "..." } ], "totalCount": 25 }GET/api/reddit/:redditId
Fetch a single Reddit item by Mongo ObjectId or Reddit short id.
curl "https://releasetrain.io/api/reddit/1nq0h33"GET/api/reddit/:redditId/poll
Runs a real, billed LLM call: classifies each of the post's top-level, non-author comments as yes/no/unclear against the post's own question (its selftext, falling back to the title), and returns the tally. One batched model call per request, not one per comment.
curl "https://releasetrain.io/api/reddit/1nq0h33/poll" -H "Authorization: Bearer YOUR_JWT_TOKEN"{ "question": "Anyone else seeing this after the update?", "total": 12, "yes": 7, "no": 3, "unclear": 2, "breakdown": [ { "id": "c1", "author": "user123", "body": "Yeah, same here.", "verdict": "yes" } ] }GET/api/reddit/by-subreddit
Fetch by one or more subreddits, case-insensitive. Optional score, comment, pagination, and projection filters.
curl "https://releasetrain.io/api/reddit/by-subreddit?q=programming,technology&minScore=50&limit=25"GET/api/reddit/count
Total post count over the rolling two-year window.
curl "https://releasetrain.io/api/reddit/count"{ "totalRedditPosts": 248 }GET/api/reddit/meta/subreddits
Return all unique subreddits from the Reddit collection.
curl "https://releasetrain.io/api/reddit/meta/subreddits"{ "success": true, "count": 14, "data": ["programming", "technology"] }GET/api/reddit/query/cve
Text-search Reddit content for CVE-like strings.
curl "https://releasetrain.io/api/reddit/query/cve?q=CVE-&limit=25"GET/api/reddit/query/filter
Filter Reddit docs by comment count and predicted positive score window.
curl "https://releasetrain.io/api/reddit/query/filter?minComments=5&minScore=0.6&maxScore=0.95&limit=50"GET/api/reddit/query/positive
Returns all Reddit docs where metadata.predicted.positiveScore > 0.5, sorted by score descending.
curl "https://releasetrain.io/api/reddit/query/positive"{ "total": 83, "minScore": 0.5, "data": [ ... ] }GET/api/reddit/query/questions
Return Reddit docs where metadata.predicted.isUpdateRelated is true and a question marker appears in title or author description.
curl "https://releasetrain.io/api/reddit/query/questions?where=either&limit=25&page=1&showCount=true"GET/api/reddit/query/questions/suggest
Typeahead over real community questions already in the corpus, extracted from post titles/selftext. No LLM call.
curl "https://releasetrain.io/api/reddit/query/questions/suggest?q=mysql&limit=5"{ "query": "mysql", "results": [ "Anyone know if the MySQL 8.4 upgrade broke replication for others?" ] }GET/api/reddit/query/update-related
Filter Reddit documents by the nested update-related fields under metadata.labeled and metadata.predicted.
curl "https://releasetrain.io/api/reddit/query/update-related?isLabeled=true&isUpdateRelated=true&limit=25&page=1"GET/api/reddit/stats/by-month
Monthly counts for labeled training distribution.
curl "https://releasetrain.io/api/reddit/stats/by-month?startMonth=202401&endMonth=202412"GET/api/reddit/stats/summary
Range summary over Reddit data: total docs, risky docs, latest-update mentions, and CVE mentions.
curl "https://releasetrain.io/api/reddit/stats/summary?start=20240101&end=20241231"GET/api/subreddits/smoke
Simple footprint check to list distinct subreddits found in the Reddit collection.
curl "https://releasetrain.io/api/subreddits/smoke"{ "count": 14, "items": ["programming", "technology"] }POST/api/reddit
Insert or upsert a Reddit document by redditId.
curl -X POST "https://releasetrain.io/api/reddit" -H "Content-Type: application/json" -d '{"redditId":"1nq0h33","title":"Example","subreddit":"programming"}'PUT/api/reddit
Replace a Reddit document while preserving the existing Mongo _id.
curl -X PUT "https://releasetrain.io/api/reddit" -H "Content-Type: application/json" -d '{"redditId":"1nq0h33","title":"Updated"}'PUT/api/reddit/:redditId
Update a single Reddit item by ObjectId or redditId.
curl -X PUT "https://releasetrain.io/api/reddit/1nq0h33" -H "Content-Type: application/json" -d '{"title":"Retitled","score":88}'Version endpoints
Versions at a glance
Two flavors: older convenience routes like /api/v/ and the newer /api/v/search. For steady client integration, /api/v/search is the safer path: its filters and paging model are explicit.
Endpoints collapsed by default, ordered method-first then route.
GET/api/dashboard/mltl-risk
Dashboard aggregate for documents marked as MLTL risk. Optional component filter.
curl "https://releasetrain.io/api/dashboard/mltl-risk?q=chrome,firefox"GET/api/v/
Older convenience route: returns recent versions. Without q, a broad recent slice; with q, divides the limit across components.
curl "https://releasetrain.io/api/v/?q=chrome,firefox"{ "versions": [ ... ] }GET/api/v/:id
Fetch one version by Mongo ObjectId.
curl "https://releasetrain.io/api/v/660c38fce3cba9423e4f8f23"GET/api/v/aggregate/byDate
Count how many versions were released on a specific day.
curl "https://releasetrain.io/api/v/aggregate/byDate?date=20250723"{ "success": true, "date": "20250723", "count": 42 }GET/api/v/count
Total version count inside the rolling two-year window.
curl "https://releasetrain.io/api/v/count"{ "totalVersions": 54210 }GET/api/v/d/versionsByComponent
Return latest/current/CVE snapshots for one or more components.
curl "https://releasetrain.io/api/v/d/versionsByComponent?component=name:chrome,version:118"[ { "name": "chrome", "latestVersion": { ... }, "currentVersion": { ... }, "latestCveVersion": { ... } } ]GET/api/v/fc
Forecast the next release date for a single component.
curl "https://releasetrain.io/api/v/fc?q=chrome"[ { "component": "chrome", "releaseDate": "2026-04-07", "version": "135.0.0" } ]GET/api/v/fcc
Forecast coinciding release dates for multiple components.
curl "https://releasetrain.io/api/v/fcc?q=chrome,firefox"GET/api/v/latest10
Latest N versions per requested component.
curl "https://releasetrain.io/api/v/latest10?q=chrome,firefox&limit=10"GET/api/v/search
Unified read-only search with filters, projections, count, and cursor paging.
curl "https://releasetrain.io/api/v/search?q=chrome,firefox&limit=50&page=1&showCount=true"
curl "https://releasetrain.io/api/v/search?q=chrome&channel=patch&isCve=true&fields=versionId,versionNumber&limit=25"{ "data": [ { "_id": "...", "versionId": "20250217chrome1.2.3" } ], "totalCount": 314 }GET/api/v/stats/by-month
Monthly counts grouped by month and release channel, optionally filtered to selected components.
curl "https://releasetrain.io/api/v/stats/by-month?startMonth=202401&endMonth=202412&q=chrome,firefox"GET/api/v/versionId/:versionId
Fetch one version by business identifier rather than Mongo ObjectId.
curl "https://releasetrain.io/api/v/versionId/20250217chrome1.2.3"POST/api/v
Create a version document. The server normalizes versionNumber, infers the release channel, and fills timestamps/search tags.
curl -X POST "https://releasetrain.io/api/v" -H "Content-Type: application/json" -d '{"versionProductName":"chrome","versionNumber":"124.0.1","versionReleaseDate":"20260325","versionReleaseChannel":"patch"}'PUT/api/v/:id
Update an existing version by Mongo ObjectId.
curl -X PUT "https://releasetrain.io/api/v/660c38fce3cba9423e4f8f23" -H "Content-Type: application/json" -d '{"classification":{"componentType":["browser"]}}'PUT/api/v/versionId/:versionId
Update an existing version by business identifier. Refreshes versionTimestampLastUpdate.
curl -X PUT "https://releasetrain.io/api/v/versionId/20250217chrome1.2.3" -H "Content-Type: application/json" -d '{"newFieldName":"newValue"}'Component endpoints
Endpoints collapsed by default, ordered method-first then route.
GET/api/c/count
Total number of distinct components in the rolling two-year window.
curl "https://releasetrain.io/api/c/count"{ "totalComponents": 1440 }GET/api/c/frequency
Builds a component list from top components and those updated today.
curl "https://releasetrain.io/api/c/frequency"{ "totalComponents": 20, "components": ["chrome", "firefox"] }GET/api/c/name/:componentName/:versionNumber?
Fetch version history for a specific component, optionally narrowed to one exact version number.
curl "https://releasetrain.io/api/c/name/firefox"
curl "https://releasetrain.io/api/c/name/firefox/118.0.1"GET/api/c/names
Return distinct component names in the rolling two-year window.
curl "https://releasetrain.io/api/c/names"GET/api/c/os
Returns distinct component names classified as OS in the rolling two-year window.
curl "https://releasetrain.io/api/c/os"GET/api/component/
Search component records. Matches product name or predicted component type.
curl "https://releasetrain.io/api/component/?q=linux"Knowledge base
Knowledge base at a glance
Lets a vendor or user publish their own release directly into the versions collection (isVendorPublished: true), alongside the bot-collected data, and attach real-world upgrade experience reports to any release.
Endpoints collapsed by default, ordered method-first then route.
GET/api/knowledge/releases
List vendor-published releases, newest first, up to 100. With no Authorization header, returns every publicly-published release; with a Bearer token, narrows to just that caller's own published releases instead.
curl "https://releasetrain.io/api/knowledge/releases?q=acme"{ "data": [ { "versionId": "acme:widget:1.2.0", "versionProductName": "acme/widget", "versionNumber": "1.2.0", "isVendorPublished": true, "vendorNs": "acme", "publishedBy": "vendor@example.com" } ] }POST/api/knowledge/releases
Publish a release. vendorNs must be 3 to 32 lowercase alphanumeric/hyphen characters and must not collide with an existing bot-tracked vendor name; component and version are required; channel is one of patch/minor/major/security.
curl -X POST "https://releasetrain.io/api/knowledge/releases" -H "Authorization: Bearer YOUR_JWT_TOKEN" -H "Content-Type: application/json" -d '{"vendorNs":"acme","component":"widget","version":"1.2.0","channel":"minor","notesUrl":"https://acme.example.com/notes/1.2.0"}'{ "success": true, "id": "660c38fce3cba9423e4f8f23" }POST/api/knowledge/releases/:id/reports
Attach an upgrade experience report to a release. outcome must be one of success/issues/upgrade; fromVersion and description are optional.
curl -X POST "https://releasetrain.io/api/knowledge/releases/660c38fce3cba9423e4f8f23/reports" -H "Authorization: Bearer YOUR_JWT_TOKEN" -H "Content-Type: application/json" -d '{"outcome":"success","fromVersion":"1.1.0","description":"Clean upgrade, no config changes needed."}'{ "success": true }Aggregation endpoints
Endpoints collapsed by default, ordered method-first then route.
Measure volume, gaps, and classification counts across both collections. All date params use YYYYMMDD format. Range-based endpoints default to the rolling 2-year window when start/end are omitted.
Versions Β· /api/aggregate/v/*
GET/api/aggregate/v/typeBreakdown
CVE vs release-note split plus per-channel breakdown for a date range. Omit start/end to use the rolling 2-year window.
curl "https://releasetrain.io/api/aggregate/v/typeBreakdown?start=20250101&end=20251231"{
"range": { "start": "20250101", "end": "20251231" },
"total": 4821,
"cveCount": 1203,
"nonCveCount": 3618,
"byChannel": { "major": 312, "minor": 1540, "patch": 1766, "cve": 1203, "other": 0 }
}GET/api/aggregate/v/classificationSummary
Summarize security and breaking classification tags for one day.
curl "https://releasetrain.io/api/aggregate/v/classificationSummary?timestamp=20250723"{ "timestamp": "20250723", "total": 14, "classification": { "security-fix": 8, "breaking-change": 6 } }GET/api/aggregate/v/componentTypeCount
Count classified component types for a single day.
curl "https://releasetrain.io/api/aggregate/v/componentTypeCount?timestamp=20250730"{ "timestamp": "20250730", "total": 40, "components": { "browser": 8, "os": 6 } }GET/api/aggregate/v/cveCountByDay
Day-by-day count of CVE-channel versions over an explicit date range. Same shape as versionCountByDay, filtered to isCve: true.
curl "https://releasetrain.io/api/aggregate/v/cveCountByDay?start=20250701&end=20250730"{ "range": { "start": "20250701", "end": "20250730" }, "days": [ { "_id": "20250701", "count": 4 } ] }GET/api/aggregate/v/missingFields
Sample documents where a requested field is missing, null, or empty. Useful for data quality audits.
curl "https://releasetrain.io/api/aggregate/v/missingFields?field=versionNumber&limit=50"GET/api/aggregate/v/oldestTimestamp
Find the release date of the Nth newest document and compute its age in days.
curl "https://releasetrain.io/api/aggregate/v/oldestTimestamp?count=1000"{ "oldest": "20250723", "deltaInDays": 245 }GET/api/aggregate/v/sourceCountByType
Count one source type for a given day. sourceType: cve, major, minor, patch.
curl "https://releasetrain.io/api/aggregate/v/sourceCountByType?sourceType=cve×tamp=20250723"{ "timestamp": "20250723", "sourceType": "cve", "count": 18 }GET/api/aggregate/v/updateTypeCount
Count major, minor, patch, and other versions for a single day.
curl "https://releasetrain.io/api/aggregate/v/updateTypeCount?timestamp=20250723"{ "timestamp": "20250723", "major": 2, "minor": 5, "patch": 17, "other": 1 }GET/api/aggregate/v/versionCountByDay
Day-by-day version counts over an explicit date range.
curl "https://releasetrain.io/api/aggregate/v/versionCountByDay?start=20250701&end=20250730"{ "range": { "start": "20250701", "end": "20250730" }, "days": [{ "_id": "20250701", "count": 12 }] }Community Β· /api/aggregate/reddit/*
GET/api/aggregate/reddit/summary
Full overview in one call: totals, Reddit vs Stack Overflow split, top subreddits/components, and score stats. Omit start/end for the rolling 2-year window.
curl "https://releasetrain.io/api/aggregate/reddit/summary?topN=5"{
"range": { "start": "20240518", "end": "20260518" },
"total": 28340,
"bySource": { "reddit": 21050, "stackoverflow": 7290 },
"topSubreddits": [{ "_id": "android", "count": 4120 }, { "_id": "chrome", "count": 2980 }],
"score": { "avg": 14.3, "max": 4821, "totalWithPositiveScore": 19204 }
}GET/api/aggregate/reddit/count
Total post count plus Reddit vs Stack Overflow vs Server Fault split for a date range.
curl "https://releasetrain.io/api/aggregate/reddit/count?start=20250101&end=20251231"{ "range": { "start": "20250101", "end": "20251231" }, "total": 14820, "redditCount": 11340, "stackoverflowCount": 3070, "serverfaultCount": 410 }GET/api/aggregate/reddit/bySource
Counts grouped by source field. Documents without a source field are counted as reddit.
curl "https://releasetrain.io/api/aggregate/reddit/bySource"{ "range": { "start": "20240518", "end": "20260518" }, "total": 28340, "sources": { "reddit": 21050, "stackoverflow": 6420, "serverfault": 870 } }GET/api/aggregate/reddit/bySubreddit
Top subreddits or Stack Overflow components by post count, with average score. Filter by source to compare communities.
curl "https://releasetrain.io/api/aggregate/reddit/bySubreddit?limit=5&source=reddit"{
"range": { "start": "20240518", "end": "20260518" },
"source": "reddit", "limit": 5,
"subreddits": [{ "_id": "android", "count": 4120, "avgScore": 18.4 }]
}GET/api/aggregate/reddit/countByDay
Post count per day. Same shape as /api/aggregate/v/versionCountByDay. Filter by source to compare Reddit vs Stack Overflow ingestion cadence.
curl "https://releasetrain.io/api/aggregate/reddit/countByDay?start=20250701&end=20250730&source=stackoverflow"{ "range": { "start": "20250701", "end": "20250730" }, "source": "stackoverflow", "days": [{ "_id": "20250701", "count": 8 }] }Search events
Search events at a glance
Tracks what people search and ask, for the admin panel's activity views and for surfacing trending queries. Both a plain vendor/component search and a real /api/ask question land in the same search_events collection, tagged by kind.
Endpoints collapsed by default, ordered method-first then route.
GET/api/events/search
Recent search/ask events, newest first.
curl "https://releasetrain.io/api/events/search?limit=100" -H "Authorization: Bearer YOUR_JWT_TOKEN"{ "data": [ { "query": "chrome", "userId": "660c38fce3cba9423e4f8f23", "kind": "vendor", "timestamp": "2026-03-25T17:00:00.000Z" } ] }GET/api/events/search/top
Top N most-searched queries in the last 24 hours.
curl "https://releasetrain.io/api/events/search/top?n=5"{ "data": [ { "query": "chrome", "count": 42 }, { "query": "firefox", "count": 18 } ] }POST/api/events/search
Log a vendor/component search. Anonymous if no bearer token is sent; attributed to the caller's user ID otherwise.
curl -X POST "https://releasetrain.io/api/events/search" -H "Content-Type: application/json" -d '{"query":"chrome"}'{ "ok": true }Admin
Admin at a glance
Operational and moderation endpoints for the admin dashboard: bot freshness (plus its per-bot cadence thresholds), data quality attribution, MongoDB Atlas storage headroom, vendor-catalog alias curation and manual gap-fill, and a generic runtime settings store shared by the Ask pipeline defaults, the global rate limit, the registration email allowlist, nav-view visibility, and the eval tools' access levels.
Endpoints collapsed by default, ordered method-first then route.
DELETE/api/admin/vendor-aliases/:id
Remove a vendor alias by Mongo ObjectId.
curl -X DELETE "https://releasetrain.io/api/admin/vendor-aliases/660c38fce3cba9423e4f8f23" -H "Authorization: Bearer YOUR_JWT_TOKEN"{ "ok": true }GET/api/admin/bot-cadence
Each collector bot's default expected-update cadence (in days, the same values /api/admin/bot-health checks against), plus any admin-set override that replaces a bot's default. The System overview panel's Bot health card always reflects the effective value (override if set, else default).
curl "https://releasetrain.io/api/admin/bot-cadence" -H "Authorization: Bearer YOUR_JWT_TOKEN"{ "defaults": { "chrome.py": 21, "firefox.py": 21, "mysql.py": 120 }, "overrides": { "mysql.py": 90 } }GET/api/admin/bot-health
Checks how recently each collector bot has actually written new data, against a per-bot expected cadence (e.g. Chrome/Firefox every 21 days, MySQL every 120). Flags any bot past its cadence as stale.
curl "https://releasetrain.io/api/admin/bot-health" -H "Authorization: Bearer YOUR_JWT_TOKEN"{ "checkedAt": "2026-03-25T17:00:00.000Z", "stale": [ { "bot": "mysql.py", "lastSeen": "2025-11-01", "ageDays": 144, "maxDays": 120 } ], "healthy": [ { "bot": "chrome.py", "lastSeen": "2026-03-24", "ageDays": 1, "maxDays": 21 } ], "noData": [] }GET/api/admin/overview
Bundles bot health, source attribution, storage usage, top-line collection counts, user growth, and search/ask query volume into one response, so the admin dashboard's first screen is a single request.
curl "https://releasetrain.io/api/admin/overview" -H "Authorization: Bearer YOUR_JWT_TOKEN"{
"checkedAt": "2026-03-25T17:00:00.000Z",
"botHealth": { "stale": [], "healthy": [ "..." ], "noData": [] },
"sourceAttribution": { "total": 54210, "unknown": 812, "missing": 0, "pct": 1.5 },
"storage": { "storageMb": 210.4, "dataMb": 180.2, "indexMb": 22.1, "limitMb": 512, "pct": 0.411 },
"counts": { "versionsTotal": 54210, "cveTotal": 12030, "releaseNotesTotal": 42180, "redditTotal": 21050, "stackoverflowTotal": 7290 },
"users": { "total": 214, "newLast7Days": 6, "newSinceLastLogin": 2 },
"queries": { "total": 8340, "last7Days": 412 },
"botGapLog": { "total": 18, "success": 11, "recent": [ "..." ] }
}GET/api/admin/settings
Current values of every admin-tunable runtime setting: the Ask pipeline defaults, the global per-IP rate limit (plus a separate, higher adminRateLimitPerMinute ceiling for a request whose own JWT has role: "admin"), the registration email domain allowlist, which nav views are visible, each eval tool's access level, and the guardrails registry (every deterministic safety/correctness check applied to Ask answers, each with its tier of "mandatory" or "optional" and its current admin-set enabled value; see the public GET /api/guardrails below for the per-caller effective view of the same list).
curl "https://releasetrain.io/api/admin/settings" -H "Authorization: Bearer YOUR_JWT_TOKEN"{ "askRecentWindowDays": 14, "askDefaultPreset": "auto", "askDefaultProvider": "ollama", "askDefaultSize": "medium", "rateLimitPerMinute": 120, "allowedEmailDomains": "gmail.com,outlook.com", "viewGraphVisible": true, "viewDocsVisible": true, "evalRewriterAccess": "admin", "evalEvaluatorAccess": "admin", "evalOrchestratorAccess": "admin", "guardrails": [ { "id": "toolResultInjectionScan", "tier": "mandatory", "label": "Scan retrieved content for prompt injection", "description": "Flags tool results that try to redirect the model's own instructions before they reach it.", "enabled": true }, { "id": "vendorCheck", "tier": "optional", "label": "Require a resolvable vendor/product", "description": "Declines outright if the question names no vendor/product this system tracks.", "enabled": true } ] }GET/api/admin/source-attribution
What fraction of the versions collection has no confident sourceBot attribution ("unknown" or missing entirely). A rising percentage signals a bot's source-inference rule needs updating.
curl "https://releasetrain.io/api/admin/source-attribution" -H "Authorization: Bearer YOUR_JWT_TOKEN"{ "total": 54210, "unknown": 780, "missing": 32, "pct": 1.5, "byBot": [ { "_id": "chrome.py", "count": 4210 }, { "_id": "unknown", "count": 780 } ] }GET/api/admin/storage
MongoDB Atlas storage/data/index size against the M0 free-tier's 512MB shared cap.
curl "https://releasetrain.io/api/admin/storage" -H "Authorization: Bearer YOUR_JWT_TOKEN"{ "storageMb": 210.4, "dataMb": 180.2, "indexMb": 22.1, "limitMb": 512, "pct": 0.411, "collections": 8, "objects": 1204830 }GET/api/admin/vendor-aliases
Every manually-curated vendor alias, correcting or adding a vendor name the automatic catalog (built from tracked release data and Reddit subreddit names) doesn't resolve on its own.
curl "https://releasetrain.io/api/admin/vendor-aliases" -H "Authorization: Bearer YOUR_JWT_TOKEN"{ "data": [ { "_id": "660c38fce3cba9423e4f8f23", "alias": "ada", "canonicalName": "Ada", "createdAt": "2026-09-15T17:00:00.000Z" } ] }GET/api/views/visibility
Public: which nav-menu views are currently enabled, so a signed-out visitor's page load can hide a disabled view's link too. home and users can't be hidden by design.
curl "https://releasetrain.io/api/views/visibility"{ "viewGraphVisible": true, "viewArchVisible": true, "viewCveVisible": true, "viewDashboardVisible": true, "viewDocsVisible": true, "viewChangelogVisible": true, "viewAckVisible": true, "viewNetworkVisible": true, "viewEvalRewriterVisible": true, "viewEvalEvaluatorVisible": true, "viewEvalOrchestratorVisible": true }POST/api/admin/vendor-aliases
Add a vendor alias mapping one alternate spelling/name to its canonical name.
curl -X POST "https://releasetrain.io/api/admin/vendor-aliases" -H "Authorization: Bearer YOUR_JWT_TOKEN" -H "Content-Type: application/json" -d '{"alias":"ada","canonicalName":"Ada"}'{ "data": { "_id": "660c38fce3cba9423e4f8f23", "alias": "ada", "canonicalName": "Ada", "createdAt": "2026-09-15T17:00:00.000Z" } }POST/api/admin/vendor-gap-fill
Manually runs the same automatic-catalog gap-fill a bot's own fallback triggers for a real, web-verified vendor with zero tracked evidence (see the botGapLog field on GET /api/admin/overview). The attempt is logged the same as an automatic one, so it also shows up in that response's botGapLog.recent list.
curl -X POST "https://releasetrain.io/api/admin/vendor-gap-fill" -H "Authorization: Bearer YOUR_JWT_TOKEN" -H "Content-Type: application/json" -d '{"vendorName":"ada"}'{ "success": true }PUT/api/admin/bot-cadence
Set (or clear) one bot's cadence override. maxDays is a number from 1-365, or null to remove the override and fall back to that bot's default. Applies immediately, no restart needed, and is picked up by /api/admin/bot-health's next check.
curl -X PUT "https://releasetrain.io/api/admin/bot-cadence" -H "Authorization: Bearer YOUR_JWT_TOKEN" -H "Content-Type: application/json" -d '{"bot":"mysql.py","maxDays":90}'{ "defaults": { "chrome.py": 21, "firefox.py": 21, "mysql.py": 120 }, "overrides": { "mysql.py": 90 } }PUT/api/admin/settings
Patch one or more runtime settings. Applies immediately, no restart needed, and persists to the settings collection. Unrecognized keys are ignored; each known value is validated/clamped (e.g. askRecentWindowDays to 1-90, rateLimitPerMinute to 10-2000) before being applied and returned. allowedEmailDomains takes a comma-separated string; any .edu (or .edu.<country>) address is always allowed regardless of this list. guardrails takes an array of {"id","enabled"} patches merged into the existing registry by id; an unknown id is ignored. The response always echoes back the full merged settings object, including the full updated guardrails array.
curl -X PUT "https://releasetrain.io/api/admin/settings" -H "Authorization: Bearer YOUR_JWT_TOKEN" -H "Content-Type: application/json" -d '{"askRecentWindowDays":30,"rateLimitPerMinute":200,"allowedEmailDomains":"gmail.com,outlook.com","guardrails":[{"id":"vendorCheck","enabled":false}]}'{ "askRecentWindowDays": 30, "askDefaultPreset": "auto", "rateLimitPerMinute": 200, "allowedEmailDomains": "gmail.com,outlook.com", "evalRewriterAccess": "auth", "evalEvaluatorAccess": "admin", "evalOrchestratorAccess": "admin", "guardrails": [ { "id": "vendorCheck", "tier": "optional", "label": "Require a resolvable vendor/product", "description": "Declines outright if the question names no vendor/product this system tracks.", "enabled": false } ] }Test & discovery endpoints
Endpoints collapsed by default, ordered method-first then route.
GET/api/test/all
Runs a built-in suite of GET requests against selected routes and returns status plus payload samples.
curl "https://releasetrain.io/api/test/all"{ "totalGET": 11, "results": [ { "method": "GET", "path": "/api/v?q=chrome,firefox", "status": 200, "success": true } ] }GET/api/test/endpoints
Enumerates all registered routes and flags duplicates.
curl "https://releasetrain.io/api/test/endpoints"{ "totalEndpoints": 30, "endpoints": [ { "methods": ["GET"], "path": "/api/health" } ] }GET/api/test/endpoints/html
HTML view of discovered GET endpoints with generated example URLs and sample outputs.
curl "https://releasetrain.io/api/test/endpoints/html"Ask (AI Q&A)
Ask at a glance
Retrieval-augmented Q&A over the same versions/reddit corpus the rest of the API reads. A plain vendor/category name (e.g. "chrome") short-circuits to a document lookup with no model call and no sign-in required; a real question streams back live progress over Server-Sent Events and requires sign-in, since each one is a real, billed LLM call.
Which path a question actually takes: intent decides it first, then, for everything that isn't declined or a comparison, the preset's own architecture decides whether four roles run as genuinely separate model calls or one continuous tool-use loop.
intent"} INTENT -->|"opinion"| DECLINE["Declined
no retrieval"] INTENT -->|"comparison"| CMP["Fixed evidence gather
per side, no agents"] CMP --> CMPANS(["Answer"]) INTENT -->|"version Β· cve Β· patch Β· general"| ARCH{"Architecture"} ARCH -->|"single-agent Β· buggy Β· fixed"| LOOP["One continuous
tool-use loop"] LOOP --> LOOPANS(["Answer
deterministic version fix"]) ARCH -->|"delegated Β· feedback loop"| RW["Rewriter"] --> RT["Retriever"] --> EV{"Evaluator"} EV -.->|"insufficient, feedback preset only"| RT EV -->|"sufficient"| OR["Orchestrator"] --> AGANS(["Answer"]) classDef decision fill:#eff6ff,stroke:#93c5fd,color:#0f172a classDef agent fill:#fffbeb,stroke:#fde68a,color:#0f172a classDef flat fill:#f1f5f9,stroke:#e2e8f0,color:#0f172a classDef done fill:#f0fdf4,stroke:#86efac,color:#0f172a class INTENT,ARCH,EV decision class RW,RT,OR agent class DECLINE,CMP,LOOP flat class CMPANS,LOOPANS,AGANS done
Endpoints collapsed by default, ordered method-first then route.
GET/api/ask/compare
Runs the same question through up to 5 presets in parallel, for side-by-side accuracy comparison. Defaults to single_agent,multi_agent_buggy,multi_agent_fixed if presets is omitted.
curl "https://releasetrain.io/api/ask/compare?question=Should+I+use+Node+or+Flask&presets=single_agent,multi_agent_fixed" -H "Authorization: Bearer YOUR_JWT_TOKEN"{ "question": "Should I use Node or Flask?", "runs": [ { "preset": "single_agent", "runId": "660c38fce3cba9423e4f8f23", "answer": "...", "sources": [ "..." ] }, { "preset": "multi_agent_fixed", "runId": "660c38fce3cba9423e4f8f24", "answer": "...", "sources": [ "..." ] } ] }Triggering the feedback loop: ask about a version for a product that plainly does not exist (so both internal retrieval and the deterministic web-search fallback come up empty, and the Evaluator judges the first pass insufficient) under multi_agent_feedback, the only preset with feedbackLoop on. Not a hard guarantee every single time, since the Evaluator's own verdict is a live model judgment call, not a fixed rule, but this is the reliable way to exercise it. Look for "feedbackLoopCount": 2 in the response (1 means it answered in one pass, no retry needed), or open that answer's own Feedback Loop tab in the UI.
curl "https://releasetrain.io/api/ask/compare?question=What+is+the+latest+version+of+Quantavox+Studio&presets=multi_agent_feedback" -H "Authorization: Bearer YOUR_JWT_TOKEN"GET/api/ask/history
The signed-in user's own past Ask runs, newest first.
curl "https://releasetrain.io/api/ask/history?limit=20" -H "Authorization: Bearer YOUR_JWT_TOKEN"{ "data": [ { "_id": "660c38fce3cba9423e4f8f23", "question": "What is the latest PHP version?", "answer": "...", "rating": 1, "createdAt": "2026-03-25T17:00:00.000Z" } ] }GET/api/ask/presets
The named retrieval-pipeline presets (single_agent, multi_agent_buggy, multi_agent_fixed, plus the delegated architectures) and the current admin-configured default.
curl "https://releasetrain.io/api/ask/presets"{ "presets": { "single_agent": { "label": "Single-agent (no rewrite)" } }, "defaultPreset": "auto" }GET/api/ask/providers
Available LLM providers (Anthropic, Groq, Ollama Cloud) and each one's small/medium/large model sizes, plus the current default preset/provider/size a new visitor's Ask form should start on.
curl "https://releasetrain.io/api/ask/providers"{ "providers": [ { "id": "anthropic", "label": "Anthropic", "sizes": [ { "id": "small", "label": "Small" } ] } ], "defaultPreset": "auto", "defaultProvider": "ollama", "defaultSize": "medium" }GET/api/ask/quota
Last-seen rate-limit headers per provider (Anthropic, Groq) plus how many calls this server process has made today. A snapshot from the last real /api/ask call, not a live check.
curl "https://releasetrain.io/api/ask/quota"{ "anthropic": { "remaining": 48, "limit": 50, "rateLimitedSecondsLeft": null }, "groq": { "remaining": 14400, "limit": 14400, "rateLimitedSecondsLeft": null } }GET/api/ask/recent-window-days
Public: the current admin-configured recency window (in days) Ask applies by default, so the feed's own lookback can track the same window instead of a separately hardcoded value.
curl "https://releasetrain.io/api/ask/recent-window-days"{ "askRecentWindowDays": 14 }GET/api/guardrails
Public, with optional auth: every guardrail applied to Ask answers, each with the admin's raw enabled setting, the effective value that actually applies to the calling user right now (a mandatory guardrail's effective always equals enabled; an optional one's is the caller's own saved preference if signed in and set, else the admin default), and configurable (true only when the guardrail is tier: "optional" and the caller is signed in). Send Authorization: Bearer <token> to get a signed-in caller's own effective/configurable values; omit it for the signed-out view.
curl "https://releasetrain.io/api/guardrails" -H "Authorization: Bearer YOUR_JWT_TOKEN"{ "guardrails": [ { "id": "toolResultInjectionScan", "tier": "mandatory", "label": "Scan retrieved content for prompt injection", "description": "Flags tool results that try to redirect the model's own instructions before they reach it.", "enabled": true, "effective": true, "configurable": false }, { "id": "vendorCheck", "tier": "optional", "label": "Require a resolvable vendor/product", "description": "Declines outright if the question names no vendor/product this system tracks.", "enabled": true, "effective": false, "configurable": true } ] }POST/api/ask
Ask a question. A bare vendor/category name resolves instantly as plain JSON ({"intent":"documents",...}), no sign-in needed. A real question streams back text/event-stream progress events ending in one result (or error) event, and requires sign-in. config accepts preset (or "auto" to classify intent server-side), provider, size, and the vendorCheck/temporalFilter/intentFilter toggles. Question is capped at 500 characters. The result event also carries guardrailActivity (which of the mandatory guardrails, see GET /api/guardrails, actually did something for this specific answer) and, on any source a guardrail is responsible for surfacing, a guardrail field naming it.
curl -N -X POST "https://releasetrain.io/api/ask" -H "Authorization: Bearer YOUR_JWT_TOKEN" -H "Content-Type: application/json" -d '{"question":"Was the WebView bug patched?","config":{"preset":"auto"}}'data: { "type": "progress", "phase": "retrieving", "detail": "Searching versions and reddit" }
data: { "type": "result", "runId": "660c38fce3cba9423e4f8f23", "answer": "...", "sources": [ "..." ], "abstained": false }POST/api/ask/:runId/rate
Rate one of the caller's own past runs helpful (1) or not helpful (-1).
curl -X POST "https://releasetrain.io/api/ask/660c38fce3cba9423e4f8f23/rate" -H "Authorization: Bearer YOUR_JWT_TOKEN" -H "Content-Type: application/json" -d '{"rating":1}'{ "success": true }Ask pipelines
Which process POST /api/ask runs, by the question's own classified intent. Preset "auto" resolves to one of these before the model is ever called (see pickAutoPipeline in ask.js); any other preset value runs that one directly regardless of intent. "Research type" is the general question-type category each row corresponds to in the wider question-classification literature, not this system's own terms.
| Research type | Type | Intent | Process | Example |
|---|---|---|---|---|
| Decision-making | Comparison | comparison-question | Delegated + feedback loop | "Should I use Node or Flask?" |
| Factoid, verify | Security | cve-question | Union search + BM25 rerank | "Any recent CVEs in MySQL?" |
| Factoid, verify | Patch | patch-question | Union search + BM25 rerank | "Was the WebView bug patched?" |
| Factoid, numeric | Version | version-question | Single-agent | "What's the latest PHP version?" |
| How-to | General | general-question | Delegated, no feedback loop | "How do I roll back a Windows update?" |
| Review/opinion | Opinion | opinion | Declined, no retrieval | "What's the best language?" |
Eval tools (admin)
Eval tools at a glance
Research/diagnostic tools that run a real retrieval pass, and a real, billed LLM call, to measure how much each pipeline stage actually changes the outcome: does the Rewriter's query rewrite help retrieval, does the Evaluator's deterministic override actually flip its verdict, does the Orchestrator's version-correctness check actually change its answer. Each tool's access level (disabled / admin / auth / public) is admin-configurable via PUT /api/admin/settings; admin is the default for all three.
Endpoints collapsed by default, ordered method-first then route.
GET/api/eval-rewriter/sample
Returns one real, already-classified community question, sampled from Reddit posts predicted update-related, to seed an eval run so testing doesn't require hand-writing a question.
curl "https://releasetrain.io/api/eval-rewriter/sample" -H "Authorization: Bearer YOUR_JWT_TOKEN"{ "question": "Anyone know if the MySQL 8.4 upgrade broke replication for others?", "subreddit": "mysql", "url": "https://reddit.com/..." }POST/api/eval-evaluator/run
Runs the real retrieval pipeline and the Evaluator agent for a question, then reports its raw verdict alongside the final verdict after the same deterministic overrides /api/ask itself applies, and whether an override actually fired.
curl -X POST "https://releasetrain.io/api/eval-evaluator/run" -H "Authorization: Bearer YOUR_JWT_TOKEN" -H "Content-Type: application/json" -d '{"question":"Was the WebView bug patched?","config":{"provider":"anthropic","size":"medium"}}'{ "question": "Was the WebView bug patched?", "rawVerdict": { "sufficient": false, "reason": "..." }, "finalVerdict": { "sufficient": true, "reason": "Overridden: a search_web result with real content was found." }, "overridden": true, "model": "claude-...", "provider": "anthropic" }POST/api/eval-orchestrator/run
Runs the same retrieval and Evaluator gate as the Evaluator eval, then reports the Orchestrator's raw generated answer alongside the final answer after the same version-correctness rewrite /api/ask applies, and whether it actually changed anything.
curl -X POST "https://releasetrain.io/api/eval-orchestrator/run" -H "Authorization: Bearer YOUR_JWT_TOKEN" -H "Content-Type: application/json" -d '{"question":"What is the latest PHP version?"}'{ "question": "What is the latest PHP version?", "abstained": false, "rawAnswer": "...", "finalAnswer": "The latest php version is 8.4.2, released 2026-01-15.", "overridden": true, "model": "gpt-oss:120b", "provider": "ollama" }POST/api/eval-rewriter/run
Runs retrieval twice for the same question, once using the Rewriter agent's search terms and once using the raw question text, and reports each side's sources side by side, to measure whether the Rewriter step actually improves retrieval.
curl -X POST "https://releasetrain.io/api/eval-rewriter/run" -H "Authorization: Bearer YOUR_JWT_TOKEN" -H "Content-Type: application/json" -d '{"question":"Anyone know if the MySQL 8.4 upgrade broke replication?"}'{ "question": "Anyone know if the MySQL 8.4 upgrade broke replication?", "rewriterTerms": ["mysql 8.4 replication"], "withRewriter": { "sources": [ "..." ], "toolCallsUsed": 2 }, "withoutRewriter": { "sources": [ "..." ], "toolCallsUsed": 3 }, "model": "gpt-oss:120b", "provider": "ollama" }β‘ Quick Start
Three requests that cover the most common use cases. Paste any into a terminal to verify connectivity and explore the response shape. Base URL: https://releasetrain.io Β· All GET endpoints are public and unauthenticated.
What released in the last 7 days?
curl "https://releasetrain.io/api/v/search?start=20260511&end=20260518&limit=25&showCount=true"
Any CVEs published this month?
curl "https://releasetrain.io/api/v/search?channel=cve&start=20260501&end=20260531&limit=50&showCount=true"
What is Reddit saying about Chrome right now?
curl "https://releasetrain.io/api/reddit/by-subreddit?q=chrome&minScore=5&limit=25"
Latest 10 Firefox releases with key fields only
curl "https://releasetrain.io/api/v/latest10?q=firefox&limit=10"
Forecast Chrome's next release date
curl "https://releasetrain.io/api/v/fc?q=chrome"
π Data Models
Two MongoDB collections store all release intelligence. Not every document has every field β the schema evolves as new sources are added.
versions collection
One document per software version release. Written by the bot fleet; read by /api/v/* and /api/aggregate/*.
| Field | Type | Description |
|---|---|---|
_id | ObjectId | MongoDB document ID |
versionId | string | Composite key: YYYYMMDD + productName + versionNumber. Unique per release. |
versionProductName | string | Normalised product name, lowercase. e.g. chrome, firefox |
versionNumber | string | Semver string. e.g. 124.0.1 |
versionReleaseDate | string | Release date as YYYYMMDD |
versionReleaseChannel | string | Inferred: major Β· minor Β· patch Β· cve Β· other |
versionTimestamp | number | Unix milliseconds derived from versionReleaseDate |
versionTimestampLastUpdate | string | ISO-8601 datetime of last write |
isCve | boolean | true when channel is cve |
classification.componentType | string[] | e.g. ["browser"], ["os"], ["runtime"] |
classification.securityType | string[] | e.g. ["security-fix"] |
classification.breakingType | string[] | e.g. ["breaking-change"] |
metadata.predicted.isUpdateRelated | boolean | ML prediction: is this an update-related version? |
metadata.predicted.positiveScore | number | Sentiment score 0β1. Above 0.5 is positive. |
metadata.labeled.isUpdateRelated | boolean|null | Human override. null = unlabeled. |
{
"_id": "660c38fce3cba9423e4f8f23",
"versionId": "20250217chrome124.0.1",
"versionProductName": "chrome",
"versionNumber": "124.0.1",
"versionReleaseDate": "20250217",
"versionReleaseChannel": "patch",
"versionTimestamp": 1739750400000,
"versionTimestampLastUpdate": "2025-02-17T10:00:00.000Z",
"isCve": false,
"classification": { "componentType": ["browser"] },
"metadata": {
"predicted": { "isUpdateRelated": true, "positiveScore": 0.72 },
"labeled": { "isUpdateRelated": null }
}
}
reddit collection
One document per Reddit post. Written by the scraper and ML labeller; read by /api/reddit/*.
| Field | Type | Description |
|---|---|---|
_id | ObjectId | MongoDB document ID |
redditId | string | Reddit short ID, e.g. 1nq0h33. Deduplication key. |
title | string | Post title |
subreddit | string | Subreddit name without prefix, e.g. programming |
author_description | string | Post body / selftext |
score | number | Reddit upvote score at ingestion time |
num_comments | number | Comment count at ingestion time |
created_utc | string | ISO-8601 datetime of original Reddit post |
updatedAt | string | ISO-8601 datetime of last upsert |
comments | object[] | Top-level comment objects from the thread |
metadata.predicted.isUpdateRelated | boolean | ML prediction: does this post discuss a software update? |
metadata.predicted.positiveScore | number | Sentiment score 0β1 |
metadata.labeled.isUpdateRelated | boolean|null | Human label. null = unlabeled. |
{
"_id": "69d176bbda0850f83829b2d6",
"redditId": "1nq0h33",
"title": "Chrome 124 breaks extension manifest v2",
"subreddit": "chrome",
"author_description": "After updating to 124.0.1 my uBlock Origin stopped...",
"score": 342,
"num_comments": 87,
"created_utc": "2025-02-18T09:14:00.000Z",
"updatedAt": "2025-02-18T12:00:00.000Z",
"metadata": {
"predicted": { "isUpdateRelated": true, "positiveScore": 0.21 },
"labeled": { "isUpdateRelated": true }
}
}
π Pagination Guide
The API supports two paging schemes. Use page/limit for random access; use cursor for efficient forward scrolling through large result sets without offset drift.
Page / Limit
| Param | Description |
|---|---|
page | 1-based page number. Default: 1 |
limit | Documents per page. Default: 25. Pass limit=all to disable paging (large collections only). |
showCount=true | Adds totalCount to the response body at the cost of an extra countDocuments call. |
curl "https://releasetrain.io/api/v/search?q=chrome&limit=50&page=2&showCount=true"
# response: { "data": [...], "totalCount": 314 }
Cursor (forward-only)
| Param | Description |
|---|---|
cursor | Opaque token from the X-Next-Cursor response header. Omit for the first page. |
# First page β capture the X-Next-Cursor response header
curl -i "https://releasetrain.io/api/v/search?q=chrome&limit=50"
# Subsequent page
curl "https://releasetrain.io/api/v/search?q=chrome&limit=50&cursor=TOKEN"
Support by endpoint
| Endpoint | Page/Limit | Cursor |
|---|---|---|
/api/v/search | β | β |
/api/v/latest10 | β | β |
/api/reddit | β | β |
/api/reddit/by-subreddit | β | β |
/api/reddit/query/cve | β | β |
/api/reddit/query/questions | β | β |
/api/reddit/query/update-related | β | β |
/api/iot | β | β |
π€ ML Fields
Two predicted fields are added to every Reddit document by the bot ML labeller. Human overrides live alongside predictions so consumers can choose which branch to trust.
metadata.predicted.isUpdateRelated
Text classifier trained on labeled Reddit posts. Predicts whether a post discusses a software update β a new release, patch announcement, upgrade discussion, or CVE advisory.
| Value | Meaning |
|---|---|
true | Post likely discusses a software update or release event |
false | Post predicted as not update-related |
| field absent | Document has not been scored yet |
Query predicted positives: /api/reddit/query/update-related?isLabeled=false&isUpdateRelated=true. Switch to isLabeled=true to use human labels.
metadata.predicted.positiveScore
Sentiment classifier output. Continuous score 0β1 reflecting community sentiment toward the update being discussed. Scores above 0.5 are considered positive.
| Range | Interpretation |
|---|---|
0.0 β 0.5 | Neutral to negative sentiment |
0.5 β 0.75 | Mildly positive |
0.75 β 1.0 | Strongly positive |
Retrieve high-confidence positives: /api/reddit/query/positive. Use /api/reddit/query/filter?minScore=0.75&maxScore=1.0 for a custom window.
Human labels vs predictions
Human labels live under metadata.labeled.isUpdateRelated and take precedence over predictions for training and evaluation. The Label view in releasetrain-client is the labelling interface. Pass isLabeled=true on any query route to read only human-verified data.
π Glossary
Domain-specific terms used throughout the API, codebase and this documentation.
| Term | Definition |
|---|---|
versionId | Composite business key: YYYYMMDD + productName + versionNumber. Unique per release. Used by /api/v/versionId/:id. |
versionReleaseChannel | Inferred semver category: major (breaking), minor (feature), patch (bugfix), cve (security advisory), other (non-standard). |
isCve | Set to true when a version document originates from a CVE or NVD advisory rather than a regular release channel. |
isUpdateRelated | Boolean: does a Reddit post discuss a software update? Stored under metadata.predicted (ML) and metadata.labeled (human). |
positiveScore | ML-predicted sentiment score 0β1. Reflects community tone toward the update discussed in a Reddit post. |
rolling 2-year window | Most read routes restrict results to the past two years by default. Override with ?start=YYYYMMDD&end=YYYYMMDD. |
redditId | Reddit's own short alphanumeric post ID, e.g. 1nq0h33. Used as the deduplication key on ingestion. |
cursor | Opaque pagination token from the X-Next-Cursor response header. Pass on the next request to continue without offset drift. |
componentType | Classification tag assigned during enrichment: browser, os, runtime, package, tool. |
MLTL | Multi-Language Temporal Logic. A spec-tracking module for cross-language version timeline analysis. |
JUSPN | Japanese specification release tracking module. Mirrors the EDI40-2023 stack matrix for Japanese standard editions. |
EDI40-2023 | EDI 4.0 2023 specification adoption tracker covering LAMP, MEAN, MERN, MEVN and WAMP stack version matrices. |
β Error Format
All error responses return JSON. Use the HTTP status code for programmatic branching; the message field is human-readable context.
| Status | When | Body shape |
|---|---|---|
200 OK | Success | { "data": [...] } or collection-specific shape |
400 Bad Request | Missing or invalid parameter | { "error": "Bad Request", "message": "..." } |
404 Not Found | Document ID does not exist | { "error": "Not Found", "message": "document not found" } |
500 Server Error | Unhandled exception or DB error | { "error": "Internal Server Error", "message": "..." } |
// 400 example
{ "error": "Bad Request", "message": "field param is required" }
// 404 example
{ "error": "Not Found", "message": "document not found" }
The /api/health and /api/meta routes use a slightly different shape: { "ok": true } on success and { "ok": false, "error": "..." } on failure.
π Field Projection
Several endpoints accept a fields query parameter that limits the fields returned per document β useful for reducing payload size when building lightweight dashboards or mobile clients.
# Return only title, subreddit and score
curl "https://releasetrain.io/api/reddit?limit=50&fields=title,subreddit,score"
# Return only key version fields
curl "https://releasetrain.io/api/v/search?q=chrome&fields=versionId,versionNumber,versionReleaseDate"
# Nested fields via dot notation
curl "https://releasetrain.io/api/reddit?fields=title,metadata.predicted.isUpdateRelated"
| Endpoint | Notes |
|---|---|
/api/v/search | All version fields including nested paths |
/api/reddit | All reddit fields including nested paths |
/api/reddit/query/cve | All reddit fields |
/api/reddit/query/questions | All reddit fields |
/api/reddit/query/update-related | All reddit fields |
/api/reddit/by-subreddit | All reddit fields |
_id is always returned regardless of the fields value. Nested paths use dot notation, e.g. metadata.predicted.positiveScore.
π Security and Access
Current access model for the REST API.
| Concern | Status |
|---|---|
| Authentication | None required for GET endpoints. The full read surface is public. |
| Write access | POST and PUT routes are intended for the bot fleet and are not token-guarded in the current version β treat them as internal. |
| CORS | Permissive. All origins are allowed for GET requests. Safe to call from browser JavaScript. |
| Rate limiting | No hard limit is enforced. For long-running integrations, cache responses locally and use cursor or start/end to request only new data. |
| HTTPS | All production traffic is served over HTTPS. HTTP redirects to HTTPS. |
| Data sensitivity | All data is derived from public sources (Reddit, public vendor advisories, NVD). No PII is stored. |
π Live Collection Stats
Fetched live from the API on first load. Rolling 2-year window. Est. size based on average document size.
π¦ Versions
| Total | β¦ |
| CVE advisories | β¦ |
| Release notes | β¦ |
| Est. size | β¦ |
π¬ Community
| Total | β¦ |
| Reddit posts | β¦ |
| Stack Overflow | β¦ |
| Server Fault | β¦ |
| Est. size | β¦ |
Loading freshness infoβ¦
CVE Lifecycle Pipeline
CVE Post Timeline
Source
Filters
π Changelog
Notable changes to releasetrain-client, newest first.
Ask panel: paper-shaped tabs, prominent sign-in
- feat The "About Ask" sidebar panel is now six tabs, structured like a paper (Intro, Related, Method, Result, Discussion, References), instead of one long flowing section. Existing content (the Pipeline diagram, the Multi-agent concept explanation, the Auto routing table, the related-work comparison table) moved into whichever tab it actually belongs under; new Result (the paper's own reported +17.2% 1-agent vs 4-agent retrieval-quality delta and zero-hallucination result), Discussion (known limits, how the Guardrails registry mitigates them), and References (the two papers this pipeline directly implements, plus the concurrent related work) tabs cover ground this panel never had anywhere before.
- fix Reported live: the small inline "sign-in" text link was too easy to miss next to the rest of the panel's plain copy, given signing in is what unlocks the whole Ask feature. Replaced with a full-width call-to-action button, shown above the tabs so it's visible regardless of which one is open.
Feedback Loop tab and preset badge fixes
- fix Reported live: the Feedback Loop tab looked unchanged after last update's new Rewriter/Retriever/Evaluator/Orchestrator guardrails, since it only ever read the numeric feedbackLoopCount field, which only the two genuinely delegated presets (Multi-agent, delegated / Multi-agent, feedback loop) set. It now reports every pipeline-level retry guardrail that applies to this specific answer, with a plain explanation when a preset (e.g. Multi-agent, fixed) doesn't use a separate Rewriter/Retriever/Evaluator loop at all.
- fix Reported live: a plain "recent CVEs affecting MySQL" question run under Multi-agent (fixed) showed the badge "Multi-agent, fixed · 1 agent", reading as a flat contradiction the same way a comparison question's badge already had one fix for. Multi-agent (buggy)/(fixed) are genuinely single-continuous-loop architectures despite their own name (the paper's own naming: "buggy"/"fixed" describes that one loop's retrieval bug, not delegation), so the agent-count suffix is now suppressed for them instead of contradicting the label.
Feedback loops for every role: Rewriter, Retriever, Evaluator, Orchestrator
- feat The delegated multi-agent pipeline's single hardcoded retry (Retriever, then Evaluator again) is now an admin-configurable ceiling (new guardrail, "Retriever/Evaluator retry ceiling") instead of a fixed one-shot retry, and the per-answer Feedback Loop tab shows the real round count for that specific answer.
- feat New optional guardrail, "Let the Rewriter try different search terms on retry": off by default, a signed-in user can opt in for their own questions. When on, a retry regenerates a genuinely new set of search terms from the Rewriter agent instead of reusing the original terms with just the Evaluator's retry hint spliced on.
- fix New mandatory guardrail, "Retry a malformed Evaluator response": a response that failed to parse as the required JSON shape was previously treated the same as a real "insufficient" verdict, with no distinction between "the model judged this insufficient" and "the model's response was garbled." Now retried up to an admin-configurable ceiling before being accepted.
- feat New mandatory guardrail, "Regenerate a hedge answer written despite real evidence": the delegated pipeline had no rescue at all for an Orchestrator hedge ("I don't have enough evidence") written despite real, structured evidence already collected, unlike the single continuous-loop pipeline, which already had one, just unconditionally. Both pipelines now share the same named, admin-configurable check.
Comparison answers: fixed counts, and a new guardrail
- fix Reported live: a comparison answer stated "Teams recorded 8 known vulnerabilities" when the real tracked total was 23. The server's evidence gathering was reading its own capped, 8-document fetch (sized to keep the LLM's prompt small) as if it were the true count; comparison answers now state the real, uncapped count of vulnerabilities, updates, and community reports.
- feat New mandatory guardrail, "Verify and correct the stated time window in comparison answers": a free-tier model can restate the recency window it was given wrong (seen live stating "a 90-day window since June 19" when the real window searched was 3 days since Sep 14); the real window is now appended deterministically instead. Shows up on that answer's own Guardrails tab when it fires.
A Feedback Loop tab, next to Guardrails
- feat The answer rail gets a sixth tab, Feedback Loop: this answer's own rating, real user-rating stats for this question's vendor across every user, and whether an admin-set threshold currently flags that vendor as running negative. Read-only for now (turns the thumbs-up/down rating collected since Ask launched, but never read back anywhere, into an actual signal); it does not yet change how a future answer for a flagged vendor gets produced.
- feat New "Feedback Loop" section in the Account view's admin area, next to Guardrails: an editable minimum-sample-size and negative-rating-percentage threshold (with an enable toggle), backed by the server's
feedbackThresholdsfield on the existingGET/PUT /api/admin/settings. - feat The Feedback Loop tab also shows this exact answer's own loop count: how many retrieval/evaluation rounds the delegated multi-agent pipeline actually took (1 normally, 2 when the Evaluator judged the first pass insufficient and
multi_agent_feedback's own retry fired), a new structuredfeedbackLoopCountfield instead of that fact only living inside a free-text summary.
Server Fault split out from the community counts
- feat releasetrain-bot's new serverfault.py posts into the same shared community collection as Reddit and Stack Overflow, tagged its own
source. The admin dashboard's profile stat row, System overview cards, and bot-health freshness list now show Server Fault as its own line instead of it silently landing inside the Reddit count. - fix The server's reddit/stackoverflow split counted "Reddit" as everything that wasn't literally
source: stackoverflow, so a doc from any other source landed in the Reddit bucket by default. Reddit, Stack Overflow, and Server Fault are now each counted explicitly across/api/reddit/countand every/api/aggregate/reddit/*endpoint.
Admin traffic gets its own rate limit
- fix Reported live: "Too many requests" on the Vendor catalog section, since the Account view's admin panel alone fires 6+ requests just loading one tab (dashboard, settings, guardrails, bot-cadence, vendor-aliases, users), sharing the same rate-limit bucket as anonymous public traffic. A signed-in admin now gets a separate, higher ceiling (the new Admin rate limit setting), so normal active admin use no longer competes with public traffic for the same budget.
- fix The generic Settings list tried to render the
guardrailsarray (added last update) through its plain number/text/checkbox fallback, showing a garbled "[object Object],[object Object]" row. The dedicated Guardrails section already renders it properly; the generic list now skips this one key.
A Guardrails tab on every answer
- feat The answer rail gets a fifth tab, Guardrails, next to Answer/Sources/Benchmark/Model vs Rules: the same Mandatory (admin-set, disabled here) and Optional (a signed-in user's own saved preference) list already in the Ask options panel, plus, unique to this tab, a plain-language note on any guardrail that actually did something for THIS specific answer (dropped a suspicious search result, verified a version number, forced a live web search, blocked a leaked answer), with a link that jumps to the affected source in the Sources tab when there is one.
- fix The server's own per-run "did this guardrail apply" flag was keyed only on whether the answer's text got rewritten, which missed the common case where a guardrail's seeded evidence alone already steered the model to the right answer with no rewrite needed. Verified live: "What is the latest version of MySQL?" with versionCorrectionRewrite off produced an unverified answer with no guardrail tag; re-enabled, the same question was correctly tagged.
Guardrails: a client UI for the server's new safety/correctness registry
- feat New Guardrails section in the Account view's admin area, alongside the other admin sections: every guardrail releasetrain-server now tracks (backed by the existing
GET/PUT /api/admin/settings, which now also carries aguardrailsarray), split into Mandatory (an admin can turn one off, at the cost of a specific documented safety/correctness fix) and Optional (the admin-set default a signed-in user may override for themselves), each with a checkbox and an explicit Save button. - feat New collapsed-by-default Guardrails panel in the live Ask options row, right next to the existing Vendor check/Temporal filter/Intent filter toggles (which are unchanged and serve a different, existing purpose: quick one-off per-question testing). Backed by the new public
GET /api/guardrails: every mandatory guardrail is listed read-only with a lock icon, and every optional one shows a checkbox reflecting what's actually in effect for the viewer right now. Signed in, that checkbox is yours to flip, saved immediately to your account via the newGET/PUT /api/account/guardrails; signed out, it's shown disabled at the admin default, with a link to sign in and customize it. - docs API Reference: documented the new
GET /api/guardrailsandGET/PUT /api/account/guardrailsroutes, and noted the newguardrailsfield on the existingGET/PUT /api/admin/settingsentries.
Feed panel header: fix crowding at the new 40% column width
- ux Reported live: at the left column's new, narrower 40% width, the "Recent Updates" heading wrapped onto a second line ("components)" alone) while the Sort dropdown and "Expand all" button stayed full size beside it, reading as cramped. The sort dropdown's own option text dropped its redundant "Sort: " prefix (e.g. "Sort: Most activity" → "Most activity", still exposed to screen readers via the select's own
aria-label), the button's padding tightened to its own instance, and the heading/controls all shrank a notch, so the row comfortably fits at this width.
Layout: give the right rail more room
- ux The two-column layout (main content left, the Ask intro/answer rail right) is now a 40/60 split instead of an even 50/50, so the rail's own wider content (the pipeline diagram, the Model vs Rules table) has more room to breathe.
- ux The narrower left column's base font size drops slightly (13px to 12px) to keep its plain-prose content comfortable at the new width.
Workflow diagram: fix a "Rewriter ran" contradiction, plus a CVE-count highlight
- fix The live per-answer workflow diagram mapped vendor resolution (a plain catalog lookup, on every preset) onto the same "Rewriter" node as a real Rewriter LLM call, so a single-loop preset (Single-agent, Multi-agent buggy/fixed, no real Rewriter step at all) still showed a "Rewriter" box completing with a real elapsed time, flatly contradicting the Model vs Rules tab's own "this preset's architecture never includes a separate Rewriter step" right next to it. Vendor resolution now gets its own node in the diagram, ahead of Rewriter.
- ux Reported live: a single-loop run's Model vs Rules tab typically checks Model on both Retriever and Orchestrator, which reads as "2 agents" sitting right under the answer badge's own "1 agent." Both numbers are correct, they just answer different questions (roles the model fulfilled vs. distinct agents involved); the tab now says so in a short note rather than leaving the two counts to silently disagree.
- feat The Ask pipeline diagram already added to the Docs page is now also shown in the Ask intro sidebar, before a question is asked.
- feat A CVE question's answer now highlights the stated count ("six CVEs") when the model's own text gives one, rather than an arbitrary single CVE ID plucked out of a list of several: the count is the fact that actually answers an "are there any recent CVEs" question. Falls back to a single ID, then a version number, exactly as before, when no count is stated.
Docs: a Mermaid diagram for the Ask pipeline
- feat New flowchart at the top of the Ask (AI Q&A) docs section: how a question's classified intent picks its path (declined, the fixed comparison evidence gather, or the general pipeline), and, for the general path, whether the preset's architecture runs the Rewriter/Retriever/Evaluator/Orchestrator as genuinely separate model calls (with the feedback-loop retry edge) or one continuous tool-use loop.
- fix Every Mermaid diagram in the Docs page (this new one and the six existing System Architecture diagrams) now actually stretches to fill its column: Mermaid stamps its own computed width as an inline
style="max-width:NNNpx", which silently won over the page's ownwidth:100%rule at equal specificity, same root cause already fixed for the live Ask answer workflow diagram.
Settings: hide the three Eval tool nav links entirely
- feat Three new Settings entries: Show Eval Rewriter/Evaluator/Orchestrator in the menu, using the same view-visibility mechanism already covering Graph/Arch/CVE/Risk Report/Docs/Changelog/Credits/Release. Hides the nav link entirely, for every viewer including admins, all default to visible. Separate from each tool's own API access level (Disabled/Admin only/Any signed-in user/Public): hiding the nav link doesn't change whether the raw endpoint still responds.
Ask intro panel: related work as a table, not a paragraph
- docs The "Related work" section now reads each paper's actual text (fetched live, not just summarized secondhand) into a compact 5-column table: Paper, Goal, Similar, Different, Example question, one key word bolded per cell. Replaces the earlier single paragraph with the same five papers now individually comparable at a glance.
Ask intro panel: multi-agent concept and related work
- docs Two new sections in the Ask feature's own intro sidebar (shown before a question is asked): "Multi-agent concept," explaining which presets genuinely run four separate model calls versus simulating the same roles in one continuous tool-use loop, and pointing to each answer's own Model vs Rules tab for the specific-run truth; and "Related work," naming the five multi-agent RAG papers this system's own architecture and Rewriter fix relate to, each linked to its arXiv page.
Eval Rewriter: show the source URL, not the title
- ux Eval Rewriter's With/Without/Common source lists now show each result's raw URL instead of its title, so a reader can see exactly where a result came from at a glance in this debugging/comparison view. The main answer's own Sources tab is unaffected and still shows the title.
Account: rate limiting, email allowlist, bot cadence, and vendor catalog admin controls
- feat New Settings entry: global rate limit (requests/min per IP), applied to every API route except
/api/health. - feat New Settings entry: allowed registration email domains, a comma-separated allowlist. Any
.edu(or.edu.<country>) address is always allowed regardless of this list. - feat New Bot health thresholds section in the Account view's admin area: an editable per-bot cadence override (with a "Reset to default" option) for every bot
/api/admin/bot-healthtracks, backed by the server's newGET/PUT /api/admin/bot-cadence. - feat New Vendor catalog section in the Account view's admin area: an alias manager (add/list/delete a manual vendor-name correction for the automatic catalog) plus a manual gap-fill trigger, backed by the server's new
/api/admin/vendor-aliasesandPOST /api/admin/vendor-gap-fill. - docs API Reference: documented all 6 new/changed admin routes above, and noted the two new Settings fields on the existing
GET/PUT /api/admin/settingsentries.
Docs: coverage for auth, users, bookmarks, Ask, admin, and eval routes
- feat The API Reference (Docs view) now documents roughly 40 previously-undocumented routes: authentication (register/login/logout), user accounts, bookmarks, the full Ask AI Q&A surface (ask/compare/history/rate/presets/providers/quota), the admin eval tools (Rewriter/Evaluator/Orchestrator), the knowledge-base release-publishing endpoints, search-event tracking, the admin dashboard endpoints (bot health, source attribution, storage, overview, settings), nav-view visibility, a Reddit post's community-sentiment poll, question typeahead, and a missing CVE-count-by-day aggregation. Every write-access endpoint now shows a "requires login" / "admin only" / access-level tag reflecting its actual auth middleware.
Settings: per-endpoint access control for eval tool APIs
- feat Three new Settings panel entries: Eval Rewriter/Evaluator/Orchestrator API access, each a Disabled / Admin only / Any signed-in user / Public choice, backed by releasetrain-server's new admin-configurable access-level mechanism (no code deploy needed to change it). All three default to Admin only, matching their previous hardcoded behavior exactly. This is separate from, and does not affect, the Eval tools' own admin-only nav link visibility.
Account: a System overview card for vendor gap-fills
- feat New "Vendor gap-fills" card in the admin System overview panel, backed by a new GET /api/admin/overview field: how many times ask.js's automatic wikipedia.py fallback (triggered when a real, web-verified vendor still has zero tracked evidence) actually resolved, plus the 10 most recent attempts with their outcome. This data was already being logged to a bot_gap_log collection; nothing ever read it back until now.
Answer badge: fix "Multi-agent Β· 1 agent" contradiction
- fix A comparison question always collapses to one write-up call regardless of which preset is picked, including under Auto (which itself picks Multi-agent, feedback loop for a comparison question), so the badge could read "MULTI-AGENT, FEEDBACK LOOP · 1 AGENT": naming the picked-but-unused preset right next to the real agent count, reading as a flat contradiction. The badge now says "Comparison" instead of the preset name for this case; which preset was actually selected, and the real reason it collapsed, stays fully explained on the Model vs Rules tab.
Answer badge: no round brackets, shows agent count
- fix The pipeline badge next to a question (e.g. "(MULTI-AGENT (FEEDBACK LOOP))") nested a bracket inside a bracket once a preset's own name carried a parenthetical qualifier. Preset names now use a comma ("Multi-agent, feedback loop") and the outer wrap is dropped entirely; the badge's own bold, uppercase, colored styling already sets it apart from the question next to it.
- feat The badge now also states how many distinct model calls actually produced this answer (e.g. "Multi-agent, feedback loop · 4 agents"), computed per run rather than assumed from the preset name: a comparison question always collapses to 1 regardless of preset, a genuinely delegated architecture is 4, everything else is 1, plus 1 more when a real web-verification call fired.
Model vs Rules: fix a comparison-question contradiction
- fix A comparison question ("Firefox or Chrome?") always runs a genuinely different, fully deterministic evidence pipeline, regardless of which preset is picked, but the table's fallback text didn't know that and blamed "single-agent architecture" for the missing Rewriter/Evaluator step even under Multi-agent (delegated). Every row now checks res.intent for this case and explains the real reason.
- feat Every row now checks at least one box: a step that never ran still had something decide that deterministically (the preset's own architecture, an intent that skips agentic steps entirely, or an abstain gate), so an honest 0/0 is now reserved only for a role genuinely never reached at all (an opinion question bypassing vendor resolution, or vendor checking turned off).
- fix Vendor resolution's Model checkbox now also checks when a real web-verification call ran but came back negative (previously only a successful match counted), and Retriever no longer claims the model chose search tools for a comparison question, which is entirely fixed and deterministic.
Workflow diagram: drop its placeholder min-height once loaded
- fix .ask-workflow-diagram's min-height (there only to avoid a layout jump while mermaid.render() is still loading) stayed in effect even after the diagram finished rendering, keeping the container floored at a fixed height regardless of how short the actual (now viewBox-tightened) content was. Cleared back to 0 the moment real content lands, so the answer text below moves up to meet it instead of leaving a fixed gap on top of the v3.84.2 viewBox fix.
Answer card: close the gap under the workflow diagram
- fix Mermaid's own viewBox reserved space below the rendered Rewriter/Retriever/Evaluator/Orchestrator row (its default padding, plus room for the curved "retry" edge), which scaled up along with everything else once stretched to the card's full width and read as a real gap between the diagram and the answer text. The viewBox is now re-tightened to the diagram's own rendered bounding box after every render.
- fix The phase caption under the diagram (e.g. "Generating answer... 1.4s") no longer reserves its min-height/margin once it's cleared back to empty at the end of a run, which was adding its own fixed gap on top.
Model vs Rules: fix vendor resolution's checkboxes
- fix The Vendor resolution row hardcoded both the Model and Rule checkboxes checked, even for a plain catalog-match vendor, which involves no model call at all. Now Model is checked only when the vendor was actually run through a real web-verification LLM judgment call; a catalog hit alone checks Rule only.
- fix The Meaning column now states the reason for each box that is actually checked (labeled "Model:"/"Rule:"), instead of one sentence describing the row regardless of which boxes are checked.
Ask: a "Model vs Rules" tab on every real answer
- feat New fourth tab on the answer rail, next to Answer/Sources/Benchmark: a table naming each role (vendor resolution, Rewriter, Retriever, Evaluator, Orchestrator) with a Model column and a Rule column (both plain disabled checkboxes, an indicator not a setting) and a plain-language Meaning column explaining what happened for either case. Driven entirely off this specific answer's own real fields, not a fixed description of the architecture: single_agent correctly shows no separate Rewriter/Evaluator step, a web-verified vendor shows the real search that confirmed it, and an Evaluator/answer override shows the actual reason it fired.
- fix Server-side: runAsk and runDelegatedAsk already computed whether the Evaluator's verdict or the final answer text got overridden by a deterministic check, but never exposed it. Threaded through as evaluatorRan/evaluatorOverridden/evaluatorOverrideReason/answerCorrected, same pattern as vendorWebVerified.
Two new admin-only eval pages: Evaluator and Orchestrator
- feat
π§ͺ Eval Evaluator: runs the real retrieval path, then shows the Evaluator's own raw sufficiency verdict next to the final verdict after the deterministic override (a real search_web hit, or a real release document naming the vendor and version) can force it to sufficient, exactly the same two checks and wording production uses. - feat
π§ͺ Eval Orchestrator: same retrieval and Evaluator gate, then the Orchestrator's own raw generated answer next to the final answer after the deterministic version-correctness rewrite can replace it. An abstained Evaluator verdict shows the abstain message directly, since there's nothing for the Orchestrator to write from, same as production. - ux Both reuse Eval Rewriter's own "Sample a real question," flat source list, and vertical-only-scroll treatment, so all three eval pages look and behave the same way.
Rewriter Eval: flat source lists, ellipsis actually works
- ux Removed the redundant "Original:" line from the Prompt section (the question box right above it already shows it); the section is just the Rewriter's actual output now.
- ux "Only with/without Rewriter" shortened to "With Rewrite"/"Without Rewrite", and their source lists (plus Common's) are now flat, with no separate Documented/Discussion group heading on top: each item's own icon (π¦/π΄ vs π¬/π§/π) already says which one it is. New shared askRenderSourceItems helper, factored out of askRenderSources' own per-item rendering.
- fix A long source title inside a Delta column could grow that whole column wider than intended instead of actually truncating with an ellipsis (a CSS Grid item's default min-width is auto, not 0 like a flex item's, so there was nothing to truncate against). Ellipsis truncation now works as originally intended.
Rewriter Eval: shorter labels, vertical-only scroll
- ux Prompt section's labels shortened to "Original:" and "Rewriter Prompt:", dropping the explanatory parentheticals now that the section's own heading already makes clear what each line is.
- fix The view only ever scrolls vertically now; anything long enough to otherwise force a sideways scrollbar breaks onto another line instead.
Rewriter Eval: cut the duplication, add a Prompt section
- ux Reported live as "too much": the full With/Without Rewriter lists repeated every source already shown once, split between the Delta and Common sections below them, for no added information. Removed both full lists; a compact summary line ("With Rewriter: N tool calls, N sources · Without: ...") replaces them.
- feat Added a Prompt section at the top: the raw question exactly as typed, right next to the Rewriter's own actual output. That output is the delta being tested here, previously only visible several sections further down.
- ux Common now sits inside a closed, click-to-expand
<details>block instead of always being fully shown; it's the least differentiating part of the comparison, so it no longer has to be scrolled past by default.
Rewriter Eval: page scroll, relative dates, tighter rows
- fix The view had no scroll region of its own on a page that disables native body scroll, so a long Delta list (13+ sources on one side, reported live) just got clipped with no way to reach the rest. Now scrolls like every other view (#ackView's own pattern).
- ux Removed the "Delta: what changed" label (the two sub-headings already say what it is); added a "Question: ..." line to the top of the Delta and Common boxes too, matching the two full-list boxes below them.
- ux Every source's long timestamp is now a short "Nd ago" (or "today"), and every list sorts newest-first, so comparing and scanning don't require parsing an ISO date by eye.
- ux Each source is its own single-line row, truncated with an ellipsis instead of wrapping a long title across several lines.
Rewriter Eval: delta leads, one scroll per side
- ux Delta now leads the results (renamed "Delta: what changed," a clear two-column Only-with/Only-without layout), Common comes next, and the two full evidence lists come last. The comparison itself, not the raw lists, is now the first thing you see.
- fix The With/Without Rewriter columns each scroll as one whole unit (label, subtitle, and its entire source list together) instead of the source list scrolling separately inside a fixed-height card.
- feat Both columns now show the actual question text, not just their own search terms.
- ux The question input, Sample, and Run controls sit on one line; the buttons are relabeled to just "Sample" and "Run".
Rewriter Eval: Common/Delta boxes, denser layout
- feat Added Common (sources both runs found) and Delta (sources only one side found) boxes below the two full evidence lists, so the actual effect of the Rewriter's search terms is visible at a glance instead of eyeballing two long lists by hand.
- ux The four boxes now sit in a real two-column grid (was flex-wrap, which could stack unpredictably depending on available width), each with its own capped-height scroll region so a long source list on one side doesn't force the page to grow just to keep both columns aligned. Source chips are smaller here than the normal Ask rail's, since fitting more per screen matters more for a side-by-side comparison. Question box is a plain single-line input instead of a textarea, and the explanatory paragraph under the heading is gone.
New admin-only Rewriter eval page
- feat Added
π§ͺ Eval Rewriter, an admin-only nav item that runs the Retriever twice on the same question: once with the Rewriter's own chosen search terms, once with the raw question text instead, everything else (vendor, allowed tools, tool-call budget) held constant. Both real evidence lists render side by side; a "Sample a real question" button pulls a genuine, already-classified community question instead of a made-up one. No automated LLM grading picks a winner, unlike the earlier promptfoo-based Eval page removed this session for its memory cost; this just shows both lists for a human to read directly.
Ask: show a source link for the fallback web search too
- feat Whenever a run's own retrieval found zero evidence, the pipeline already falls back to a real web search (deterministicWebFallback) for every preset, but that attempt was invisible once the answer finished. A successful fallback find already shows up as a normal clickable source; a failed one (reported live: "What's the latest powershell version?" abstained after this fallback's own search came up empty) now shows a brief note naming exactly what was searched, plus a one-click link to run the same search manually and verify, since the search engines this tool scrapes can intermittently block an automated request without blocking a real browser.
Ask: a delayed second feed refresh catches late backfills
- feat A web-verified vendor (see the pipeline-escalation work) can kick off a background Wikipedia-bot backfill that's still running when the answer comes back, so the feed's existing immediate refresh almost always raced it and found nothing yet even though the vendor genuinely gets posted a few seconds later. Reported live: "npm" answered correctly but the feed still said "No versions found." A second refresh now fires 6 seconds later, giving that backfill a real window to finish first; skipped if the search box no longer shows the same vendor by then.
Ask: fewer lines, one fewer confusing timestamp
- fix The workflow caption used to stay frozen on its last in-progress phase ("Generating answer⦠1.4s") even after the answer had fully finished, sitting right next to the card's own total latency chip ("6s") with no label telling the two apart. It now clears once the run finishes; the diagram itself still shows every node's own elapsed time.
- ux Removed the separate static "Thinkingβ¦" line shown while a question is running: the live caption right above it already says what's happening, so it was one more line with no extra information.
Ask: right-align the live workflow caption
- ux The "Generating answer⦠Ns"-style caption under the workflow diagram now sits at the bottom right instead of flush left.
Feed: a named component search skips the recency cap
- feat The 28-day (LOOKBACK_DAYS) recency cap used to apply to every result with no exceptions, including a named component search, so a link like
/?q=Hibernate,javacould come back empty for a component whose only tracked release predates that window. Searching for a specific vendor (typed into the search box, or pre-filled from a?q=URL) now shows everything tracked for it regardless of age; the default, no-search "Recent Updates" feed is unchanged.
Ask: fix vendor web verification search, show its evidence
- fix verifyVendorViaWeb was searching the raw question text ("Whats the latest gradle version?") instead of the extracted product name, which came back noisy enough to fail verification for a real, well-known product (Gradle). It now searches the extracted candidate plus "software" (e.g. "gradle software"), the same suffix trick the Wikipedia bot's own search variants already rely on, per the established "software gives the search better results" rule.
- feat Added a "Web Verification" section to the Sources tab whenever a run's vendor resolution escalated to a real web search, showing exactly what was searched and the raw results it was judged from, left and right, including on a "no vendor detected" abstain where it's the only way to see why.
Ask: show pipeline escalation to web verification
- feat When a question names a vendor this system doesn't track and the answer comes from a real web search verifying it instead (see the Wikipedia-fallback work), the workflow diagram now extends the single-agent pipeline with two more nodes, Web Search and Verify, spliced in between Rewriter and Retriever, live and timed the same as the other four. A question that never escalates still renders the exact same 4-node diagram as before.
- ux The answer card's preset badge reflects the escalation too, e.g. "SINGLE-AGENT + WEB VERIFICATION" instead of just "SINGLE-AGENT", so it's visible without opening the diagram.
Register: state which email providers are accepted
- ux The registration form now shows, up front, which email providers signup actually accepts (Gmail, Outlook, Yahoo, iCloud, ProtonMail, AOL, or a .edu address; disposable/temp-mail addresses aren't) instead of a viewer only finding out after a rejected submission. Matches the server's own existing allowlist exactly, not a new or separate rule.
Removed: the Eval admin research page
- fix The entire admin-only Eval page (nav item, view, compose panel) and its server-side backing (evalRunner.js, the promptfoo dependency, and every
/api/eval/*route) are removed. Loading promptfoo added roughly 110MB of RSS to every running server process, whether or not Eval was ever used, on a memory-capped 2GB production VM; even after lazy-loading it, actually using Eval permanently re-added that cost for the rest of that process's life (Node caches a module after its first require), which was still slowing the whole system down for every other feature sharing that VM. Removing the feature and its dependency entirely, rather than trying to further isolate its memory footprint, is the fix.
Eval: simplified to one question at a time
- ux Reworked the Eval page's toolbar into a single compose panel: a question box (type your own, or click "Suggest a random question" to fill it in, still freely editable) side by side with an expected-answer box, plus a Name field and one Run button. Replaces the old "N random questions at once" batch mode and the separate candidate-picker dropdown, both dropped as unnecessary complexity once real usage settled on evaluating one deliberately-chosen question per session.
- feat An expected answer typed into the compose box is now saved immediately when the session starts, not only after it finishes.
Eval: pick a specific question, and name your sessions
- feat Added an "Or pick a specific question" mode to the Eval page: load a pool of randomly-sampled candidates, each labeled with its real classified question type (cve/patch/version/opinion/comparison/general, the same classification "Auto" itself uses to route a question), and run a session on exactly the one you choose instead of trusting a type turns up in a random batch.
- feat Sessions can now be named, either up front (an optional "Name" field next to Run new evaluation / Run this question) or after the fact (a Rename control on the loaded session). Named sessions show their name in the Past sessions dropdown.
Fixed: Eval page had no way to scroll
- fix
#evalViewwas missing the sticky/height/overflow-y:autotreatment every other view already has (page-level scrolling is disabled entirely, so each view has to be its own scroll region). A session with more than a screen's worth of questions had no way to scroll down to see the rest.
New admin-only Eval page: pipeline research evaluation
- feat Added an admin-only
π§ͺ Evalnav item/view, backed by promptfoo on the server (evalRunner.js). Pick a flexible number of questions (1-20), and it draws a true random sample ($sample) of real, already-classified Reddit questions and runs every one through every pipeline preset (Single-agent, Multi-agent buggy/fixed/delegated/feedback loop, and Auto) side by side, for a human to rate π/π: the tool behind this session's RISE-seminar evaluation of the per-question-type pipeline routing decision. - feat Each sampled question ships with real ground truth to judge answers against: an editable "expected answer" box the admin fills in by hand, the real top-level Reddit comments on that same post (closest thing to ground truth for "did this happen to other people" questions, which no release note or CVE record can confirm or deny), and real matching vendor release-note/CVE records pulled from this system's own tracked data.
- ux A session runs in the background on the server (an N-question x 6-preset matrix is real model calls, genuinely minutes) and the page polls for progress; past sessions are kept and browsable from a dropdown, and ratings/expected answers are stored separately from real production usage stats (
eval_runs, neverask_runs).
Removed the vertical rule between selects and toggles
- fix
.ask-options-sep(the plain vertical rule separating the model/size/pipeline selects from the evidence-gating toggles) removed per request, markup and CSS both.
Close button pinned top-right; fewer wraps in the options panel
- fix The rail's close button (
margin-left:autoin a wrapping flex row) dropped to the bottom-right corner once#askOptionsPanelwrapped to more than one line, instead of staying in the top-right corner..ask-rail-headeris nowposition:relativewith the buttonposition:absolute; top:0; right:0, so it stays pinned to that corner regardless of how many lines the panel wraps to. - ux Tightened
.ask-options-panel's gap (10px → 6px) and.ask-preset-select's padding/font-size (0 8px/12px → 0 6px/11px), per request to reduce line breaks in the narrower rail column; more of the row's content now fits per line before wrapping.
Tighter answer rail: one-line heading, grouped toggles, no dead usage line
- fix A long question plus a long preset name (e.g. "Multi-agent (feedback loop)") wrapped
.ask-answer-headingto two lines, costing real vertical space in an already-tight column. The question now truncates with an ellipsis instead (.ask-answer-questionshrinks/truncates,.ask-answer-presetstaysflex-shrink:0so the bracket is always fully visible on that same line), per explicit request to reduce line breaks in the rail and avoid scrolling. - ux The three evidence-gating toggles (Vendor check/Temporal filter/Intent filter) are now grouped in
.ask-toggle-groupso they wrap together as one unit inside#askOptionsPanel's own row instead of splitting apart individually when the row runs out of width. - ux
relocateAskOptionsPanel()now lands#askOptionsPanelinside.ask-rail-header(sharing that row with the close button) instead of at the top of.ask-rail-colon its own otherwise-empty row, per request to put the close button next to an existing row rather than giving it one of its own. - fix Removed the "Usage: N call(s) today..." line: it read as permanently broken, stuck on "limits unknown until a request succeeds" for any provider that doesn't return real rate-limit headers (Ollama Cloud, the default, among them). The underlying quota fetch and the rate-limited-provider graying-out in the Model select are unaffected; only the visible text line is gone.
Submit button: no more solid dark fill, darker hourglass instead
- fix The
.btn-primaryadded last release to fix the submit arrow's low contrast turned into a solid near-black box around the loading hourglass, which read worse, not better. Per follow-up request, back to plain.btn-ghost(matching Clear and the bookmark button); the hourglass emoji itself (its own built-in colors, unaffected by CSScolor) is what actually needed to stand out, so#askSubmitBtn.ask-btn-loadingnow appliesfilter: brightness(0.6) saturate(1.3)to darken it directly instead of boxing it in a dark background.
Question moves inside the answer card, next to the pipeline
- ux The asked question used to sit outside the answer rail's card, in the rail's own static header (
#askRailQuestion); the pipeline name (e.g. "SINGLE-AGENT") was a separate bold uppercase line inside the card. Per request, the question moved inside the card as the first line, with the pipeline name right next to it in brackets, e.g. "whats the latest flask version? (single-agent)". Applies to the running/loading state (question only, no bracket yet since the pipeline isn't resolved until the answer arrives), the final single-pipeline answer, an error card, and Compare mode's rail rendering (question only, no single pipeline to bracket). The rail's header now holds only the close button. The narrow-screen modal is unaffected: it already shows the question in its own separate#askModalQuestionheader, so nothing was duplicated there.
Higher-contrast Ask submit button
- fix
#askSubmitBtn(the arrow, and the spinning hourglass shown while a question is running) had neither.btn-primarynor.btn-ghost, so it rendered with no explicit background at all and read as barely visible against the page. Added.btn-primary(dark background, white icon), matching the contrast every other primary action button on the page already has.
Even row height across every admin section
- fix A closed admin row with a Refresh button (Bookmarks, Installed versions, System overview, All users, Search & Ask activity) was visibly taller than a plain text-only one (Change password, Model provider keys, Organization namespaces), since the button's own padding and border added height the plain rows never had.
.ua-admin-headernow has amin-heightmatching the button's own outer height, so every row reads at the same height whether or not it has one.
Query preview names the vendors it actually found
- feat The "vendor required" flag in the query preview said nothing about which vendor, if any, the question actually resolved to. New
previewVendors()tests the question's words againstsuggestionPool, the same live component-name list the search autocomplete already matches against, and shows the real recognized name(s) (e.g. "vendor: zoom, teams") whenever at least one is found; falls back to the old "vendor required" only when the box is checked but nothing in the question is recognized.
Clear/submit share the input's row instead of their own
- fix With #askOptionsPanel now relocating away from the topbar on a wide screen (last release), .ask-options-row was left holding only Clear, the bookmark button, and the submit arrow: a near-empty second row under the question input. Those three are core form controls, not agentic-AI configuration, so they moved up onto .ask-input-row itself, on every screen size: one row (search, Clear, bookmark, submit) instead of two. .ask-options-row now holds only #askOptionsPanel, so it collapses to nothing once that panel relocates, rather than sitting there empty.
Agentic-AI controls move into the answer rail on wide screens
- ux The model/size/pipeline selects, the three evidence-gating toggles, and the usage line used to always live in the topbar's second row, pinned in the fixed header regardless of screen width. Per request, they're grouped into
#askOptionsPaneland relocated (the real node, not a copy) to sit at the top of the answer rail's column on a screen with room for it (≥900px), right beside the diagram/answer they configure; a narrow screen, with no rail at all, keeps them in the topbar exactly as before.relocateAskOptionsPanel()runs once at load and again every time the viewport crosses that width. Clear, the bookmark button, and the actual submit arrow stay in the topbar on every screen size, since those are core form controls, not agentic-AI configuration. - fix
.ask-rail-colnow wraps the options panel's landing spot plus both the intro panel and the answer rail, and is itself the sticky/scrollable flex column; the two panels are plain toggled children of it instead of each separately carrying their own flex/sticky/overflow rules, so the relocated options panel scrolls and sticks together with whichever of the two is showing.
Query preview moved into the Ask answer; one empty-state surface
- ux The "search: ... window: ... intent: ... vendor required" readout is no longer a page-wide fixed strip below the header (right-aligned as of the last release, per an earlier request). Per follow-up request it now renders inline, small and muted, right above the workflow diagram in the Ask answer rail's Answer tab, a snapshot of what the submitted question actually resolved to rather than a live typing hint. The old fixed-overlay plumbing (
--preview-h, its ResizeObserver, the layout padding/rail-offset calc()s that reserved space for it) is gone with it, since the reading now lives inside normal document flow. - fix A genuine fetch failure (a real "β οΈ The server is temporarily unavailable (502)" case) still showed three uncoordinated messages at once: an ad-hoc error paragraph written straight into
#feed, the unrelated pagination sentinel independently reading "π No results," and#statussaying "Failed to load." Same redundant-elements bug fixed for the plain-empty-search case last release, just via a different codepath that fix didn't reach.showEmptyState(message, {icon, detail, isError})/hideEmptyState()is now the one surface every "nothing in the feed" case (over-filtered search, day-window exclusion, or a real fetch error) goes through, so#emptyState.show ~ #sentinelsuppresses the sentinel regardless of which reason triggered it.
Query preview strip right-aligned
- ux The "search: ... window: ... intent: ... vendor required" preview strip below the header now right-aligns its text, per request, instead of sitting flush left. On a wide screen this puts it roughly above the Ask answer rail (the right-side column), the same side of the screen as the question/tabs it's describing.
Feed lookback window now tracks the Ask recency setting
- feat
LOOKBACK_DAYS(the feed's own recency window, driving "Recent Updates," the activity chart, and Reddit/StackOverflow matching) used to be a plain hardcoded constant, separate from the admin Settings panel's "Ask recency window (days)," which only ever coincidentally shared a starting value. Per explicit request they're now the same number: the client fetches the live value from a new publicGET /api/ask/recent-window-daysat page load and applies it before the feed's first render (28 stays as the fallback if that fetch fails). Changing the Settings value and reloading now widens or narrows the feed too. - fix
boot()and the independent top-levelloadHomeStats()IIFE both build something sized offLOOKBACK_DAYSand both run concurrently at page load; each now awaits the same singlelookbackDaysReadypromise before doing so, so there's no race where one of them builds its day range from the stale fallback while the other already has the live value.
Friendlier message when the API is unreachable
- ux A failed feed load showed the raw thrown error verbatim, e.g. "β οΈ Error: 502 Bad Gateway": accurate, but not something most visitors can act on.
friendlyFetchError()now classifies it (a 5xx means the server itself is down, a 4xx means the request was rejected, anything else is a real network/connectivity failure) and shows a plain-language headline plus a short, still-realistic detail line, reused by both the main feed's error state and the filter-submit failure's status text.
Removed a redundant "no results" message
- fix An empty feed showed two "no results" messages in a row: the prominent emptyState block ("No results found for the last 28 days") immediately followed by the small infinite-scroll sentinel's own "π No results" text right below it.
#emptyState.show ~ #sentinel { display: none; }hides the sentinel whenever the empty state is already showing, covering every codepath that sets that text rather than patching one call site.
Lookback window widened to 4 weeks; fixed a stale label
- fix
LOOKBACK_DAYSback up to 28 (was 14). The sidebar's "Activity (2 weeks)" label was hardcoded text, not derived from the constant like the feed header's own "(last N weeks, M components)" is, so it silently went stale the last time this changed; now set once from a newLOOKBACK_WEEKSderived constant, same source of truth as everywhere else. - fix The admin Settings panel's "Ask recency window (days)" hint said it "matches the feed's own lookback window by default (14 days)," worded as if the two were linked; they only ever coincidentally shared a starting value; changing one has never changed the other. Reworded to say so plainly, and the day count it does mention is now interpolated from
LOOKBACK_DAYSinstead of a hardcoded number that can drift again.
Profile row on one line; empty state explains the day window
- ux Name, email, and the role badge in the Account profile card were three stacked lines; now one row (wraps only if the panel is too narrow to fit them), with Sign out staying right-aligned on the same line. Smaller font on all three now that they share a row.
- ux The feed's empty state now says "No results found for the last
LOOKBACK_DAYSdays" whenever a named search actually has matches, just none recent enough to pass the feed's day-window cap (e.g. searching "Python" when its newest known release predates the window entirely). Previously a flat "No updates match the current filters," which didn't say why. An over-filtered or genuinely no-match result still gets the old generic message.
More stats on the Account profile card; tighter admin panel
- feat The profile card's stat row now also shows Reddit and StackOverflow document counts (new
stackoverflowTotalfield onGET /api/admin/overview;redditTotalno longer double-counts stackoverflow.py's posts, which share the same collection). "Bots stale" now reads as a fraction of the total tracked bots (e.g. "0/9") instead of a bare count with no denominator. - ux Smaller font and tighter gaps on the stat row now that it holds more chips. Trimmed remaining padding/margin in the profile card and each admin section's closed row, and gave
#usersView's own box a few more px of height (bottom slack 16px → 8px), so the "all admin sections closed" state fits without scrolling on more screens.
"Latest version" for a component picked the wrong branch
- fix A product with several concurrently-maintained branches (e.g. Python's 3.12/3.13/3.14) posts patches to each on its own schedule, so the most recently-dated release isn't necessarily the highest version number: an older branch's patch can land after a newer branch's.
fetchLatestVersionFor(the feed group header's "(latest: X, Nd ago)" bracket and the Ask suggestion dropdown's own bracket) was taking the first non-CVE entry in/api/c/name/:name's date-sorted list, so it showed Python's latest as "3.12.14" (dated after 3.14.7) instead of the real latest, 3.14.7. Now picks the max by actual version number instead. The server-side counterpart (/api/v/d/versionsByComponent, used by the Account page's Installed Versions drift check) had the identical bug and is fixed the same way.
Account view uses the available width instead of wrapping
- ux The Account view's own column was capped at a fixed 580px even though it's had the whole main area to itself since Filters/nav became their own drawers, forcing the profile card's stat row (and other content) to wrap onto extra lines it didn't need to. Widened to
min(900px, 96vw). Form fields (password, org names, provider keys) are capped to a sensible width instead of stretching edge to edge; the search-events table, dashboard cards, and stat rows use the extra room. - fix Reduced remaining padding/margin in the profile card and its stat row.
Even summary spacing; richer stats in the profile card
- fix A stray leftover CSS rule (
#ua-search-events-section { margin-top: 24px; }) gave "Search & Ask activity" a visibly larger gap above it than every other admin section. Removed; every collapsible row's spacing now comes from the same source (its own border), so it's consistent everywhere. - feat The admin registration notice and stat line moved into the profile card itself (name/email/role/Sign out), visible the moment the Account view opens instead of a separate line further down the page. Expanded with more aggregate counts: versions tracked, CVE total, stale bots, and storage used, alongside accounts and queries.
Fix: every collapsible summary row, not just the admin panel's
- fix The "chevron stacked above centered text" layout bug fixed for the admin panel earlier applied to every other collapsible
<summary>in the app too (Filters/Stats and other sidebar sections, docs view's endpoint/architecture toggles, CVE view's post/legend toggles, "Why create an account?", "Paste a list"): each was missing an explicitflex-direction: row, so the global summary style's owncolumndefault won on that one property. All fixed the same way.
Filters/Stats get their own panel; badge and source-list fixes
- feat Filters and Stats are now their own slide-over panel, opened with a new ποΈ topbar button, separate from the β° menu (which now holds just the view-switcher nav). Toggle either one independently; opening one closes the other.
- fix The Account page's role badge ("ADMIN"/"USER") was stretching to the full width of its card instead of staying a compact pill, since its flex-column parent's default cross-axis stretch was overriding its own inline-block sizing.
- fix A feed group's "Sources" line could show a stray "videoCall" alongside the real vendor (e.g. "mitre, teams, videoCall") from documents saved before videoCall.py started stamping the actual vendor per URL; the legacy generic label is no longer shown.
Recent Updates now strictly capped at the lookback window
- fix A named component search, or the LLM/Hypervisor toggles, used to bypass the feed's recency window entirely and surface a release from a year ago. Per request, the feed now hard-caps at the lookback window (14 days) in every case, no exceptions: a search or toggle with nothing that recent shows no results instead of reaching further back.
Sidebar consolidated to 2 sections; tighter admin/profile padding
- ux The feed sidebar's Types, Stats, Activity, and Top searches sections (previously 4 separate collapsible rows) are now sub-divisions of one combined "Stats" section, next to Filters. 5 rows to scan closed, down to 2.
- fix Reduced the padding/margin around every admin and Account-page collapsible section (System overview, Settings, All users, Search & Ask activity, Change password, Model provider keys, Organization namespaces, Bookmarks, Installed versions): removed redundant per-section margins (the border between rows already provides separation) and switched the summary row's own padding to a smaller, relative (rem-based) size. With everything closed, the whole admin panel now fits without scrolling on a typical laptop screen.
Fix: feed group's "latest" freshness could read a day off
- fix A feed group's "(latest: X, Yd ago)" freshness could say "1d ago" for a version genuinely posted earlier the same day. The date was anchored to a fixed noon-UTC instant and diffed against the current moment, so the result depended on how far the viewer's own timezone sits from UTC, not on whether a calendar day had actually passed for them (confirmed live: a release posted 5am Pacific already read "1d ago" by evening the same Pacific day). Now computed as a plain whole-calendar-day difference in the viewer's own local timezone.
View-visibility menu toggles; consistent collapsible sections; narrower admin table
- feat New admin Settings toggles for each optional nav-menu view (Graph/Arch/CVE/Risk Report/Docs/Changelog/Credits/Release): turn one off and its menu link disappears for everyone. Home and Account can't be hidden, to keep core navigation and admin access always reachable.
- ux Change password, Model provider keys, Organization namespaces, Bookmarks, and Installed versions are now the same closed-by-default collapsible design as System overview/Settings/All users/Search & Ask activity, instead of a different always-open card style, so the Account page is shorter overall and reachable without scrolling past several open sections first.
- fix Search & Ask activity table: removed the User agent column, timestamps now show as "3d ago" instead of a full date/time, and the table switched to a fixed percentage-column layout so it fits its container at any width instead of occasionally needing its own horizontal scroll.
- fix Compare mode's pipeline legend (Benchmark tab) no longer needs horizontal scroll either: replaced the old 6-column min-width table with a stacked list that reflows to any width.
Compare mode: no more horizontal scroll on the pipeline legend
- fix The Benchmark tab's "What do these pipelines do?" legend was a 6-column table (min-width 760px) that only fit with its own horizontal scrollbar, wider than the answer rail, the narrow-screen modal, and most phones. Replaced with a stacked list: each pipeline's name, a wrapping row of yes/no fact chips, and its example, all reflowing to fit any width instead of needing to scroll sideways.
- ux Admin Search & Ask activity table tightened further on mobile (smaller cell width/font) so its own self-contained scroll box is needed as rarely as possible.
Admin-configurable Ask defaults
- feat Three new admin Settings entries: default Ask pipeline, default model provider, and default model size β what a new visitor's Ask form starts on, instead of the previous fixed Auto/Ollama Cloud/Medium defaults. Rendered as real dropdowns (not free text), so an invalid value can't be typed in.
Admin section headers: fix wrapped summary layout
- fix Each admin section's closed-state
<summary>row (chevron, title, count, Refresh) was rendering as four centered, stacked lines instead of one compact row β a globalsummaryCSS rule'sflex-direction: columnwasn't being overridden. Now a single line, tighter padding. - ux Settings section's summary now shows a count, matching All users / Search & Ask activity.
Benchmark tab, admin registration/search visibility, installed-versions sync
- feat New Benchmark tab on every Ask answer, alongside Answer and Sources. On a normal answer it offers a one-click "Compare all 5 now"; running Compare all 5 itself now renders here too (same tabbed card the rail already used, previously modal-only), with a compact side-by-side table (pipeline, time, source count, full answer at small font) so every pipeline's answer can actually be read and compared, not just skimmed as 5 separate full cards.
- feat Admin panel: a registration notice banner ("N new registrations since your last login") plus an always-visible accounts/queries stat line (total + last-7-days for both), backed by
GET /api/admin/overview's newusers/queriesfields. - feat The admin "Search & Ask activity" table (renamed from "Component searches") now logs and shows real Ask questions too, not just vendor/component searches, tagged by type; a signed-out visitor's question is logged even though it can't be answered without signing in.
- feat Installed versions (Account view) now actually persists to your account server-side instead of only this browser's localStorage, so it follows you across devices.
- ux Each admin section (System overview, Settings, All users, Search & Ask activity) is now a closed-by-default, collapsible section instead of one long always-open page.
- ux Search & Ask activity table: removed the raw IP column, shows the user's real name instead of a truncated id.
- fix Removed the inline research-type citation footnotes from the Ask pipelines tables (intro panel and docs view), per request.
Agent-workflow diagram: full width, no edge overlap
- fix The live agentic-workflow diagram now stretches to fill its full column width; Mermaid stamps its own
max-widthinline style on the rendered SVG, which was overriding the externalwidth:100%rule. - fix Increased node/rank spacing so the dotted "retry" feedback edge between Evaluator and Retriever no longer overlaps the main flow line.
- fix Comparison-question entity extraction: a trailing connector word ("...and which browser?") could leave it attached to the previous entity (e.g. "teams and"); the trailer pattern now also strips "and"/"but".
Admin settings panel; research-type column with citations
- feat New Settings section in the Account view's admin area, backed by the server's new generic
/api/admin/settings(GET/PUT). Renders whatever keys the server actually returns, not a hardcoded form, so a new admin-tunable value needs no new markup here. First real setting: Ask's recency window (days), now admin-editable and defaulting to 14 to match the feed. - ux Both "Ask pipelines" tables (the Ask intro panel and the docs view) gained a "Research type" first column: the general question-type literature these categories come from (Li & Roth 2002's factoid-QA taxonomy; Treude, Barzilay & Storey 2011's Stack Overflow question-type study), cited below each table.
Feed scrolls with the page on mobile, not boxed into 70vh
- fix On a narrow screen,
#feedPanel(list and its own header, including the sort dropdown and Expand all) was capped tomax-height: 70vhwith its own nested scroll, on top of the page's own scroll. Scrolling through updates scrolled the sort/Expand-all controls out of reach too, and there was nothing else on the single-column mobile layout the cap was actually making room for. Removed; the feed now flows with the page like the rest of this layout already does on mobile. Confirmed infinite-scroll pagination doesn't depend on the feed being its own scrolling element (itsIntersectionObserverhas norootset, so it already watches the real viewport).
Auto pipeline selection, by question intent
- feat New "Auto (recommended)" Pipeline option, now the default: the question's own classified intent picks a concrete pipeline server-side (comparison β delegated + feedback loop, security/patch β union search + rerank, a plain version lookup β single-agent, everything else β delegated) instead of a manual guess, and the answer states plainly why ("Why this process: ...") once it's done.
- ux Replaced the Ask intro panel's "Try asking" list with a table: question type, the real internal intent tag, which process Auto picks for it, and a clickable example (same fill-the-input behavior as before).
- feat New "Ask pipelines" section in the docs view with the same mapping, for anyone reading the API docs directly rather than the Ask box's own intro panel.
- fix A live run's phase captions (and the answer card's own pipeline label) previously showed the literal word "auto" instead of the real resolved pipeline, since the client only learns which concrete preset Auto picked once the server says so. A new synthetic
auto_resolvedprogress event (and preferringdata.config.presetfor the final label) fixes both.
"Do you recommend X or Y" fixed; taller, smaller-font workflow diagram
- fix "Do you recommend zoom or teams?" leaked "recommend zoom" into the feed's own vendor filter (
?q=recommend+zoom,teams), silently dropping Zoom out of the feed since no real product name contains "recommend zoom" as a substring. The comparison entity-name regex only stripped a leading verb phrase at the very start of the question ("Should I use...", "Recommend..."); it didn't know about a leading "Do/Would/Will you..." wrapped around it. Fixed in both the client's own preview and the server's real entity extraction (kept in sync by hand, see each one's own comment). - ux Workflow diagram: smaller font and more node/rank spacing, scoped to just this diagram (not the docs view's own Mermaid diagrams), now that each box carries a two-line label (name + seconds).
Workflow diagram redraws live, each box shows its own seconds
- fix A fast-completing role (a comparison question's Retriever calls are plain DB lookups, often well under 100ms) could finish before its own "active" render ever painted, since the next phase's render raced past it: the diagram would sit at its very first idle frame for the whole request and only ever show the final state. Now redrawn every 250ms while a request is running, not just on each phase event, so even a very short-lived active state gets at least one real frame on screen.
- feat Each box now shows its own elapsed seconds under its name (e.g. "Retriever, 0.4s"), live-updating while that role is active and frozen once it's done, instead of one combined caption line below the whole diagram.
Sort by most sources
- feat New "Sort: Most sources" option in the feed's sort dropdown, ranking each component by how many distinct bots actually produced its content (the same count its own "Source(s): ..." line shows), most first. "unknown" doesn't count as a real source, so a component with only unattributed documents doesn't out-rank one with a confirmed single source.
Live agent workflow diagram in the answer rail
- feat The answer rail now opens the moment a real question is submitted, showing a live Mermaid diagram of the four-role architecture (Rewriter β Retriever β Evaluator β Orchestrator, with the feedback loop back to Retriever) as it actually runs: idle by default, blue while a role is active, green once it's done. Always the same full shape regardless of pipeline preset. A preset with no real role delegation (Single-agent, Multi-agent buggy/fixed) just never lights up Rewriter/Evaluator, since those roles genuinely don't exist for it.
- feat The rail is now two tabs: Answer (the workflow diagram plus the answer itself) and Sources (citations, vendor/intent/temporal chips, and "Show internals"), instead of one long stacked card.
- fix Removed the text-based phase ticker that used to sit above the question input while a request ran; the workflow diagram in the rail replaces it, and it no longer needs its own reserved strip at the top of the page.
CVE chip kept its box after the rest lost theirs
- fix The group header's π΄ CVE chip still rendered as a red boxed pill after Major/Minor/Patch/Reddit/SO lost theirs:
.chip.bad's own background rule sat later in the stylesheet than.groupChips .chip's box-removal at equal CSS specificity, so it silently won regardless of which was actually meant to apply. Added matching.groupChips .chip.bad(and every other chip variant) at higher specificity so the box-removal always wins here; CVE keeps its red text, just no more background.
Components, not groups; softer accents; a Major/Minor/Patch fix
- fix A CVE record carries its own release channel too (a CVE affecting 6.31.1 reads channel "patch"), which was double-counting it into both the π΄ CVE chip and the Major/Minor/Patch chips. Those three now only count real, non-CVE release-notes entries.
- ux Renamed "Groups" to "Components" throughout the feed panel (sidebar KPI, "Expand all" button title, the header's own count): "group" was this app's internal grouping mechanism, "component" is what a reader actually thinks of each entry as.
- ux Removed the "N groups" text that repeated on the right side of the header, now that the header's own "(last 2 weeks, N components)" label already states it.
- ux Dropped the ".py" from each component's "Source: chrome, github" line. The real sourceBot value keeps it (for consistency with releasetrain-bot's own naming); only the display drops it.
- ux The "posted today" row indicator (and the LLM/Hypervisor ones) used the page's darkest near-black ink color, which read as too heavy a bar. Switched to the softer neutral tokens already defined for exactly this purpose, and every row's left-border accent is now rounded instead of a hard rectangular edge.
Per-component sourcing, header controls line up
- feat Replaced the global, deck-wide "Recent Updates" source breakdown (raw totals with no way to tell which component each count belonged to, and permanently-stuck "unknown" buckets that should have said "github.py") with a per-component "Source: chrome.py" / "Sources: chrome.py, github.py" line in each group's own summary.
- feat "Recent Updates (last 2 weeks)" now also states how many groups are currently in that window, e.g. "(last 2 weeks, 214 groups)".
- ux The Sort dropdown and "Expand all" button now share an explicit height, matched to whichever was naturally shorter (the button): the native select's own UA chrome previously rendered visibly taller.
Feed group chips: less box, more aligned
- ux The group header's own CVE/Reddit/SO/Major/Minor/Patch chips lost their box (background and border) and became plain colored icon+label+count text, separated by a "|": six pill boxes together read as too heavy for a per-group summary, especially next to a lone one-count chip like "Patch 1".
- ux That chip row now sits flush-left with the expand/collapse arrow on the row above, instead of indented to (approximately) line up under the name text.
Feed group header: chips on their own row, badge-styled
- ux Each component's CVE/Reddit/SO/Major/Minor/Patch total chips now sit on their own row below the component name, instead of crowding onto the same line; the latest-version bracket moved to the far right of the name's own row.
- ux Chips (feed group totals and per-row chips alike) are rounder and bolder, closer to a GitHub/shields.io badge, while keeping this site's existing muted color palette rather than picking up their louder solid-fill colors.
Stack Overflow citations now labeled as such
- fix The Ask answer's source list hardcoded every community citation as Reddit ("kind: 'reddit'"), even when the underlying document actually came from Stack Overflow (stackoverflow.py writes into the same shared collection, distinguished only by a "source" field the server ignored). Added a π§ icon and a "Stack Overflow: <name>" snippet prefix so a genuine Stack Overflow citation now reads as one, matching the icon the feed already uses for it.
A how-to example, without growing the list
- feat Swapped the plain "What's new in Kubernetes this month?" sample for "How do I roll back a bad Windows update? (General, how-to)": procedural/how-to is a real, well-established question type (this session's own research discussion), and stackoverflow.py now flags it on ingest, but classifyIntent doesn't route it specially yet, so it's labeled honestly as General rather than implying a dedicated intent that doesn't exist. Kept the list at 7 items on purpose, since it was already trimmed once to stop the panel needing a scroll.
Feed sort is now a choice, not one fixed default
- feat Added a Sort dropdown next to "Recent Updates": Recent (the default), A-Z, Most CVEs, Highest risk, and Most activity. Remembered across visits. "Highest risk" ranks by the same model-predicted community update-risk score used throughout the rest of the app, and re-sorts itself once Reddit data finishes its background load if that's the active mode.
Feed sorts by recency, window back to 2 weeks
- feat Feed groups now sort by recency (whichever component was most recently updated leads) instead of alphabetically. This is a "Recent Updates" feed, so surfacing what actually just changed matters more than a stable, predictable position, and finding one specific component by name is already better served by the search/filter box than by scanning an alphabetized list.
- feat Lookback window back down to 2 weeks (was 4). "Recent Updates (last 2 weeks)", the activity chart, and Reddit/StackOverflow matching all follow the same single
LOOKBACK_DAYSconstant.
Fixed a stale "latest" version in the feed group header
- fix A group header could show an older version as "latest" (e.g. "Zoom (latest: 7.0.0, 171d ago)" while a genuinely newer 7.1.8 sat in the feed below it). The server endpoint this reads was sorted by when a document was last written to the database, not by its actual release date; a bot that posts several historical entries newest-first (the natural order for most release-note pages) ends up writing its oldest entry last, which then looked like the "latest" one. The endpoint now sorts by real release date directly.
Poll button only offered for a real yes/no question
- fix The π Poll chip appeared on any Reddit post with a "?" and comments, including a WH-question like "What's the best way to fix this?" or "Why did this happen?", which has no binary answer to poll for in the first place. Now only offered when the question is actually shaped for yes/no. Same fix applied to the server's own search_reddit_questions tool, so Ask's "did other people..." questions don't match a WH-shaped post either.
Ask intro panel no longer needs to scroll
- fix Growing "Try asking" from 4 to 7 examples pushed the panel's content past the viewport, forcing a vertical scroll that wasn't there before. Tightened spacing throughout (headings, paragraphs, sample buttons) and trimmed the two explanatory paragraphs down to the same facts in fewer words, so the same information fits in noticeably less height.
Ask answer rail no longer scrolls sideways
- fix The right-side answer panel was missed in the earlier "no view scrolls sideways" pass: it sets overflow-y:auto, which silently promotes overflow-x to auto too, so an unwrapped token in a generated answer could put a horizontal scrollbar on the rail and clip text at the edge. Pinned to overflow-x:hidden, and added overflow-wrap to the answer text and its inline code spans so real content wraps instead of needing to scroll in the first place.
Fixed a blank intent tag, and a tighter preview strip
- fix The "Will..." preview line showed a bare "intent:" with nothing after it for a comparison question: the badge above the input learned the new intent, but this line's own separate tag map didn't. Added.
- fix That preview strip pushes the whole page down since it has no reserved layout space of its own, and a comparison question's longer term list made it wrap to 2 to 3 lines. Shortened the wording to plain labels ("search:", "window:", "intent:", "vendor required" instead of full sentence phrasing) and tightened the strip's own padding and line-height. Same information, less height.
- feat Added a 7th "Try asking" example showcasing the community Yes/No poll feature: "Did other people lose Wi-Fi after the latest Windows update?"
"Try asking" now has one example per intent
- feat The Ask intro panel's sample questions now cover every intent the classifier recognizes, each labeled with which one it is: Version, CVE, Patch, General, Comparison, and Opinion, the last one deliberately phrased to preview that it declines rather than reading like the rest.
Comparison entity extraction fix, and a freshness stamp on the feed
- fix "android or ios which is more secure" resolved to the entities "android" and "ios which": a trailing qualifying clause ("which is...", "that...") wasn't being cut off the second name, so it matched nothing and the feed showed only one side's documents. Fixed in both the server's classifier and this page's own preview copy of it.
- feat Each feed group's header now shows how fresh its latest tracked version actually is, e.g. "(latest: 8.5.10, 12d ago)", not just the bare number.
- feat Swapped one of the Ask intro panel's sample questions for a comparison example: "Should I use Node or Flask for a new API?"
Live preview badge learned the comparison intent
- fix The as-you-type badge above the question box still showed "Opinion (will decline)" for a real comparison question ("should i use zoom or teams for the next video call"), even after the server started answering it for real. This preview is a client-side mirror of the server's own classifier and had fallen out of sync; it now recognizes the same comparison shape and shows "Comparison question" instead.
Views no longer scroll sideways
- fix The Account view and every other panel could scroll horizontally when a wide child (an admin table, a long token) pushed past the edge. Each view now clips to its own width. The admin search events table, which really is wide, scrolls inside its own box so every column stays reachable.
Provider key fields start empty and stay empty
- fix The Claude key box still showed dots from the browser password manager. All three key inputs now load read only until you click into them, so no password manager can prefill them. The app never puts a key here itself, shared or otherwise, so every box reads the same: empty, with a placeholder.
Provider key fields no longer autofill
- fix Browsers were autofilling the Model provider key inputs with the saved account password. They now opt out of password-manager autofill, so a stray Save can't overwrite a key with your login password.
Use your own model provider keys
- feat Account view has a Model provider keys section: set your own Claude, Groq, or Ollama Cloud key and your Ask requests use it in place of the shared server key. Stored on your account, only ever shown back as the last 4 characters, cleared by saving an empty box. Fixes the case where one person exhausting the shared credit blocked Ask for everyone.
Long source titles wrap instead of scrolling sideways
- fix A long Reddit/discussion title in an answer's Sources list forced a horizontal scrollbar on the answer card. Titles now wrap inside their chip.
The direct answer is highlighted in the response
- feat The exact substring that most directly answers a version question (e.g. "8.5.10") is now highlighted in green in the answer text, wherever it appears. Comes from the server's own
highlightTerm, the same deterministically-verified version number ask.js already checks the answer against, so this never guesses at what looks important, only ever marks a value already confirmed correct.
Sources flow left to right instead of one per line
- fix v3.60.0's column-aligned, one-per-line source list is replaced with a wrapping row of compact chips: sources flow left to right and only drop to a new line once a row runs out of width, instead of every source taking its own line regardless of how short it is.
Source list columns line up; sign-in link in the Ask panel
- ux Each Documented/Discussion source row's icon, title, and date now sit in fixed grid columns, so every row's date lines up at the same position instead of trailing right after that row's own differently-long title.
- feat The Ask intro panel's "requires sign-in" text is now a real link straight to the Account view, instead of only naming it in prose.
Feed groups collapsed by default; version bracket fetched live
- fix Every feed group now starts collapsed, including the first one. It used to default open, which read as one arbitrarily-expanded group sitting above an otherwise all-collapsed list.
- fix A group's "(latest: X)" bracket (added in v3.58.0) is now fetched live by name, the same call and cache the Ask suggestion dropdown already uses, instead of being computed only from whatever items the feed happens to have loaded right now. Verified live: a group showing "Patch 1"/"Minor 2" chips could still have zero non-CVE items loaded in view (those chips count a CVE record's own versionReleaseChannel field too), leaving the bracket blank even though the real latest release exists, just older than the feed's current window.
Feed group headers show their latest version
- feat Each collapsed feed group's header now shows "(latest: X)" next to the component name, computed from the group's own already-loaded items, not a separate fetch. Only counts a real release (excludes CVE records and Reddit/StackOverflow posts), so a component whose most-recently-touched document happens to be a CVE still shows its actual latest version, not the CVE's own affected-version number.
Component suggestions show their latest version
- feat Typing a component name into Ask now shows its own latest version next to it in the suggestion list (e.g. "Android (latest: 17.0.0)"), fetched lazily per suggestion and cached so it never re-fetches the same name twice. Skips any CVE record when picking "the latest version", since a component's own most-recently-touched document can be a CVE rather than a real release.
The right column is always there now, not just on demand
- feat On a screen with room for it, the right column now shows an Ask intro panel (what it does, technically, plus clickable sample questions) whenever no answer is currently showing, instead of sitting empty until the first question. Swaps to the real answer the moment one exists.
- ux The two-column layout is no longer conditional on an answer existing; it's always on at the same width it used to only switch to for an answer. The overall page's left/right padding was also trimmed slightly.
Even 50/50 split between feed and answer
- fix The feed and the inline answer rail now split the available width evenly (50/50). Previously the rail stayed a fixed 360px regardless of screen size, so the feed took up most of the width on anything wider than a laptop.
Ticker back to one line, numbers kept
- fix v3.54.0's one-step-per-row ticker layout is reverted back to the original wrapped horizontal line. The #1/#2 round numbering it shipped alongside stays.
Every round of a multi-agent pipeline is now numbered
- feat On Multi-agent (buggy) and Multi-agent (fixed), a repeated Retriever/Orchestrator round now shows a number (e.g. "Retriever #2: Searching the web", "Orchestrator #2: Generating answer") instead of the same two labels appearing over and over with no way to tell one round apart from another. Matches the #1/#2 tagging the delegated presets already got.
- ux The pipeline ticker now shows one step per row instead of a single wrapped line with arrows crammed between entries. A question with several rounds reads as an actual sequence now, not a run-on blur.
Compare all 5, agent identifiers, a legend table
- feat Compare now runs all 5 pipelines side by side (was 3): Single-agent, Multi-agent buggy/fixed, and the two new delegated presets. A technical legend table now sits above the 5 answer cards, listing what each pipeline does and doesn't do (rewrites the query, searches the union of original + rewrite, real agent delegation, feedback loop retry) with a short concrete example per row.
- ux On Multi-agent (delegated) and Multi-agent (feedback loop), when the feedback loop actually triggers a second Retriever/Evaluator round, the progress ticker now tags each entry
#1/#2(e.g. "Retriever #2: Searching the web") so two agent calls no longer look like the same step repeating.
Two new pipelines: genuine agent delegation
- feat Two new Pipeline options: Multi-agent (delegated) and Multi-agent (feedback loop). Unlike every other pipeline here, which is one continuous model call with capability flags toggled on or off, these two genuinely delegate: the Rewriter, Retriever, and Evaluator are each a separate model call, with results explicitly handed between them. The feedback loop variant additionally lets the Evaluator send the Retriever back for one more search pass when its first attempt is judged insufficient. Real cost: several model calls per question instead of one, so pick these deliberately, not as a default.
- ux The progress ticker's Rewriter:/Retriever:/Evaluator: labels are now genuinely accurate for these two pipelines (each really is a separate call), plus two new phases, "choosing search terms" and "judging evidence", that only ever appear on them.
Readable checked/unchecked tooltips
- ux The Vendor check / Temporal filter / Intent filter tooltips now put the checked and unchecked case each on their own line, with a blank line between, instead of one run-on sentence.
Hover tooltips on filters and Ask options
- ux Vendor check, Temporal filter, and Intent filter now explain what checked versus unchecked actually does on hover, instead of just naming themselves. The Model, Size, and Pipeline selects, and the Major/Minor/Patch/CVE/Reddit quick filters, got the same treatment where they were missing one.
Component autosuggest is back; a few more fixes
- feat The single search/ask box now suggests real component names as you type again (the old Search box's own autocomplete), alongside real past community questions in the same dropdown. Picking a component fills just the current comma-separated term; picking a question fills the whole box.
- ux An abstained answer now says why: "No vendor matched", "No evidence found", or "Opinion question" instead of a plain, unexplained "Abstained" badge.
- ux Recent Updates groups are now sorted alphabetically by component name instead of by whichever one happens to have the most recent item, so a component is easy to find by scanning. Each group's own entries still sort newest first.
Fixed: Reddit poll always failing
- fix The π Poll button never sent which model provider to use, so the server always defaulted to Anthropic regardless of what is actually selected and working in the Ask box. If Anthropic's account is out of credit or otherwise unavailable, that made every single poll fail, while Ask itself looked fine since it lets you pick a different provider. Poll now sends whichever provider is currently selected there, and caches its result per provider so switching providers and polling again does not show a stale answer from a different one.
Less clutter in the feed and the answer rail
- ux The answer rail's sources are now split into two labeled groups, Documented (release notes, CVE) and Discussion (Reddit, the web), instead of one flat list mixing both kinds together.
- ux Dropped the per-row "reddit"/"stackoverflow"/"CVE"/"patch" text chips from the feed. Each row's own icon and colored left border already say what kind it is, and the group header already totals each kind, so repeating it on every single row was pure noise. The one channel with no icon of its own (major) keeps a colored left border in its place.
- ux More breathing room throughout: taller feed rows, bigger chips with more padding, and a roomier answer card.
Keep the progress ticker after the answer arrives
- fix The pipeline ticker used to clear the moment an answer arrived. It now stays on screen, with each step's final time frozen, until the next question is asked, so the full timing breakdown is there to review.
The progress ticker is now real, not approximated
- feat A real question's answer now streams as it happens. The "which phase is this" ticker above the input follows actual server sent events instead of guessed timing: Resolving vendor, Searching (with the real tool name, e.g. "release notes" or "CVE records"), Widening search window on the one automatic retry, and Generating answer. Each entry's elapsed time is genuine and live, freezing the moment the next real event arrives.
- feat On a multi-agent pipeline (Multi-agent buggy or fixed), each step is also labeled with the paper's own role name (Rewriter, Retriever, Evaluator, Orchestrator), matching this platform's own architecture story. Single-agent shows the same phases without the role names, since that baseline has none.
- fix The model can no longer answer with a bare bracketed citation like "[source]" or "γsourceγ" that points at nothing. The system prompt now asks for a real named source or no citation at all.
Visible progress while a question runs
- feat A real question now shows a "which phase is this" ticker above the input (Resolving vendor → Searching sources → Generating answer), each step's own elapsed time counting up live and freezing once that step ends. There's no live signal from the server for this yet, so step *boundaries* are an approximation. Each step's own timer is real, though, and the last step (Generating answer) just runs until the actual response arrives rather than guessing at it.
- ux The submit button's hourglass now visibly spins while waiting, instead of sitting static.
- feat The π΄ CVE chip in the Recent Updates breakdown is now one chip per source bot (sourceBot-keyed, same convention as every other π¦ bot chip), not one opaque combined total. CVE isn't one bot's output, it's an
isCveflag several different product bots each set on their own documents.
The feed follows the question
- feat Asking a real question that resolves a vendor or category (Vendor check on) now also filters the feed to it, so the answer and its full browsable history sit side by side. A question that doesn't resolve one goes back to showing everything, instead of leaving an unrelated filter in place.
- ux Simplified the "Why create an account?" list in the sign-in view. Each reason is now one short, user-facing line instead of a longer technical description.
Answers show inline, beside the feed
- feat On a screen with room for it (laptop width and up), asking a real question no longer opens a popup. The answer renders in a sticky right-hand rail next to the feed instead, trimmed to a compact length with a "Show full answer" button and its sources shown as inline links. Narrower screens and "Compare all 3" still use the popup, since three side-by-side cards need the width.
- feat Default Ask options changed: Model defaults to Ollama Cloud (free tier), Pipeline defaults to Single-agent, and Vendor check / Temporal filter / Intent filter are now checked by default.
Search and Ask are one box now
- feat The Search/Ask mode toggle is gone. There's one box. Type a plain vendor or category name ("chrome", "any sql updates recently") and it lists matching versions/CVEs, same as Search always did, still free and signed-out. Type a real question and it runs the full Ask pipeline as before (sign-in required, a real model call).
/api/askitself tells them apart before ever touching the model, using the same vendor/category resolution the Rewriter already does. A plain lookup never costs a call or needs sign-in, and a real question is unaffected. - fix Signing in is now only asked for when it's actually needed (a real question, or Compare all 3). Previously, the Ask form required sign-in up front for every submission, including what would have been a free lookup.
Ask suggests real past community questions as you type
- feat Typing 3+ characters into Ask now shows a dropdown of real, similar past community questions (each ≤15 words, ranked by relevance to what's typed), not a static "recent questions" list, and not client-side filtering over the public API (which has no free-text search and returns 3,240+ heavy documents by default). Picking one fills the input; the subreddit it came from shows alongside each suggestion. Public, no sign-in needed: it only reads existing Reddit data, no model call.
Rate-limited providers show as unavailable, not clickable
- ux When a provider is currently rate-limited, its Model option now shows "(rate limited)" and can't be selected, instead of letting you pick it and then hitting an error. Checked on page load, on every Model change, and after every ask attempt.
Source breakdown cleanup, and readable Ask answers
- fix The "Will search for..." preview strip was overlapping the "Recent Updates" heading right below it. It's a fixed overlay, not part of normal page flow, so nothing reserved space for it. Added a live-measured
--preview-hoffset (same pattern as the header's own--topbar-h) to the page's top padding. - ux Recent Updates source breakdown: sources with 0 results this window (e.g. StackOverflow) no longer show at all, and every source (CVE, community sources, and each bot) is now sorted together by count, highest first, not CVE/Reddit/StackOverflow-first regardless of size. Reddit and StackOverflow now show their real bot filenames,
reddit.pyandstackoverflow.py(confirmed against releasetrain-bot's actual scripts), matching every other bot chip's naming convention; CVE stays a plain label since it isn't one bot's output. - feat Ask answers render lightly formatted instead of as one plain-escaped block of text:
**bold**and`code`render as real<strong>/<code>, bullet and numbered lists render as real lists, and blank lines become paragraph breaks. Still escapes the model's raw text first and only recognizes this fixed set of markdown syntax on top of that. Nothing in the answer can inject real HTML.
Ask options are always visible now, no popover to open
- ux Reworked the Ask form back to two always-visible rows: the question input on top, and every option (Model, Size, Pipeline, the three toggles, Usage, and the Ask button) in one row below it. Removed the Options (βοΈ) button and its popover from v3.35-3.40. Feedback was that hiding the controls behind a click made them easy to miss and needed an extra step just to see what's selected.
- fix Usage now refreshes on Ask-mode activation, on a Model change, and after every ask attempt, instead of only while the (now-removed) popover happened to be open.
Topbar: strictly two lines, controls right-aligned
- ux Line 1 is now brand/title on the left, Search/Ask mode toggle (and the account chip, when signed in) pushed flush to the right. Previously they sat clustered right after the title with a lot of dead space beside them. Line 2 stays the active form (input + its own right-aligned buttons), same as before.
- fix The "Will search for..." preview line no longer counts as a 3rd header row. It's now a thin floating strip anchored just below the header, so the header itself is a strict two rows regardless of whether a preview is showing.
- fix The Ask Options popover was rendering open by default, every page load, before ever being clicked, due to a CSS specificity bug (its own
display: flexsilently beat the browser's default[hidden]handling). Caught while checking this change on mobile. Also fixed the popover overflowing off the left edge of the screen on narrow viewports (it was anchored to the small gear-button cluster, which sits near the left edge once the input wraps to its own row on mobile; now anchored to the full-width form instead).
Ask can now find answers on the open web, not just Reddit
- feat The Ask agent now has a
search_webtool: when release notes, CVE records, and Reddit turn up nothing, it searches the open web and actually reads the top results (official vendor forums, bug trackers, GitHub issues - anything this platform doesn't scrape into its own data) before answering. Sources found this way show a π icon. - fix Temporal filter bug - a mismatched variable name meant the "only search the last N days" setting silently never reached any search tool. Caught from a real answer that cited a 6-month-old community post as "in the past 24 hours." Fixed and verified live.
Ollama Cloud added as a third model, and a Size picker
- feat Ollama Cloud is now a third Model option alongside Claude and Groq - a hosted API call (not a local install), so it works the same way on the production server as Groq does. Free tier.
- feat Size picker - each Model now offers Small/Medium/Large, sized by whatever unit that provider actually publishes (parameter count for Groq/Ollama, Anthropic's own Haiku/Sonnet/Opus naming). The Model and Size lists are both fetched live from the server rather than hardcoded, so they always match what's actually configured and runnable.
- fix Every model offered was verified to actually support tool calling before being listed - a couple of plausible-looking "smallest" picks (a 7B Groq model, several larger Ollama Cloud models) turned out to either reject tool calls outright or require a paid plan, so they were swapped for ones confirmed working live.
Rate-limit hits now show up in Usage, not just as an error
- feat When a provider actually rate-limits a request (e.g. Groq's "TPM: Limit 8000, Used 7333... try again in 21s"), that shows up in the Ask Options Usage line too - "⚠️ rate limited — retry in ~21s" - not only as the one-off error banner on the answer that failed. Refreshes automatically right after every ask attempt when Options is already open.
Provider quota, and a Yes/No poll for Reddit questions
- feat Usage line in Ask Options - shows how many calls have been made today and how much of the provider's own rate limit (requests and tokens) remains, sourced from the real headers the provider returned on its last call. Refreshes when the Options popover opens or the Model select changes.
- feat Reddit Yes/No poll - a π Poll chip now appears on any Reddit item in the feed whose title/self-text looks like a question (contains "?") and has at least one comment. Clicking it classifies each top-level, non-author comment as Yes/No/Unclear against the post's own question in a single batched model call, and shows the tally (e.g. "No 2 Β· Unclear 2"). Hover the chip afterward to see the per-comment breakdown. Requires sign-in, same as Ask.
Pick your model, and a simpler Ask bar
- feat Model picker - choose which model answers your question: Claude (Anthropic) or Groq (free tier). Selecting Groq is useful when the Anthropic key is out of credit or rate-limited. The answer's model is now returned by the server and available for display.
- ux Simplified the Ask bar - it was down to input, three checkboxes, two selects, and a submit button, all visible at once. The model select, pipeline select, and the three toggles (Vendor check, Temporal filter, Intent filter) now live in a popover off a single βοΈ Options button; the bar itself is just the question input plus Options and Ask (β€). Closes on outside click, Escape, or switching back to Search mode.
Ask row restructured: input left, controls right, one Ask button
- fix The Ask submit button said "Ask" right next to the "π¬ Ask" mode pill - same duplicate-label problem as the earlier Search fix. It's now an icon-only button (β€), matching Search's icon-only submit.
- fix Question input stays on the left and grows; the checkboxes, preset select, and submit button are now one grouped block on the right that moves together rather than each control wrapping independently - was reading as cluttered with all three checkboxes, the select, and the button loose on one line.
- feat The "Will ..." preview line now also reflects the checkboxes as you toggle them:
time-box to last 3 dayswhen Temporal filter is on (or the exact date if one's named in the question),tag intent:version-questionwhen Intent filter is on, and a note when Vendor check is on - all computed client-side, matching what the server will actually do. - Confirmed the question text was never being cleared on submit (verified, no code touches it) - closing the answer modal or asking again keeps exactly what you typed.
Topbar polish, and a search-term preview before you even ask
- feat "Will search for: ..." preview appears below the Ask input as you type - a deterministic, client-only preview of which words will actually drive the match, computed before any API call, so it's visible even if the configured key has no credit yet. It's an approximation (the model can still add vendor synonyms this simple filter doesn't know), not the model's own eventual query.
- fix Removed the redundant "Search" submit button next to the "π Search" mode pill (same label shown twice); it's now a plain icon button, still fully clickable and still the Enter-key default.
- fix Moved the Search/Ask mode toggle to the right end of the topbar row, after the active form's own input and buttons, instead of crowding the left edge next to the brand.
- fix The β° menu drawer no longer pads its content down by the topbar's full height before "Home" - that padding existed for a clearance the drawer doesn't actually need (it already renders above the topbar), and made the gap grow whenever Ask mode's extra checkbox row made the topbar taller.
- fix Aligned the height of every control on the Search/Ask row (input, buttons, preset select, mode toggle) so the bar reads as one consistent strip.
Evidence-gated Ask, merged topbar, light green theme
- feat Vendor check / Temporal filter / Intent filter checkboxes on the Ask form, backed by releasetrain-server's new abstention-first gates: a question with no resolvable vendor or an opinion-shaped question (e.g. "what IT task is always a nightmare") now declines outright instead of guessing, and a dated question ("as of Jan 2026") is answered against what was true then rather than the latest release overall.
- feat A live "detected intent" badge appears next to the Ask input as you type (client-side preview only - the full question is always sent to the server unchanged, since date/intent detection there needs the complete wording).
- feat Each answer card now shows vendor/intent/temporal chips when set, an "Abstained" badge when the question was declined, and a collapsible "Show internals" section with the actual search calls made and the system prompt used.
- feat Topbar merged into a single row (hamburger, brand, mode toggle, and the active Search/Ask form all share one line and wrap together on narrow screens, instead of stacking as separate rows).
- feat Light green theme, replacing the prior gray one; the card feed no longer has its own bordered panel boundary, so it reads as part of the page rather than a separate box floating on it.
Ask a question, not just search for a component
- feat Ask mode: a toggle next to the search bar swaps component search for a natural-language question, answered by Claude with tool access to the same release-note, CVE, and Reddit sources the feed indexes (backed by releasetrain-server's new
POST /api/ask). Every answer is a short summary with its sources always attached below it, never just prose on its own. - feat Pick which pipeline answers: Single-agent, Multi-agent (buggy - reproduces this project's own documented rewrite-replaces-query failure on purpose), Multi-agent (fixed - union fetch + BM25 rerank), or Compare all 3 side by side in one modal. Each answer gets a π/π so real usage builds up exactly the kind of judged comparison data a bespoke score can't provide on its own.
- feat Requires sign-in - each question is a real model call, not a free local search.
Search bar pinned to the top, full width; gray theme
- feat Search is always visible: pulled the component search bar back out of the β° drawer into the fixed topbar itself, so it stays on screen (and reachable without opening the menu) while scrolling. It now spans the full width of the page instead of a narrow sidebar column.
- feat Gray theme: page background and card surfaces are now genuinely gray (previously a near-white surface on an almost-white background), with borders darkened to match. The blue brand accent is unchanged - it's the one color that still needs to read as "interactive."
Everything but the feed moves behind the β° menu
- feat One menu drawer, one card feed: the always-visible sidebar (search, filters, stats, activity chart, top searches) and the topbar's row of view links (Graph, Arch, CVE, Risk Report, Docs, Changelog, Credits, Account, Release) are now both inside a single off-canvas drawer opened with the β° button, at every screen width, not just on mobile. The default page is just the topbar and the card feed, full width.
- feat Picking a view from the drawer closes it automatically; clicking the backdrop or pressing Escape also closes it. No filter/search/stat functionality was removed, only relocated.
Admin dashboard: system overview
- feat System overview panel in the Account view's admin section (visible to admin users only): bot-health freshness (which bots have gone quiet past their expected cadence, backed by releasetrain-server's new
/api/admin/*endpoints), MongoDB storage usage against the Atlas free-tier cap, source-attribution unknown rate, and top-line collection counts, all in one refreshable view. - feat Bots are grouped Stale / Healthy / No data, each row showing last-seen date and age against that bot's own threshold, so a silent outage (like the ones this session's bot audit found by hand) shows up here automatically instead of needing a manual sweep.
Breakdown is now by bot, not by type
- feat One number per bot, not per type: the π¦ chips in the Recent Updates breakdown now key off the real
sourceBotfield (backfilled by releasetrain-bot's new maintainer.py source-attribution pass) instead ofversionProductType. Grouping by type conflated multiple bots into one bucket ("Browser" = chrome.py + firefox.py + safari.py) and fragmented one bot into many (github.py's per-repo product names each got their own type). "unknown" covers documents from before the backfill, or that the inference genuinely couldn't place.
Every other bot source now shown in the breakdown, by type
- feat "By type" breakdown for everything not already CVE/Reddit/StackOverflow/LLM/Hypervisor: browsers, OSes, databases, languages, and every other source this system's ~30 other bots track now get their own π¦ chip (versionProductType, highest count first) instead of being invisible in the summary line entirely.
- fix Grouping normalizes casing (so "browser"/"Browser" from different bots count as one bucket) but keeps whichever original casing was seen first as the display label β an earlier version of this ran every label through a naive title-case transform, which mangled real values like "OS" β "Os" and "TypeScript" β "Typescript".
Per-source breakdown on the Recent Updates header
- feat Source breakdown line under "Recent Updates": shows how many of the current (last 4 weeks) results are π΄ CVE, π¬ Reddit, and π§ StackOverflow, with π€ LLM / π₯ Hypervisor appended when nonzero. Scoped to the same window as the header itself, not the sidebar's all-time totals, so it stays honest about what's actually in view.
Tooling, tests, and cleanup
- feat CI and smoke tests: GitHub Actions runs build, Biome lint, and a Playwright suite on every push and PR. The suite stubs the API and loads every view, failing on any uncaught JavaScript error.
- feat Configurable API endpoint: resolves from
?api=, then<meta name="api-base">, then the built-in default. No more editing a source constant to run against a local server. - feat Global fault banner: an uncaught error or rejected promise now shows one dismissible banner instead of leaving an empty UI with no signal.
- feat Single-sourced version:
package.jsonis authoritative; the build stamps it into the page. - fix Pinned the lazily-loaded CDN libraries (Chart.js, mermaid, vis-network, pako) to exact versions with
crossorigin. - fix Removed the build stack: Grunt, Jest, Babel and ESLint (all unconfigured or unused) are gone;
npm run buildis now a plainsrc/todist/copy. Dependency count dropped from ~640 packages to ~55. - fix Deleted legacy standalone pages and assets no longer reachable from the app:
/reddit,/label,/mltl,/juspn,/edi40-2023, plussrc/lib,src/app.js,src/plantuml*and the two orphaned stylesheets.src/is nowindex.html,img/anddata/graph.json.
Denser, quieter UI
- ux Compact / technical restyle: 13px base, 3px radius, flat hairline borders instead of shadows, monospace for numbers/versions/dates. Palette cut to two meaningful hues (CVE, risk) plus one interactive blue; LLM/hypervisor/"new" markers are now neutral slate, meaning carried by the chip label. Tightened topbar, sidebar, feed rows, chips and buttons.
- ux Fewer quick-filters up front: the five community/risk toggles (Pot. CVE, Reddit, Reddit Risk, Risk Latest, Risk Security, SO Risk, SO) now live in a collapsed "community & risk filters" disclosure inside Filters. The six primary toggles (Major/Minor/Patch/CVE/LLM/Hypervisor) stay visible.
- ux Sidebar sections collapsed by default except Filters. "Stats" and "Live Collection Stats" merged into one section β KPIs on top, all-time collection totals in a nested "Collection totals" disclosure.
- ux Fewer chips per feed row: dropped the license and component-type chips (repetitive β every row in a group carried the same values). Security-type and breaking-change chips stay, since they flag something actionable.
- feat Graph view: nodes with zero edges are hidden from the canvas and listed in a new "Isolated nodes" sidebar section; physics tightened and the view auto-zooms in closer after stabilization.
Hypervisor as its own category: feed, filter, KPI, chart
- feat Hypervisor releases highlighted in the feed: entries whose
versionProductTypeisHypervisor(the newhypervisor.pybot's value β VMware ESXi / Workstation / Fusion, Oracle VirtualBox, Xen, Proxmox VE, XCP-ng) get a teal left-border/background and a π₯οΈ Hypervisor chip. Mirrors the LLM treatment added in v3.22.0 via a parallelisHypervisorVersion()predicate. - feat Hypervisor quick-filter + KPI: a π₯οΈ Hypervisor sidebar toggle and a π₯οΈ Hypervisors tile in the Stats block, alongside π€ AI Models. Combines with the other quick-filter toggles the same way.
- feat Dedicated background dataset:
ensureHvVersionsLoaded()/Api.hypervisorVersions()pull the full, date-window-independent hypervisor dataset (anchored onKNOWN_HV_PRODUCT_NAMES), so the KPI/toggle show the true total and the toggle surfaces full history rather than just what's inside the 4-week feed window β hypervisor releases are as sparse in time as AI-model releases. - feat Activity chart gains a Hypervisor line: the sidebar activity chart now plots a fifth (teal) series for hypervisor releases per day, computed client-side from the full dataset via
computeHvDailyFromRaw()/refreshActivityChartHvLine(). The static mini-legend under the chart now lists all five series. - feat Shareable
?type=hvlink:releasetrain.io/?type=hvloads with the π₯οΈ Hypervisor toggle already active;setTypeParam()now round-tripsllmandhv. - feat Arch view (
?view=arch) now stacks in three tiers: hypervisor base layer β OS β applications, nested as PlantUML packages. NewaIsHypervisorComponent()(feedversionProductType === "Hypervisor", or theA_HYPERVISORname fallback) partitions components; each tier is optional and collapses out when empty. Added a VIRT sample stack (xen Β· debian Β· nginx) that exercises all three layers.
LLM as its own category: feed, filter, KPI, chart, and search
- feat AI model releases highlighted in the feed: entries whose
versionProductTypeisLLM,Embedding Model, orMultimodal Model(theai_model.pybot's values) now get a violet left-border/background and a π€ LLM chip, distinguishing them from regular software releases at a glance. - feat LLM quick-filter: a new π€ LLM toggle in the sidebar filters the feed to just AI model releases, combining with the existing Major/Minor/Patch/CVE toggles the same way they combine with each other.
- feat AI Models KPI: a new π€ AI Models tile in the sidebar Stats block, alongside Groups/Components/Reddit, giving LLM releases equal billing as their own top-level count rather than being buried in the generic type-filter list.
- fix AI Models KPI/toggle badge showed 0 even when real data existed: both were computed only from the windowed feed (
STATE.rawVersions), which almost never contains an LLM doc since AI model releases are sparse enough in time to rarely land inside the lookback window. AddedensureLlmVersionsLoaded()β a dedicated background fetch (mirrorsensureRedditLoaded()) that pulls the full, date-window-independent LLM dataset viaApi.llmVersions(), filtered client-side to realversionProductTypematches. The badge/KPI now shows this true total once loaded. - fix
Api.llmVersions()initially found only 3 of ~560 real documents: the server'sqsearch matches near-exactversionProductName, not substring "contains" (confirmed empirically βq=Claudeonly finds the doc named exactly "Claude", not "Claude 2" or "Claude 3.5 Sonnet"), so a handful of generic brand keywords like "mistral"/"openai" mostly missed. AddedKNOWN_LLM_PRODUCT_NAMES, an exact-match anchor list (~390 terms) generated fromai_model.py's actual scraped catalog β Ollama library slugs plus every OpenAI/Anthropic/Mistral/xAI/DeepSeek/Meta/Gemini Wikipedia table entry. Queried as CSV OR terms, chunked into parallel requests to keep each query string a reasonable size. Now finds ~524 of the ~564 real documents (verified live). Needs periodic regeneration asai_model.pyscrapes new models; stale entries are harmless, they just stop matching anything. - feat LLM toggle now actually surfaces full history: clicking π€ LLM merges
STATE.llmVersionsinto the candidate pool and bypasses the recency window for the merged items (same mechanism as an active search), so old AI model releases become visible in the feed instead of the toggle just showing an accurate count with nothing to click into. - feat Activity chart legend enabled, labeled, and clickable: the legend was previously hidden entirely (
display: false), so the LLM line added earlier had no visible label. Now shown at the bottom in a compact style; clicking a label toggles that line's visibility, using Chart.js's built-in legend behavior. Chart height bumped slightly to fit the legend row, with a small "Click a label to show/hide that line" hint underneath. The LLM line itself now sources fromSTATE.llmVersions(the full dataset) rather than the windowed feed, for the same reason as the KPI fix above. - fix Search couldn't find components outside the feed window: searching for a named component (e.g. "Mistral", "Ollama") previously came up empty whenever that component's releases were all older than the lookback window, even though the server correctly returned them. The recency cutoff now only applies to the default recent-activity feed; an explicit component search (or the LLM toggle) shows full history instead. New
withinFeedWindow(v, comps, bypassRecency)helper shared byapplyFilters()andfilterVersions(). - fix Autocomplete now suggests components beyond the current feed window: previously the search box only suggested names/tags already present in
STATE.rawVersions, so a component with no recent release (like most AI model brands right now) never appeared while typing. The suggestion pool is now seeded from the full/api/c/nameslist on page load, merged with what's currently loaded. - fix Range KPI now reflects what's actually shown instead of always claiming the fixed lookback window β computed from the min/max release date of the currently filtered items, so it stays honest when a search surfaces older results.
- fix Feed description text no longer shows a bare URL: several bots (
python.py,java.py,eclipse.py,ai_model.py) store a URL inversionReleaseNotesrather than prose. The card description now detects that case and showsversionReleaseCommentsinstead β the URL was already the clickable title link, so nothing is lost. - feat Lookback window widened from 7 days to 4 weeks: feed, activity chart, and Reddit/StackOverflow matching all now cover the last 28 days instead of 7. Renamed
SEVEN_DAYS_MS/SEVEN_DAYS_AGOtoLOOKBACK_MS/LOOKBACK_AGO(backed by a singleLOOKBACK_DAYS = 28constant) so the window can be tuned in one place going forward. - feat Shareable
?type=llmlink:releasetrain.io/?type=llmnow loads with the π€ LLM toggle already active. Client-only β confirmed via the API docs that there's no server-sideversionProductTypefilter param (/api/v/searchonly supportsq,channel,isCve,start/end,fields,showCount). Round-trips both ways: clicking the toggle updates the URL viasetTypeParam(), and "Clear all" removes it again.
Strip trailing commas from search queries
- fix Query normalization: trailing and leading commas are stripped before tracking a search, displaying top searches in the sidebar, and showing queries in the admin search events table.
Component search tracking, admin search activity view
- feat Search tracking: every component search is recorded server-side with query, timestamp, IP, and user agent. Logged-in users are identified by userId; unauthenticated searches are recorded as anonymous.
- feat Admin search activity: the Account view for admin users now includes a Component searches table showing all recorded searches across all users, including anonymous, sorted newest first.
- feat Top searches sidebar: the home feed sidebar shows the top 3 searched components in the last 24 hours as clickable links, open by default. Sourced from a new public aggregate endpoint.
Release view fixes, URL cleanup, view param consistency
- fix Release view: vendor-only: removed source filter dropdown; view always shows the current account's own published releases. Source filter no longer allowed switching to third-party extracted data.
- fix Experience reports embedded: reports are now stored as an array on the version document and rendered inline on load. Removed separate
knowledge_reportscollection and the extra fetch per card. - fix Vendor releases visible in home feed: two filters were hiding vendor-published releases. Server-side:
end=today(local date) excluded documents stamped with tomorrow's UTC date; vendor docs now bypass the date cap. Client-side:versionTime()maps a release date to noon UTC, which is ahead of localDate.now()for negative-offset timezones; vendor docs now bypass the future-date guard. - fix View URL params consistent with nav labels:
?view=networkrenamed to?view=releaseto match the π Release nav label. Added missing?view=accountrouting entry so the Account view is reachable via URL. - ux No
%2Cin URL: multi-component search queries now display literal commas in the address bar. Trailing commas typed in the search field are stripped before writing to the URL. - feat Subreddit search: searching a subreddit name with no matching versioned component now shows a community posts group. Posts from matching subreddits are surfaced even when no version data exists for that name.
Release Knowledge Network view
- feat Network view: new π Network nav entry. Authenticated vendors can publish releases under a unique namespace. Namespaces are validated against existing tracked vendor names. Other users can report production outcomes per release (worked well, had issues, upgraded from version).
- feat Discover tab: lists published releases with collapsible experience reports. Reports show outcome, from-version, description, date, and reporter.
- feat Publish tab: form with vendor namespace, component name, version, channel, optional release notes URL and description. Namespace is validated client-side before submission.
- ux Unauthenticated users see a gate screen explaining the feature with a direct sign-in prompt.
Risk Report: multi-component, search integration, score legend
- feat Renamed Dashboard to Risk Report: nav link and title updated to reflect the feature's purpose.
- feat Multi-component risk analysis: the risk report now reads components directly from the feed search field. Multiple comma-separated components are supported and scored together.
- feat Score legend: the sidebar shows risk level thresholds (Low, Medium, High, Critical) and the scoring factors used to compute the score.
- fix Removed redundant Component input from the Risk Report sidebar; the feed search field is now the single source of truth for component selection.
Org namespaces in share links, bookmarks, topbar login indicator
- feat Organization namespaces: users can add up to 2 org slugs to their profile. Each slug is embedded in every bookmark share link as
?org=name&share=β¦so recipients can identify the source organization. Slugs are validated as 1 to 32 alphanumeric, dash, or underscore characters. - feat Bookmarks: signed-in users can save named searches via the π button in the feed sidebar. Each bookmark stores a URL and generates a public share link. Opening a share link restores the saved search automatically.
- feat Topbar login chip: a small badge showing the logged-in user name or email appears in the topbar at all times when a session is active. Clicking it opens the Account view.
- feat Bookmark list in Account view: the profile panel lists all saved bookmarks with Open, Copy link, and Delete actions. Refresh button reloads the list from the API.
- feat Why create an account section: collapsible panel in the sign-in view lists the technical advantages of having an account including org namespaces, server-side bookmark storage, cross-device persistence, share links, JWT session, and admin role access.
- fix Org namespaces moved server-side: org names are now snapshotted onto the bookmark document at creation time and returned by the share endpoint. Share URLs are clean (
?share=abc123only). Recipients see a "Shared by: orgname" banner for 4 seconds when opening a share link. Org chips are shown on each bookmark row in the Account view. - feat Bookmark rename: an Edit button on each bookmark row opens an inline text input. Submitting saves the new name via
PUT /api/bookmarks/:idand refreshes the list. Keyboard shortcuts Enter and Escape confirm and cancel the edit. - feat Chart.js graph view: the Graph view now renders four Chart.js charts: release activity over time (line), top components by release count (horizontal bar), channel breakdown (donut), and CVE releases per week (bar). Sigma.js network graph removed. Time window and data source are selectable from the sidebar.
- feat vis-network graph view: the Graph view now renders a force-directed node and edge network. Each searched component becomes a hub node. Version nodes, CVE release nodes (diamond), Reddit posts, CVE-mention posts, high-risk posts, and StackOverflow posts are positioned as satellites. Edge length encodes date delta: nodes from today are close to the hub; older nodes are farther. Multiple searched components produce multiple hub nodes. Layer visibility, time window, and risk filters are controlled from the sidebar.
Live Collection Stats in home sidebar, mobile feed scroll, 7-day data window
- feat Live Collection Stats panel added to the default feed sidebar: shows total versions, CVE advisories, release notes, and community post counts fetched from the API on page load.
- feat Today count and yesterday delta in brackets for both Versions and Community totals: format is
54,210 [42 today, +12%]. Delta % is green when higher than yesterday, red when lower. Fetched from/api/v/aggregate/byDateand/api/aggregate/reddit/count. - ux Home sidebar stats also pre-populate the Docs sidebar Live Collection Stats so values appear immediately when switching to the Docs view.
- fix Feed panel scrollable on mobile:
max-height: 70vh; overflow-y: autoon#feedPanelatmax-width: 640pxso the version feed scrolls independently rather than expanding the full page height. - feat Data window changed from 6 months to 7 days:
Api.versionssendsstartas 7 days ago; client-side version and community post filters apply the same 7-day cutoff. Feed header updated to reflect the new window. - fix Feed sort and Range KPI now use
versionReleaseDateinstead ofversionTimestampLastUpdate. Since bots setversionTimestamptoDate.now()on every upsert, the old sort collapsed all items to today. Range now reflects actual release date spread across the 7-day window. - fix Removed
startparam fromApi.versions(): previously sendingstart = 7 days agorestricted the server to only documents withversionReleaseDatein the last 7 days. Server now uses its 2-year rolling window and returns the 150 most recently released versions; the 7-day client filter then trims the result.end=todayis still sent to suppress future-dated documents. - fix
versionTime()now strips dashes before testing the 8-digit pattern, accepting bothYYYYMMDDandYYYY-MM-DDrelease date formats. - fix Community bracket now always shown when API data is available, even when today count is zero. Previously the bracket was suppressed if
rTodayN === 0, hiding the delta from endpoints that count bycreated_utcrather than ingestion date. - fix Range KPI updates as infinite scroll loads new pages: extracted range calculation into
updateRangeKpi(items)helper, called from bothapplyFilters()and the scroll page-fetch callback after new groups are merged intoSTATE.groupsFiltered. - fix Full 7-day window now loads automatically:
appendNextGroupsalways continues viarequestAnimationFrameafter each batch, so once all local groups are rendered it falls through to the cursor-fetch branch and loads subsequent server pages without requiring a scroll. - feat Relative time labels for recent feed items: items from the last 2 hours now display "X min ago" (under 60 min), "1 hr ago" or "2 hr ago" (under 2 hr) instead of "Today". Older items keep the existing "Today" / "Yesterday" / date labels.
isNewis now based on a midnight timestamp comparison rather than string matching. - feat Activity chart added to home sidebar: compact 7-day per-day line chart showing versions and community post counts computed from loaded state. Renders using Chart.js, loaded lazily on first use.
- fix Community bracket today count now accurate: bracket is computed from
STATE.redditAllusingredditTime()after the post index loads, replacing the unreliable/api/aggregate/reddit/countper-day endpoint which counted bycreated_utcrather than ingestion date. - fix CVE feed items now open NIST NVD: the open link on CVE entries resolves to
versionUrl(the NVD advisory URL stored on the document) instead of the internal API endpoint. Falls back to the API URL whenversionUrlis absent. - fix Activity chart data sourced from range aggregate endpoints:
loadHomeStatsnow calls/api/aggregate/v/versionCountByDayand/api/aggregate/reddit/countByDaywith a single 7-day window each (2 requests total), replacing 14 individual per-day calls. Results are mapped from sparse{ _id, count }arrays to the fixed 7-day label sequence before passing toupdateActivityChart. - fix Community line in activity chart now renders correctly:
/api/aggregate/reddit/countByDaywas filteringcreated_utcwith YYYYMMDD strings, which matched nothing because the field stores Unix epoch seconds (int/double/string) or ISO date strings. Endpoint rewritten to normalizecreated_utcto a UTC Date via a$switchpipeline stage, then filter and group on the normalized value. Client also patches the community dataset fromSTATE.redditAllafter reddit loads, as a fallback for the current deployment. - feat CVE line added to activity chart: chart now shows three lines: Versions (indigo), CVE (red), Community (green). CVE per-day counts sourced from new
/api/aggregate/v/cveCountByDayendpoint, which filtersisCve: trueand groups byversionReleaseDate. Falls back to countingv.isCvefromSTATE.rawVersionswhen API data is unavailable. - fix Mobile scroll restored for all views: dashboard had no mobile CSS rule and was unscrollable with
overflow: hiddenand a two-column pane layout. All views now scroll on mobile: dashboard panes stack vertically and the page scrolls naturally; docs and ack views drop their fixed height so page scroll applies; CVE view sets amin-heightand addstouch-action: pan-yto the inner scroll list; changelog clears its overflow clip;-webkit-overflow-scrolling: touchadded to all inner-scroll containers for iOS compatibility.
Reddit integration in feed cards, timeline sort fixes & docs rewrite
- feat Reddit and Stack Overflow posts now appear inside each component feed card, interleaved chronologically with version entries using a two-pointer merge.
- feat π§ SO toggle added to the left sidebar: counts Stack Overflow posts matched to the active component set.
- fix
created_utcstored as Unix epoch seconds was being parsed as milliseconds (β 1970). Now multiplied by 1000 before passing toDate(). - fix
versionTimestampis set toDate.now()on every bot upsert, making all versions appear as "today". Timeline now usesversionReleaseDate(YYYYMMDD) as the sort key instead. - fix Reddit posts were appended as a block after all versions. Replaced
.sort()with a proper two-pointer merge of two pre-sorted arrays to guarantee chronological interleaving. - fix Left sidebar toggle counts (π¬ Reddit, β οΈ SO Risk, etc.) stayed at 0 after reddit loaded.
paintFixedCountsnow fires insideensureRedditLoaded()once the index is built. - fix
positiveScore > 0.5filter was too strict β many posts have no ML score. Feed now fetches from/api/reddit?limit=400(all recent posts by date) instead of the positive-score endpoint. - ux Partial subreddit matching: "android" matches "androiddev", "chrome" matches "googlechrome", etc.
- ux Reddit items in the feed card show an orange left border and an
r/subredditchip; Stack Overflow items show amber. - docs Docs view rewritten: marketing language removed, section headings use
:instead ofΒ·, AI chat section now describes the RAG pipeline technically (FAISS index, cosine similarity, cross-encoder reranking, LLM prompt injection). - fix Default feed no longer shows future-dated documents: server request now sends
end=todayand the client-side filter rejects any version withversionReleaseDate > now. - fix Mobile scroll broken:
html, body { overflow: hidden }was trapping all content on narrow viewports where the feed panel loses its own scroll container. Override tooverflow: auto; height: autoatmax-width: 640px. - feat New bot
nodejs.py: pollsnodejs.org/dist/index.json, derives release channel from semver and security flag, maps LTS codename, and posts to/api/v. Lookback window configurable viaLOOKBACK_DAYS.
Dashboard graphs, phone layout & changelog
- feat Hub-and-spoke dependency map on dashboard right pane: visualises componentβversions, CVE versions, Reddit posts, and Reddit+CVE edges on a DPR-aware canvas.
- feat Ecosystem snapshot graph on aggregate left pane: auto-selects the most diversely-connected component from the live dataset.
- feat Release cadence bar chart (releases/week) and Reddit mention trend line chart added to the component pane.
- fix Reddit mention trend was always empty: day-key format mismatch (
YYYYMMDDvsYYYY-MM-DD) corrected. - ux Dashboard right pane now scrolls independently; left pane and page remain locked.
- ux Changelog view added (this page) with semver-labelled entries.
- ux Graph view on phones: Sigma canvas reduced to 60 vh; sidebar controls collapse to a fixed bottom-sheet overlay.
- perf
touch-action: noneon graph canvas prevents iOS scroll hijack during pinch-zoom. - perf
prefers-reduced-motionmedia query disables all animations for users who opt out. - ux Added
meta theme-colorandcolor-schemefor better browser chrome theming.
Dashboard two-pane layout
- feat Two-pane dashboard: Total Aggregate (left, always global) and Component (right, filtered).
- feat Sample chips in empty right pane for quick component selection.
- feat Page scroll locked while dashboard is active; restored on exit.
- fix Removed duplicate "Add component" input from dashboard sidebar.
- ux Main search always syncs to dashboard on activate.
Dashboard KPIs & timeline
- feat KPI strip: Today count, Last 2 yrs, CVE today, Signals today: all with delta badges.
- feat Release & signal timeline line chart with configurable window (7 / 30 / 90 days).
- feat Update-type bar chart (major / minor / patch / CVE) with yesterday comparison.
π Dashboard view introduced
- feat New Dashboard nav entry with sidebar controls (timeline window, date picker).
- feat Aggregate version counts fetched from
/api/v/aggregateendpoints. - feat Community signals section: Reddit and StackOverflow post counts.
CVE timeline view
- feat Dedicated CVE view with filterable timeline and CVSS severity chips.
- feat Reddit / SO risk-signal overlay on CVE cards.
- ux Responsive CVE cards collapse gracefully on narrow viewports.
Graph view: Sigma.js
- feat Component dependency graph powered by Sigma.js with cost-based node colouring.
- feat Layer toggles (versions, Reddit/SO posts, CVE posts, CVE versions).
- feat Ring-overlay canvas for component groupings.
- ux Node info panel on click with links to API endpoints.
π€ Credits & Acknowledgements
We gratefully thank the following open data, open-source teams, and services whose APIs, feeds, databases, and software helped build releasetrain.io.
- NIST NVD: National Vulnerability DatabaseCVE enrichment, CVSS scores, and affected-software data
- MITRE CVE: Common Vulnerabilities and ExposuresPublic CVE identifiers and descriptions
- GitHub APIRelease notes, repository metadata, and version data
- Reddit APICommunity discussion signals for security and update topics
- Stack Exchange APIStackOverflow post data for community risk signals
- Chart.jsDashboard charts: release activity, top components, channel breakdown, CVE trend
- vis-networkGraph view: force-directed node and edge network of components, versions, CVE releases, Reddit posts, and StackOverflow posts
- PlantUMLArchitecture diagram generation
- pakoPlantUML deflate encoding
- Linux DistrowatchLinux distribution release feed
- Android WikipediaAndroid version history content
- Firefox CalendarFirefox release schedule content
- Firefox Security AdvisoriesFirefox CVE content
- iOS WikipediaiOS version history content
- Java Release FeedJava version release dates
- MySQL Release NotesMySQL release history content
- Python Release FeedPython version release information
- Eclipse Release FeedEclipse IDE release history
- DigitalOcean StatusInfrastructure release feed
- VirtualBox ChangelogVirtualBox release feed
- Microsoft Windows Release InfoWindows version release feed
- Font AwesomeIcon library
- loading.ioLoading animation assets
- regexr.comRegex development tool
- UptimeRobotUptime monitoring
π§ͺ Rewriter Eval
π§ͺ Evaluator Eval
π§ͺ Orchestrator Eval
βΊ Why create an account?
- πSave a search once, reopen it from any device.
- πShare a link and recipients see your exact filtered view.
- πStay signed in across tabs and reloads — no re-entering credentials.
- πYour saved searches are private to your account.
- π‘Admins can view, edit, and remove any user account.
- π·Add up to 2 org names to brand your share links (
?org=β¦).
Change password
Model provider keys (use your own instead of the shared server key)
A key set here is used for your own Ask requests in place of the shared server key. Stored on your account; only the last 4 characters are ever shown back. Save an empty box to clear it and fall back to the shared key.
Organization namespaces (appear in share links)
Max 2. Each name is appended to share links as ?org=name&share=β¦. Alphanumeric, dash, or underscore only.
Bookmarks
Save searches using the π button in the sidebar. Share links are public.
Installed versions
Record the versions you actually run. The Arch view compares them against the latest release to show how far each component has drifted. Saved to your account, so it follows you across devices.
βΊ Paste a list
One per line: component@version, component version, or component,version. Existing entries are updated.
System overview
Loadingβ¦
Guardrails
Mandatory
Always applied; only an admin can turn one off, and doing so removes a specific, documented safety or correctness fix.
Loadingβ¦
Optional
Applied by default at the setting below; a signed-in user may override this for their own questions.
Feedback Loop
Flags a vendor on its answers' Feedback Loop tab once real user ratings run negative past these thresholds.
Loadingβ¦
Settings
Loadingβ¦
Bot health thresholds
How many days a bot may go quiet before the System overview panel's Bot health card flags it stale. Leave a row at its default unless that bot's normal update cadence genuinely differs.
Loadingβ¦
Vendor catalog
Corrects or adds a vendor name the automatic catalog (built from tracked release data and Reddit subreddit names) doesn't resolve on its own, e.g. mapping "ada" to "Ada" when a real product's automatic verification is ambiguous.
Manual gap-fill trigger
Manually run the same automatic-catalog gap-fill a bot's own fallback triggers for a vendor with zero tracked evidence. The result also shows up in the System overview panel's "Recent vendor gap-fills" list above.
All users
Search & Ask activity
Vendors publish releases. Users report production outcomes. Collective knowledge answers questions like "How did version 4.2 perform?" or "Who upgraded successfully from 3.9?"
Value grows with participation. Sign in to publish releases and report experiences.
π Recent Updates (last 2 weeks)
No updates match the current filters.