Agora

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 APITelescopeService (list, find, byTrace, topFamilies, topTags). Read it from a controller, a test, or a script.
  • A dashboard — the @adonis-agora/telescope/ui subpath mounts the JSON query API and an SSE live-stream behind an auth guard; the separate @adonis-agora/telescope-ui package 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/alerts pages you on a brand-new exception family; @adonis-agora/telescope/ai turns 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 DiagnosticsWatcher subscribes to every agora:<lib>:<event> channel — current and future — and records each publish. A library that adopts @adonis-agora/diagnostics shows up in Telescope with zero Telescope-specific code.
  • Zero @adonis-agora/* coupling. Telescope is a separate repo with no dependency on @adonis-agora/context or @adonis-agora/diagnostics. It reads them structurally through global Symbol.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 store to the built-in lucid driver for a SQL-backed, restart-surviving store, or implement the TelescopeStore contract yourself.

Quickstart

Install the core

npm i @adonis-agora/telescope
node ace configure @adonis-agora/telescope

configure 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 pairs

Add 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 SPA

Register @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/watchers records every Lucid db:query (SQL, bindings, duration), plus mail and cache events.
  • Alerts@adonis-agora/telescope/alerts polls the store and fires a new-exception or exception-rate alert to Slack, a webhook, the console, or a custom channel.
  • AI diagnosis@adonis-agora/telescope/ai feeds 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

On this page