production-observability
Takes a Node.js or TypeScript service to production-grade observability with autotel, in an existing codebase or a new one, and keeps it there.
Skill by jagreehal
Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/jagreehal-production-observability
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Use cases: backend, devops, data, agent-building
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this skill can do and what it asks for, from its SKILL.md and code. Checked Oct 25, 2026.
- Tools
- No tools found
- Secrets
- None asked for
- Install scripts
- None found
Network hosts it talks to 1
codeload.github.com· found in install command
Files it touches
~/.claude/skills/production-observability
What's inside
- Skill name
production-observability- Description
- Takes a Node.js or TypeScript service to production-grade observability with autotel, in an existing codebase or a new one, and keeps it there. Defines the standard as a checklist an agent can verify (startup, shutdown, traces at every boundary, context propagation, request context, logs tied to traces, errors, metrics an alert can use, data safety, sampling, tests), then wires the CI ratchet that holds every later PR to it. Use when asked to "make this production ready", "add observability", "set autotel up properly", onboard a team or service to autotel, or check whether a service could be debugged in production. Do not use for one API's details: follow the links to skill autotel-core, autotel-request-logging and the rest.
- License
- Apache-2.0
- Instructions
- 252 lines in SKILL.md · view on GitHub
Files (1)
- SKILL.md
SKILL.md (first lines)
# production-observability
The bar: an on-call engineer who has never seen this code can tell that it is
failing, find the one request, follow it across every service and queue it
touched, and see why, from telemetry alone. The telemetry must not leak data,
cost more than it earns, or take the app down.
Each item below has an id. Use the same ids as the rules your code review
checks, so the standard you build to is the standard each change is reviewed
against.
## The standard
| Id | Done when | With autotel |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `safe-telemetry` | Init runs once, before the code it instruments, and cannot crash the app. Service name, version and environment come from config. Telemetry flushes on every exit. | `instrumentation.ts` loaded with `--import`; `init({ service, version, environment })`; `processHandlers: true` or your own `shutdown()` |
| `boundary-signal` | Every route, consumer, job and CLI command has a span, and every outbound call (HTTP, DB, cache, queue, model API) has a child span. | Framework adapter or middleware; `autoInstrumentations`; `trace()` on jobs; `traceConsumer` / `traceProducer` from `autotel/messaging` |
| `context-propagation` | One trace spans every service and queue a request touches. Deferred work stays inside the span that started it. | `http` / `undici` instrumentation for outbound calls; `traceProducer` injects context into messages and `traceConsumer` continues it |
| `request-context` | Each request's wide event carries the bounded ids that find it (tenant, user, order or job id, outcome) and which way each decision went (branch, fallback, retry, cache, flag variant, provider). | `getRequestLogger().set({...})`, one wide event per request |
| `structured-logs` | Server code logs through one structured logger, and every line carries `trace_id` and `span_id`. | `autoInstrumentations: ['pino']` plus `logs: true`, with the logger created after `init()` |
| `error-context` | Errors keep their cause, mark the span ERROR, and are logged once with ids. | `createStructuredError({ message, why, fix, cause })` thrown through `trace()`, or `recordStructuredError(ctx, err)` |
| `alertable-signal` | Every dependency, queue and job emits outcome by bounded reason, a duration, and for queues the lag. Alerts and SLOs read them. | `Metric#trackOutcome`, `createHistogram`, `createObservableGauge`, `autotel/slo` (skill `design-alertable-metrics`) |
| `feature-signal` | A user-facing change emits the event or metric that shows whether it worked. | `track()` or `Event` (skill `autotel-events`) |
| `no-sensitive-data` | No secrets, tokens, cookies, whole bodies or headers, or personal data beyond agreed ids reach telemetry. | `attributeRedactor: 'default'` set explicitly; fields chosen, never spread |
| `bounded-attributes` | Span names and metric labels are bounded: route templates, enum reasons. Ids live on spans and logs only. | `spanNameNormalizer: 'rest-api'`; labels from closed sets |
| `silent-drop` | Skipped, filtered, retried-out and fallen-back work is counted with a reason. | A counter or a `log.warn` with the reason, inside the span |
| `telemetry-config` | Sampling keeps every error and slow request; health checks and probes are filtered out; production runs at the agreed log level. | `sampling: 'production'` set explicitly (unset keeps everything); `spanFilter` for probes (skill `tune-sampling`) |
| `telemetry-contract` | Names that dashboards and alerts read are treated as a contract and covered by a test. | `createTraceCollector()` from `autotel/testing`, or `autotel-vitest` |
Ownership of the dashboards and alerts (skill `autotel-grafana`) and audit
trails for money and auth paths (skill `build-audit-trails`) build on this. They
are not part of the minimum.
## Existing codebase
Work in this order. Each step is mergeable on its own, and the earlier ones
make the later ones visible.
1. **Measure.** Run `npx autotel-cli map --json --no-write` (Node 22 or later)
and keep the score and the dark routes for the report. On an unsupported
framework, list entry points by hand.
2. **Startup and shutdown (`safe-telemetry`).** Set up the instrumentation file
(see [New project](#new-project)) and run the app with it. Then check the
points below before moving on:
- With no endpoint configured, autotel exports nothing.
- In production, set `OTEL_EXPORTER_OTLP_ENDPOINT` to the base URL. autotel
appends `/v1/traces`, `/v1/metrics` and `/v1/logs`, so a URL that already
ends in `/v1/traces` breaks metrics.
- `init()` throws on an unknown `sampling` preset or a bad
`attributeRedactor`, so validate config before deploying.
- `beforeExit` does not fire on `process.exit()`. Code that exits itself must
`await shutdown()` first.
3. **Entry points and outbound calls (`boundary-signal`, `context-propagation`).**
- Add the framework adapter (skill `autotel-frameworks`).
- Put the libraries the service calls in `autoInstrumentations`. It is an
allowlist and is off by default in Node, so list `http` for outbound
calls.
- Wrap jobs, crons, consumers and CLI commands in `trace()` or
`traceConsumer`.
- Re-run `map` until no route is dark.
4. **Request context and logs (`request-context`, `structured-logs`).**
- In each handler, call `getRequestLogger().set()` with the ids that find
the request.
- Route the existing logger through instrumentation so every line carries
the trace.
- Replace `console.*` in server code.
- Skill `autotel-request-logging` covers this step.
5. **Errors (`error-context`).**
- Replace bare `throw new Error('failed')` and empty catches with structured
errors that keep `cause`.
- At the HTTP boundary, return `parseError(err)`, which strips `internal`.
- Skill `autotel-structured-errors` covers this step.
6. **Data safety and cost (`no-sensitive-data`, `bounded-attributes`, `telemetry-config`).**
- Set `attributeRedactor` explicitly. It is automatic only when the
resolved environment is `production`, and the environment defaults to
`NODE_ENV`.
- Set `spanNameNormalizer` and filter health probes with `spanFilter`.
- Set `sampling: 'production'` explicitly. It keeps every error and slow
call and 10% of the rest. With no `sampling` at all, nothing is dropped,
which is right in development and expensive at scale. With your own
`spanProcessors`, wrap the exporting one in `TailSamplingSpanProcessor`
(`init()` warns when none is). Skill `tune-sampling` covers what it does
and doesn't evaluate.
7. **Signals an alert can use (`alertable-signal`, `silent-drop`).** For each
dependency, queue and job:
- count outcomes by a bounded reason
- record a duration
- for queues, observe the lag
Skill `design-alertable-metrics` turns these into alerts, and
[`incident-readiness.md`](../find-observability-gaps/references/incident-readiness.md)
lists what to emit per area.
8. **Prove it (`telemetry-contract`).**
- Add a test per critical path that asserts the span, its key attributes
and its error status (see [Proving it](#proving-it)).
- Run the app against `autotel-devtools` and follow one real request end to
end.
9. **Lock it in.** Set up [enforcement](#enforcement), so the next PR cannot
undo the work.
Leave a product decision to the team rather than guessing: which ids count as
personal data, SLO targets, and which vendor to use. Name each one in the
report.
## New project
Start with the instrumentation file and the shutdown path, before the first
route, so every later file is written against them.
```typescript
// src/instrumentation.ts — loaded with: node --import ./dist/instrumentation.js dist/server.js
import 'autotel/register'; // ESM loader hook; must come first
import { init } from 'autotel';
init({
service: process.env.OTEL_SERVICE_NAME ?? 'orders-api',
// version: SERVICE_VERSION, DD_VERSION or APP_VERSION, else the deployed
// commit (GIT_SHA, GITHUB_SHA, ...), else package.jsonFrom jagreehal/autotel, Apache-2.0.
More from jagreehal/autotel
- 0.631score
build-audit-trails
jagreehal
Build or review tamper-aware audit trails on top of OpenTelemetry spans using autotel and the autotel-audit package (`withAudit`, `setAuditAttributes`…
SkillAFreshness: A★ 8Claude Code +9 - 0.631score
find-observability-gaps
jagreehal
Scores the observability of every entry point in a codebase with `autotel map` and closes the gaps it reports.
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
autotel-anti-patterns
jagreehal
Common autotel mistakes and how to fix them.
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
autotel-testing
jagreehal
Test autotel instrumentation with createTraceCollector() and InMemorySpanExporter.
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
autotel-core
jagreehal
Explains when to reach for trace vs span vs request logger vs events in Autotel, and the package exports each lives behind.
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
migrate-to-autotel
jagreehal
Migrate an existing observability setup to autotel.
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
design-alertable-metrics
jagreehal
Designs metrics an alarm can actually be written against — picking the attributes that let a rule isolate one failing dependency, pinning metric names as a…
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
autotel-investigate
jagreehal
Query OpenTelemetry telemetry (traces, metrics, logs, LLM analytics) via the autotel CLI.
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
autotel-framework-setup
jagreehal
Set up autotel in Hono, Fastify, TanStack Start, Cloudflare Workers, Next.js, Express, MCP, and edge runtimes.
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
autotel-request-logging
jagreehal
Accumulates request-scoped context and emits one wide-event snapshot per request with getRequestLogger(), set(), setLevel(), info/warn/error, and emitNow().
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
autotel-structured-errors
jagreehal
Throws and parses errors that explain themselves with message, why, fix, link, and status, including reusable catalogs via defineErrorCatalog.
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
debug-missing-spans
jagreehal
Troubleshoot when expected OpenTelemetry spans don't reach the backend.
SkillAFreshness: A★ 8Claude Code +9
Signals
- Stars
- 8
- Forks
- 3
- Open issues
- 0
- Last commit (this folder)
- Oct 19, 2026 (8 days ago)
- Last release
- Sep 27, 2026 (1 month ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- Apache-2.0
- Repository
- github.com/jagreehal/autotel
- Website
- jagreehal.github.io/autotel/
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from jagreehal
- 0.631score
find-observability-gaps
jagreehal
Scores the observability of every entry point in a codebase with `autotel map` and closes the gaps it reports.
SkillAFreshness: A★ 8Claude Code +9 - 0.631score
build-audit-trails
jagreehal
Build or review tamper-aware audit trails on top of OpenTelemetry spans using autotel and the autotel-audit package (`withAudit`, `setAuditAttributes`…
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
autotel-anti-patterns
jagreehal
Common autotel mistakes and how to fix them.
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
autotel-testing
jagreehal
Test autotel instrumentation with createTraceCollector() and InMemorySpanExporter.
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
autotel-core
jagreehal
Explains when to reach for trace vs span vs request logger vs events in Autotel, and the package exports each lives behind.
SkillAFreshness: A★ 8Claude Code +9 - 0.626score
autotel-investigate
jagreehal
Query OpenTelemetry telemetry (traces, metrics, logs, LLM analytics) via the autotel CLI.
SkillAFreshness: A★ 8Claude Code +9
Cite this page
production-observability skill. Agent Mart. https://agentmart.dev/skills/jagreehal-production-observability (last updated 2026-10-24)