Telescope
Laravel Telescope-style observability for AdonisJS — a generic capture spine records every HTTP request, every Lucid query, and every Agora diagnostics event as a queryable entry, browsable from a self-contained dashboard, with alerts and AI exception diagnosis on top.
@adonis-agora/telescope is the AdonisJS port of the aviary NestJS nestjs-telescope
ecosystem. It records what just happened inside your app — each HTTP request, each
SQL query, each exception, and every agora:<lib>:<event> diagnostics publish — as
a uniform, queryable entry, so you can answer "what happened on trace X?"
long after the request is gone.
The problem it solves
A request comes in, fans out into a controller, a few Lucid queries, a mail send, a cache lookup, maybe a published domain event — and then it 500s. The log line tells you the error; it does not tell you the four queries that ran first, the trace they all shared, or that the same error family fired 40 times in the last hour.
Telescope captures all of it into one store, correlated by trace id, and gives you three ways to read it back:
- A headless query API —
TelescopeService(list,find,byTrace,topFamilies,topTags). Read it from a controller, a test, or a script. - A dashboard — the
@adonis-agora/telescope/uisubpath mounts the JSON query API and an SSE live-stream behind an auth guard; the separate@adonis-agora/telescope-uipackage serves a React SPA over it under the same prefix and guard (ships pre-built — no build step in your app). - Alerts & AI —
@adonis-agora/telescope/alertspages you on a brand-new exception family;@adonis-agora/telescope/aiturns an exception entry into a structured root-cause diagnosis.
How it's built
A few design choices run through every package:
- One generic diagnostics watcher. Rather than a bespoke watcher per library,
the
DiagnosticsWatchersubscribes to everyagora:<lib>:<event>channel — current and future — and records each publish. A library that adopts@adonis-agora/diagnosticsshows up in Telescope with zero Telescope-specific code. - Zero
@adonis-agora/*coupling. Telescope is a separate repo with no dependency on@adonis-agora/contextor@adonis-agora/diagnostics. It reads them structurally through globalSymbol.for(...)slots and degrades gracefully when they are absent. - Observability never breaks the thing it observes. Every recording path is fire-and-forget and fully guarded — a failing store can never break a request, a query, or a mail send.
- A pluggable store. The default is a bounded in-memory ring buffer; flip
storeto the built-inluciddriver for a SQL-backed, restart-surviving store, or implement theTelescopeStorecontract yourself.
Quickstart
Install the core
npm i @adonis-agora/telescope
node ace configure @adonis-agora/telescopeconfigure registers the provider, plugs TelescopeMiddleware onto the server
middleware stack, and publishes config/telescope.ts.
Make some requests, then read them back
import { TelescopeService } from '@adonis-agora/telescope'
const telescope = await app.container.make(TelescopeService)
await telescope.list({ type: 'request', size: 50 }) // recent requests, newest-first
await telescope.byTrace('abc123') // every entry on one trace
await telescope.topFamilies(10, 'diagnostic') // busiest lib:event pairsAdd the dashboard
The @adonis-agora/telescope/ui subpath — re-run configure and pick UI — serves the JSON
API and SSE live-stream, but not a page. For the browsable dashboard, also install
@adonis-agora/telescope-ui, the pre-built React SPA, and register its provider:
node ace configure @adonis-agora/telescope # pick "UI" (JSON API + SSE)
npm i @adonis-agora/telescope-ui # the React dashboard SPARegister @adonis-agora/telescope-ui/telescope_ui_dashboard_provider after the core
ui_provider in adonisrc.ts, then open http://localhost:3333/telescope.
The in-memory store is lost on restart — perfect for development and tests. For a
store that survives restarts and is queryable from your database, switch to the
built-in lucid storage driver.
Beyond capture
Once entries are flowing, the rest of the ecosystem reads them:
- Per-technology watchers —
@adonis-agora/telescope/watchersrecords every Luciddb:query(SQL, bindings, duration), plus mail and cache events. - Alerts —
@adonis-agora/telescope/alertspolls the store and fires anew-exceptionorexception-ratealert to Slack, a webhook, the console, or a custom channel. - AI diagnosis —
@adonis-agora/telescope/aifeeds an exception entry (plus its trace) to Claude and returns a cached cause + fix. - Extensions — a sibling lib contributes navigable entry types, declarative dashboard pages, and data providers through the extension SPI — no React, no Telescope fork.
Where to go next
Getting started
Install, configure, and read the headless API in five steps.
Capture & correlation
Watchers, the Entry model, the diagnostics spine, and trace correlation.
Storage
The TelescopeStore contract, the in-memory default, and the Lucid adapter.
Extensions
The declarative extension SPI — entry types, dashboards, data providers.
Dashboard
Mount the console, browse entries, and gate it for production.
Packages
Every @adonis-agora/telescope subpath and what it does.
Alerts
Page on new exception families via Slack, webhook, or a custom channel.
AI exception diagnosis
Structured root-cause diagnosis of exceptions, cached by family.
Configuration reference
Every config key across every package, in one place.