@aryasaatvik/motel 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/AGENTS.md +180 -0
  2. package/LICENSE +21 -0
  3. package/README.md +137 -0
  4. package/package.json +119 -0
  5. package/skills/motel-debug/SKILL.md +203 -0
  6. package/skills/motel-debug/references/effect.md +38 -0
  7. package/src/App.tsx +414 -0
  8. package/src/StartupGate.test.ts +80 -0
  9. package/src/StartupGate.tsx +263 -0
  10. package/src/cli.ts +205 -0
  11. package/src/config.ts +45 -0
  12. package/src/daemon.test.ts +547 -0
  13. package/src/daemon.ts +486 -0
  14. package/src/domain.test.ts +62 -0
  15. package/src/domain.ts +291 -0
  16. package/src/httpApi.ts +391 -0
  17. package/src/httpListPolicy.test.ts +76 -0
  18. package/src/httpListPolicy.ts +129 -0
  19. package/src/index.tsx +25 -0
  20. package/src/instructions.ts +72 -0
  21. package/src/launchAgent.test.ts +430 -0
  22. package/src/launchAgent.ts +462 -0
  23. package/src/localServer.ts +568 -0
  24. package/src/locator.ts +138 -0
  25. package/src/mcp.ts +433 -0
  26. package/src/motel.test.ts +176 -0
  27. package/src/motel.ts +88 -0
  28. package/src/motelClient.ts +353 -0
  29. package/src/opentui-jsx.d.ts +11 -0
  30. package/src/otlp.test.ts +65 -0
  31. package/src/otlp.ts +162 -0
  32. package/src/otlpProtobuf.ts +35 -0
  33. package/src/queryFilters.ts +39 -0
  34. package/src/registry.ts +115 -0
  35. package/src/runtime.ts +40 -0
  36. package/src/server.ts +11 -0
  37. package/src/services/AsyncIngest.ts +82 -0
  38. package/src/services/LogQueryService.ts +29 -0
  39. package/src/services/TelemetryQuery.ts +62 -0
  40. package/src/services/TelemetryStore.ts +2554 -0
  41. package/src/services/TraceQueryService.ts +43 -0
  42. package/src/services/ingestRpc.ts +39 -0
  43. package/src/services/queryRpc.ts +15 -0
  44. package/src/services/telemetryQueryWorker.ts +32 -0
  45. package/src/services/telemetryWorker.ts +59 -0
  46. package/src/startupBench.ts +19 -0
  47. package/src/startupLifecycle.ts +57 -0
  48. package/src/storybook/aiChatStory.tsx +244 -0
  49. package/src/storybook/fixtures/errorState.ts +44 -0
  50. package/src/storybook/fixtures/imagePaste.ts +34 -0
  51. package/src/storybook/fixtures/index.ts +62 -0
  52. package/src/storybook/fixtures/kitchenSink.ts +148 -0
  53. package/src/storybook/fixtures/rawPrompt.ts +15 -0
  54. package/src/storybook/fixtures/short.ts +27 -0
  55. package/src/storybook/fixtures/toolHeavy.ts +65 -0
  56. package/src/telemetry.test.ts +1053 -0
  57. package/src/ui/AiChatView.tsx +308 -0
  58. package/src/ui/AttrFilterModal.tsx +120 -0
  59. package/src/ui/ServiceLogs.tsx +115 -0
  60. package/src/ui/SpanContentView.tsx +184 -0
  61. package/src/ui/SpanDetail.tsx +215 -0
  62. package/src/ui/SpanDetailFull.tsx +224 -0
  63. package/src/ui/SpanDetailPane.tsx +90 -0
  64. package/src/ui/TraceDetailsPane.tsx +175 -0
  65. package/src/ui/TraceList.tsx +254 -0
  66. package/src/ui/Waterfall.tsx +389 -0
  67. package/src/ui/aiChatModel.test.ts +391 -0
  68. package/src/ui/aiChatModel.ts +773 -0
  69. package/src/ui/aiState.ts +59 -0
  70. package/src/ui/app/TraceListPane.tsx +39 -0
  71. package/src/ui/app/TraceWorkspace.tsx +452 -0
  72. package/src/ui/app/useAppLayout.ts +101 -0
  73. package/src/ui/app/useTraceScreenData.ts +590 -0
  74. package/src/ui/atoms.ts +131 -0
  75. package/src/ui/cachedLoader.test.ts +23 -0
  76. package/src/ui/cachedLoader.ts +60 -0
  77. package/src/ui/filterParser.test.ts +56 -0
  78. package/src/ui/filterParser.ts +45 -0
  79. package/src/ui/format.ts +128 -0
  80. package/src/ui/loaders.ts +101 -0
  81. package/src/ui/persistence.ts +41 -0
  82. package/src/ui/primitives.tsx +198 -0
  83. package/src/ui/state.ts +6 -0
  84. package/src/ui/theme.ts +160 -0
  85. package/src/ui/traceDetailsWidth.repro.test.ts +126 -0
  86. package/src/ui/traceSortNav.repro.seed.ts +62 -0
  87. package/src/ui/traceSortNav.repro.test.ts +231 -0
  88. package/src/ui/useAttrFilterPicker.ts +89 -0
  89. package/src/ui/useKeyboardNav.ts +1023 -0
  90. package/src/ui/waterfallFilter.test.ts +84 -0
  91. package/src/ui/waterfallFilter.ts +59 -0
  92. package/src/ui/waterfallModel.ts +130 -0
  93. package/src/ui/waterfallNav.repro.seed.ts +86 -0
  94. package/src/ui/waterfallNav.repro.test.ts +271 -0
  95. package/src/ui/waterfallNav.test.ts +453 -0
  96. package/src/ui/waterfallNav.ts +75 -0
  97. package/web/dist/assets/index-B01z9BaO.css +2 -0
  98. package/web/dist/assets/index-CYlBaY9O.js +22 -0
  99. package/web/dist/index.html +13 -0
package/AGENTS.md ADDED
@@ -0,0 +1,180 @@
1
+ # AGENTS.md
2
+
3
+ ## Commands
4
+ - Install deps: `bun install`
5
+ - Run the TUI: `bun run dev` or `bun run start` (auto-ensures a managed
6
+ OTLP daemon is running in the background so traces ingest while the TUI
7
+ is up)
8
+ - Start the background daemon only: `bun run daemon` (same as `motel start`)
9
+ - Stop the managed daemon: `bun run stop`
10
+ - Daemon status JSON: `bun run status`
11
+ - Restart the managed daemon only: `bun run restart`
12
+ - Run the local server in the foreground (no daemon, no TUI): `bun run server`
13
+ - Run tests: `bun run test`
14
+ - Query services via CLI: `motel services`
15
+ - Query traces via CLI: `motel traces <service> [limit]`
16
+ - Query a span via CLI: `motel span <span-id>`
17
+ - Query spans for one trace: `motel trace-spans <trace-id>`
18
+ - Search spans via CLI: `motel search-spans [service] [operation] [parent=<operation>] [attr.key=value ...]`
19
+ - Search traces via CLI: `motel search-traces [service] [operation] [attr.key=value ...]`
20
+ - Query trace stats via CLI: `motel trace-stats <groupBy> <agg> [service] [attr.key=value ...]`
21
+ - Query logs via CLI: `motel logs <service>`
22
+ - Search logs via CLI: `motel search-logs [service] [body] [attr.key=value ...]`
23
+ - Query log stats via CLI: `motel log-stats <groupBy> [service] [attr.key=value ...]`
24
+ - Query logs for one trace: `motel trace-logs <trace-id>`
25
+ - Query logs for one span: `motel span-logs <span-id>`
26
+ - Query facets via CLI: `motel facets <traces|logs> <field>`
27
+ - Print Effect setup instructions: `bun run instructions`
28
+ - Build the web UI: `bun run web:build`
29
+ - Dev the web UI (with hot reload): `bun run web:dev`
30
+ - Typecheck: `bun run typecheck`
31
+ - Effect LSP diagnostics over the whole project: `bunx effect-language-service diagnostics --project tsconfig.json --format text`
32
+ - Effect LSP interactive setup wizard: `bunx effect-language-service setup`
33
+
34
+ ## Release Strategy
35
+ - npm package: `@aryasaatvik/motel`
36
+ - Releases are run from an attended local session with Tegami; GitHub Actions only validates pull requests.
37
+ - Tags are versioned as `vX.Y.Z` (`git tag --sort=-version:refname` shows `v0.2.4`, `v0.2.3`, ...)
38
+ - Add user-facing release notes under `.tegami/` and commit them with the implementation they describe.
39
+ - `bun run version:packages` consumes pending entries, updates the package version and changelog, writes the publish lock, and opens or updates `tegami/version-packages` against `dev`.
40
+ - After the version pull request is merged, run `bun run release` from a clean, current `dev` branch with npm and GitHub CLI authentication.
41
+ - The release command runs typechecks, Effect diagnostics, tests, and package validation before Tegami publishes npm, pushes the matching `v<version>` tag, and creates the GitHub Release.
42
+ - See `docs/release.md` for the attended release and verification procedure.
43
+ - Publishing does not install or restart the machine-global Motel service; that cutover is a separate operation.
44
+
45
+ ## Effect LSP
46
+ The repo is wired up with `@effect/language-service` as a `tsconfig.json` `plugins` entry. Editors that pick up the TypeScript workspace plugin (Zed, VSCode, Cursor, NVim via vtsls) will surface Effect-specific diagnostics, quick fixes, and refactors inline. In Zed this requires selecting the workspace TypeScript version — it does so automatically when `node_modules/typescript` is present.
47
+
48
+ ## Verification
49
+ - The built-in verification step is `bun run typecheck`.
50
+ - For runtime verification, start the TUI or server once, then query `http://127.0.0.1:27686/api/services`, `http://127.0.0.1:27686/api/spans/<span-id>`, `http://127.0.0.1:27686/openapi.json`, and `motel logs motel-otel-tui`.
51
+ - For span-centric debugging, use `http://127.0.0.1:27686/api/spans/search?...`, `http://127.0.0.1:27686/api/spans/<span-id>/logs`, and `http://127.0.0.1:27686/api/traces/<trace-id>/spans`.
52
+
53
+ ## API Notes
54
+ - List and search endpoints return a `meta` object with `limit`, `lookback`, `returned`, `truncated`, and `nextCursor`.
55
+ - `/api/traces` and `/api/traces/search` return summaries by default. Use `/api/traces/<trace-id>` for the full trace tree.
56
+ - `/api/logs` and `/api/logs/search` support `severity` (e.g. `?severity=ERROR`), case-insensitive body search, and `attrContains.<key>=<substring>` for substring search inside attribute values.
57
+ - `/api/spans/search` supports `traceId` to scope to one trace, `attr.<key>=<value>` for exact match, and `attrContains.<key>=<substring>` for case-insensitive substring search inside attribute values.
58
+ - `/api/ai/calls` searches AI SDK calls (streamText, generateText, etc.) with first-class filters for `model`, `provider`, `sessionId`, `functionId`, `operation`, `status`, `text` (cross-field search), and returns compact summaries with previews and token usage.
59
+ - `/api/ai/calls/<span-id>` returns the full detail of a single AI call including complete prompt messages, response text, tool calls, timing, and correlated logs.
60
+ - `/api/ai/stats` aggregates AI call statistics by `provider`, `model`, `functionId`, `sessionId`, or `status` with aggregations: `count`, `avg_duration`, `p95_duration`, `total_input_tokens`, `total_output_tokens`.
61
+ - `/api/facets?type=traces&field=attribute_keys&service=<svc>` lists span-attribute keys for a service, ranked by discriminating power (keys with many distinct values first). Pair with `field=attribute_values&key=<key>` to list values for a specific key. Used by the TUI `f` attribute filter.
62
+ - `/api/docs` lists available documentation; `/api/docs/debug` and `/api/docs/effect` return the full skill content.
63
+
64
+ ## Architecture
65
+ - `src/index.tsx` creates the OpenTUI renderer and mounts the app.
66
+ - `src/App.tsx` composes the top-level screen: header, footer, and the
67
+ drill-in workspace. Heavy logic is delegated to the modules below.
68
+ - `src/ui/app/useTraceScreenData.ts` owns the atoms and data-loading
69
+ effects for traces, logs, services, and cache warming.
70
+ - `src/ui/app/useAppLayout.ts` is the single source for layout math
71
+ (pane widths, body lines, viewport rows, drill-in level).
72
+ - `src/ui/app/TraceWorkspace.tsx` renders the drill-in state machine:
73
+ L0 (trace list), L1 (waterfall), L2 (span detail), plus the service
74
+ logs side mode. When drilled in the list is hidden entirely and the
75
+ detail pane(s) expand to fill.
76
+ - `src/ui/app/TraceListPane.tsx` hosts the trace list: header + optional
77
+ filter bar + virtual-windowed body (no opentui scrollbox — that had a
78
+ race with Yoga layout timing).
79
+ - `src/ui/TraceList.tsx` exports `TraceListHeader` (the `TRACES 100 · ...`
80
+ strip) and `TraceListBody` (virtual-windowed rows with mouse-wheel
81
+ scrolling). The body owns its own scrollOffset state, preserves the
82
+ selected row's visual position across auto-refresh shifts, and snaps
83
+ the window to follow selection that moves off-screen.
84
+ - `src/ui/Waterfall.tsx` renders the waterfall timeline with a
85
+ virtualised scroll viewport; `src/ui/waterfallNav.ts` is the pure
86
+ collapse/expand/walk resolver (unit-tested).
87
+ - `src/ui/TraceDetailsPane.tsx` is the L1 body: header + waterfall.
88
+ - `src/ui/SpanDetailPane.tsx` is the L2 body; renders
89
+ `src/ui/SpanDetail.tsx` below a header that owns the span identity.
90
+ - `src/ui/useKeyboardNav.ts` centralises the keyboard handlers and
91
+ cross-pane navigation state transitions.
92
+ - `src/motel.ts` composes and runs the public Effect command tree; `src/cli.ts` exports typed telemetry query leaves and handlers.
93
+ - `src/runtime.ts` wires the Effect beta runtime and OTEL trace + log exporters.
94
+ - `src/localServer.ts` starts the local Bun OTLP/query server.
95
+ - `src/httpApi.ts` defines the typed Effect HttpApi surface and OpenAPI spec for the local server.
96
+ - `src/httpListPolicy.ts` owns pure HTTP list/search parameter decoding, bounds, cursors, and pagination metadata shaping.
97
+ - `src/server.ts` runs the local server without the TUI.
98
+ - `src/instructions.ts` contains the copied setup instructions for other Effect apps.
99
+ - `src/services/TelemetryStore.ts` persists traces and logs in SQLite and exposes indexed queries through writer and read-only service identifiers.
100
+ - `src/services/TelemetryQuery.ts` proxies read-only store calls to `src/services/telemetryQueryWorker.ts`, keeping synchronous Bun SQLite queries off the HTTP event loop.
101
+ - `src/config.ts` is the source of truth for ports and env-driven OTEL settings.
102
+ - `web/` is a Vite + React SPA for the browser-based UI (Tailwind CSS, `@effect/atom-react`, `AtomHttpApi`).
103
+ - `web/src/api.ts` creates the typed `AtomHttpApi.Service` client from `src/httpApi.ts`.
104
+ - `web/src/pages/` contains route pages: TracesPage, TraceDetailPage, LogsPage, AiCallsPage.
105
+ - `web/src/components/` contains Waterfall and SpanDetail components.
106
+ - The server in `src/localServer.ts` serves `web/dist/` as static files with SPA fallback for non-API routes.
107
+
108
+ ## Tests
109
+ - `bun run test` runs the suite. Three kinds of tests live in the repo:
110
+ - `src/telemetry.test.ts` exercises the SQLite TelemetryStore with
111
+ OTLP payloads end-to-end.
112
+ - `src/ui/waterfallNav.test.ts` unit-tests the pure collapse/expand
113
+ resolver (no UI).
114
+ - `src/ui/*.repro.test.ts` drive the real TUI under `tuistory` to
115
+ reproduce regressions, using deterministic traces seeded into SQLite
116
+ by child processes. They become no-op passes when `tuistory` is absent.
117
+
118
+ ## Effect Observability Guidance
119
+ - Inspect the target repo’s existing Effect runtime and observability wiring before adding anything new.
120
+ - Prefer the repo’s existing Effect-native observability APIs if available.
121
+ - If `effect/unstable/observability` is already the best fit, prefer it over adding `@effect/opentelemetry`.
122
+ - Only add new OpenTelemetry SDK packages when the repo already uses them or they are clearly required.
123
+ - Merge telemetry into the main runtime once, not per-feature.
124
+ - Prefer structured log annotations so fields like `sessionID`, `modelID`, `providerID`, and `tool` are queryable.
125
+
126
+ ## Local OTEL Ports
127
+ - Local API / UI base: `http://127.0.0.1:27686`
128
+ - OTLP HTTP traces: `http://127.0.0.1:27686/v1/traces`
129
+ - OTLP HTTP logs: `http://127.0.0.1:27686/v1/logs`
130
+ - Health: `http://127.0.0.1:27686/api/health`
131
+
132
+ ## Env Vars
133
+ - `MOTEL_OTEL_ENABLED`: defaults to `false` (set to `true` to emit self-traces for debugging motel itself)
134
+ - `MOTEL_OTEL_SERVICE_NAME`: defaults to `motel-otel-tui`
135
+ - `MOTEL_OTEL_BASE_URL`: defaults to `http://127.0.0.1:27686`
136
+ - `MOTEL_OTEL_HOST`: defaults to `127.0.0.1`
137
+ - `MOTEL_OTEL_PORT`: defaults to `27686`
138
+ - `MOTEL_OTEL_EXPORTER_URL`: defaults to `http://127.0.0.1:27686/v1/traces`
139
+ - `MOTEL_OTEL_LOGS_EXPORTER_URL`: defaults to `http://127.0.0.1:27686/v1/logs`
140
+ - `MOTEL_OTEL_QUERY_URL`: defaults to `http://127.0.0.1:27686`
141
+ - `MOTEL_OTEL_DB_PATH`: defaults to `${XDG_STATE_HOME:-~/.local/state}/motel/telemetry.sqlite` (one shared DB per machine; daemon log + lock + instance registry live in the same directory)
142
+ - `MOTEL_RUNTIME_DIR`: overrides the daemon log, lock, and instance-registry directory (primarily for isolated tests and custom managed instances)
143
+ - `MOTEL_OTEL_TRACE_LOOKBACK_MINUTES`: defaults to `1440` (24h)
144
+ - `MOTEL_OTEL_TRACE_LIMIT`: defaults to `100`
145
+ - `MOTEL_OTEL_LOG_LIMIT`: defaults to `80`
146
+ - `MOTEL_OTEL_RETENTION_HOURS`: defaults to `168` (7d)
147
+ - `MOTEL_OTEL_MAX_DB_SIZE_MB`: defaults to `1024` (size-based retention cap)
148
+ - `MOTEL_OTEL_RETENTION_TRACE_BATCH`: defaults to `100` completed traces per cleanup pass
149
+ - `MOTEL_OTEL_RETENTION_LOG_BATCH`: defaults to `5000` logs per cleanup pass
150
+ - `MOTEL_OTEL_RETENTION_INTERVAL_SECONDS`: defaults to `10`
151
+
152
+ ## TUI Keys
153
+ - `?`: toggle shortcut help
154
+ - `j` / `k` or `up` / `down`: move trace or span selection
155
+ - `h` / `left`: collapse current span, or step to parent
156
+ - `l` / `right`: expand current span, or step to first child
157
+ - `ctrl-n` / `ctrl-p`: switch traces while staying in the details area
158
+ - `gg` / `home`: jump to the first trace or span
159
+ - `G` / `end`: jump to the last trace or span
160
+ - `ctrl-u` / `pageup`: page up
161
+ - `ctrl-d` / `pagedown`: page down
162
+ - `enter`: drill in one level (list → waterfall → span detail)
163
+ - `esc`: back out one level
164
+ - `tab`: toggle service logs view
165
+ - `[` / `]`: switch services
166
+ - `s`: cycle sort mode (recent → slowest → errors)
167
+ - `t`: cycle theme (motel-default → tokyo-night → catppuccin)
168
+ - `/`: enter filter mode.
169
+ - **In the trace list (L0)** the input matches against the root operation name. Composable modifiers:
170
+ - `:error` — restrict to traces with at least one failed span (client-side)
171
+ - `:ai <query>` — FTS5-backed search against LLM prompt/response/tool content (`AI_FTS_KEYS`) across every span in the trace. Tokens are prefix-matched and implicitly AND'd. Debounced 250ms.
172
+ - Modifiers compose: `/ :ai rate limit :error`
173
+ - **In the waterfall (L1/L2)** the input runs a client-side substring match against each span's operation name and tag values. Non-matching spans are dimmed; the filter bar shows the live match count. `enter` commits (dim persists while you navigate); `esc` clears.
174
+ - `f`: open attribute filter picker (browse span-attribute keys → values for the current service; `backspace` walks back to keys; `esc` in the trace list clears the active filter)
175
+ - `a`: pause or resume auto-refresh
176
+ - `r`: refresh now
177
+ - `c`: copy setup instructions for another Effect app
178
+ - `o`: open selected trace in the browser
179
+ - `y`: copy selected trace or span id
180
+ - `q`: quit
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kit Langton
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,137 @@
1
+ # motel
2
+
3
+ A local OpenTelemetry ingest + TUI viewer for development, backed by
4
+ SQLite. Point your app's OTLP/HTTP exporters at the local motel server
5
+ and debug with real runtime evidence — from a terminal, the built-in web
6
+ UI, or directly from an AI coding agent.
7
+
8
+ ## For agents: install the motel-debug skill
9
+
10
+ `motel` ships a companion skill that teaches Claude Code, OpenCode,
11
+ Cursor, Codex, and 40+ other agents how to debug with runtime evidence
12
+ by querying motel's local OTLP store. Install it once and any future
13
+ agent session in the project will know how to use it.
14
+
15
+ ```bash
16
+ # Project-local (adds to .claude/skills, .agents/skills, etc.)
17
+ npx skills add aryasaatvik/motel --skill motel-debug
18
+
19
+ # Or globally, for every project
20
+ npx skills add aryasaatvik/motel --skill motel-debug -g
21
+ ```
22
+
23
+ See the full skill at [`skills/motel-debug/SKILL.md`](skills/motel-debug/SKILL.md).
24
+
25
+ ## For humans: install and run the TUI
26
+
27
+ motel is distributed on npm as `@aryasaatvik/motel`. The binary is a Bun
28
+ script, so Bun must be on your `PATH` at runtime:
29
+
30
+ ```bash
31
+ # one-off (no install)
32
+ bunx @aryasaatvik/motel
33
+
34
+ # or install globally
35
+ bun add -g @aryasaatvik/motel
36
+ motel
37
+
38
+ # npm also works (Bun still required to run it)
39
+ npm install -g @aryasaatvik/motel
40
+ ```
41
+
42
+ Don't have Bun?
43
+
44
+ ```bash
45
+ curl -fsSL https://bun.sh/install | bash
46
+ ```
47
+
48
+ `motel` starts the local OTLP ingest server on
49
+ `http://127.0.0.1:27686` and launches the TUI. Press `?` once inside for
50
+ the keyboard cheat sheet, or `c` to copy paste-ready setup instructions
51
+ for any Effect/OTEL app you want to trace.
52
+
53
+ Requirements: [Bun](https://bun.sh/) v1.1 or newer.
54
+
55
+ ### macOS service from the maintained checkout
56
+
57
+ The per-user LaunchAgent intentionally runs
58
+ `~/.bun/bin/bun ~/.bun/bin/motel server`. For a maintained-checkout
59
+ installation, prepare and link the merged `dev` checkout before installing
60
+ the service:
61
+
62
+ ```bash
63
+ bun install --frozen-lockfile
64
+ bun run web:build
65
+ bun link
66
+ motel service install
67
+ ```
68
+
69
+ This service path does not discover npm-global or arbitrary `PATH`
70
+ executables. `motel service install` verifies both stable Bun bin paths before
71
+ writing or loading the LaunchAgent. Re-running it leaves an equivalent loaded
72
+ service unchanged and loads an equivalent definition that is currently
73
+ unloaded.
74
+
75
+ ## How your app connects
76
+
77
+ Once motel is running, point your app's OTLP/HTTP exporters at these
78
+ local endpoints:
79
+
80
+ ```
81
+ http://127.0.0.1:27686/v1/traces
82
+ http://127.0.0.1:27686/v1/logs
83
+ ```
84
+
85
+ Motel keeps everything in a machine-global local SQLite database at
86
+ `${XDG_STATE_HOME:-~/.local/state}/motel/telemetry.sqlite`. One managed
87
+ daemon is shared across local projects. No Docker, no cloud account.
88
+
89
+ The store retains seven days of telemetry by default and targets a 1 GB
90
+ active-data ceiling using bounded background batches. Recent data is preserved while
91
+ the oldest completed traces and logs are removed first. Configure the policy
92
+ with `MOTEL_OTEL_RETENTION_HOURS`, `MOTEL_OTEL_MAX_DB_SIZE_MB`,
93
+ `MOTEL_OTEL_RETENTION_TRACE_BATCH`, `MOTEL_OTEL_RETENTION_LOG_BATCH`, and
94
+ `MOTEL_OTEL_RETENTION_INTERVAL_SECONDS`. Existing databases created without
95
+ incremental auto-vacuum are never silently rewritten at startup; deleted pages
96
+ are reused, but shrinking such a historical file requires an explicit offline
97
+ SQLite `VACUUM` chosen by the user.
98
+
99
+ ## How agents connect
100
+
101
+ Agents with the `motel-debug` skill installed will automatically use
102
+ motel's HTTP API. The full OpenAPI spec is at
103
+ `http://127.0.0.1:27686/openapi.json` — the key endpoints are:
104
+
105
+ ```
106
+ GET /api/health liveness check
107
+ GET /api/services services reporting telemetry
108
+ GET /api/traces?service=<service> recent traces for a service
109
+ GET /api/traces/<trace-id> full trace tree
110
+ GET /api/spans/<span-id> single span + logs
111
+ GET /api/logs?service=<service> recent logs
112
+ GET /api/traces/search?... structured trace search
113
+ GET /api/logs/search?... structured log search
114
+ GET /api/ai/calls AI SDK call inspector
115
+ ```
116
+
117
+ ## TUI keys
118
+
119
+ - `?` — keyboard cheat sheet
120
+ - `j` / `k` or `↑` / `↓` — move selection
121
+ - `enter` / `esc` — drill in / back out (trace → waterfall → span detail)
122
+ - `[` / `]` — switch service
123
+ - `tab` — toggle service logs
124
+ - `/` — filter traces
125
+ - `s` — cycle sort (recent → slowest → errors)
126
+ - `t` — cycle theme
127
+ - `c` — copy paste-ready setup instructions for another app
128
+ - `o` — open selected trace in the browser
129
+ - `q` — quit
130
+
131
+ ## Privacy note
132
+
133
+ motel is a local development tool, but your app can emit sensitive
134
+ telemetry. Correlated logs may include secrets, tokens, or PII if your
135
+ app logs them; AI call traces may include full prompt content and
136
+ response text. Treat the local SQLite store as sensitive development
137
+ data when pointing motel at real workloads.
package/package.json ADDED
@@ -0,0 +1,119 @@
1
+ {
2
+ "name": "@aryasaatvik/motel",
3
+ "version": "0.3.0",
4
+ "description": "A local OpenTelemetry ingest + TUI viewer for development, backed by SQLite.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Kit Langton",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/aryasaatvik/motel.git"
11
+ },
12
+ "homepage": "https://github.com/aryasaatvik/motel#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/aryasaatvik/motel/issues"
15
+ },
16
+ "keywords": [
17
+ "opentelemetry",
18
+ "otel",
19
+ "tracing",
20
+ "observability",
21
+ "tui",
22
+ "sqlite",
23
+ "effect",
24
+ "opentui"
25
+ ],
26
+ "workspaces": [
27
+ "web"
28
+ ],
29
+ "engines": {
30
+ "bun": ">=1.3.0"
31
+ },
32
+ "publishConfig": {
33
+ "access": "public",
34
+ "registry": "https://registry.npmjs.org/"
35
+ },
36
+ "overrides": {
37
+ "@grpc/grpc-js": "1.14.4",
38
+ "protobufjs": "7.6.4",
39
+ "shell-quote": "1.9.0",
40
+ "ws": "8.21.0"
41
+ },
42
+ "files": [
43
+ "src",
44
+ "web/dist",
45
+ "skills/motel-debug/SKILL.md",
46
+ "skills/motel-debug/references/effect.md",
47
+ "LICENSE",
48
+ "README.md",
49
+ "AGENTS.md"
50
+ ],
51
+ "bin": {
52
+ "motel": "src/motel.ts",
53
+ "motel-mcp": "src/mcp.ts"
54
+ },
55
+ "scripts": {
56
+ "clear-motel-debug": "bun run skills/motel-debug/scripts/clear-motel-debug.ts",
57
+ "dev": "MOTEL_OTEL_ENABLED=true bun run src/motel.ts tui",
58
+ "start": "bun run src/motel.ts tui",
59
+ "daemon": "bun run src/motel.ts daemon",
60
+ "status": "bun run src/motel.ts status",
61
+ "stop": "bun run src/motel.ts stop",
62
+ "restart": "bun run src/motel.ts restart",
63
+ "server": "bun run src/motel.ts server",
64
+ "mcp": "bun run src/mcp.ts",
65
+ "test": "bun test",
66
+ "cli": "bun run src/motel.ts",
67
+ "instructions": "bun run src/motel.ts instructions",
68
+ "services": "bun run src/motel.ts services",
69
+ "logs": "bun run src/motel.ts logs",
70
+ "trace-logs": "bun run src/motel.ts trace-logs",
71
+ "span-logs": "bun run src/motel.ts span-logs",
72
+ "span": "bun run src/motel.ts span",
73
+ "trace-spans": "bun run src/motel.ts trace-spans",
74
+ "search-spans": "bun run src/motel.ts search-spans",
75
+ "trace-stats": "bun run src/motel.ts trace-stats",
76
+ "log-stats": "bun run src/motel.ts log-stats",
77
+ "web:dev": "bun run --cwd web dev",
78
+ "web:build": "bun run --cwd web build",
79
+ "story:chat": "bun run src/storybook/aiChatStory.tsx",
80
+ "bench:motel-cold-start": "bun run scripts/bench-motel-cold-start.ts",
81
+ "bench:ingest-logs": "bun run scripts/bench-ingest-logs.ts",
82
+ "bench:ingest-traces": "bun run scripts/bench-ingest-traces.ts",
83
+ "bench:search-spans": "bun run scripts/bench-search-spans.ts",
84
+ "tegami": "bun scripts/tegami.mts",
85
+ "version:packages": "bun run tegami version",
86
+ "release:check": "bun run typecheck && bun run web:typecheck && bunx effect-language-service diagnostics --project tsconfig.json --format text && bun run test && bun run release:validate",
87
+ "release": "bun run release:check && bun run tegami publish",
88
+ "release:validate": "bun run scripts/validate-release.ts",
89
+ "typecheck": "tsc --noEmit",
90
+ "web:typecheck": "tsc --noEmit -p web/tsconfig.json",
91
+ "prepublishOnly": "bun run web:build"
92
+ },
93
+ "devDependencies": {
94
+ "@effect/language-service": "0.87.1",
95
+ "@types/bun": "^1.3.14",
96
+ "@types/react": "^19.2.17",
97
+ "tegami": "1.2.6",
98
+ "typescript": "^6.0.3"
99
+ },
100
+ "dependencies": {
101
+ "@effect/atom-react": "4.0.0-beta.101",
102
+ "@effect/opentelemetry": "4.0.0-beta.101",
103
+ "@effect/platform-bun": "4.0.0-beta.101",
104
+ "@opentelemetry/api": "^1.9.0",
105
+ "@opentelemetry/exporter-logs-otlp-http": "^0.219.0",
106
+ "@opentelemetry/exporter-trace-otlp-http": "^0.219.0",
107
+ "@opentelemetry/otlp-transformer": "0.214.0",
108
+ "@opentelemetry/sdk-logs": "^0.219.0",
109
+ "@opentelemetry/sdk-node": "^0.219.0",
110
+ "@opentelemetry/sdk-trace-base": "^2.8.0",
111
+ "@opentelemetry/sdk-trace-node": "^2.8.0",
112
+ "@opentui/core": "0.4.2",
113
+ "@opentui/react": "0.4.2",
114
+ "effect": "4.0.0-beta.101",
115
+ "protobufjs": "7.6.4",
116
+ "react": "^19.2.7",
117
+ "scheduler": "^0.27.0"
118
+ }
119
+ }
@@ -0,0 +1,203 @@
1
+ ---
2
+ name: motel-debug
3
+ description: Debug applications with motel, a local OpenTelemetry ingest and query server. Use when the user wants runtime-evidence debugging with traces or logs, wants temporary debug instrumentation that can be removed later, or needs a repo wired to send OTLP/HTTP telemetry to a local motel server. If the target repo uses Effect or @effect/*, also read references/effect.md.
4
+ ---
5
+
6
+ # Motel Debug
7
+
8
+ You are in **debug mode**. Debug with runtime evidence, not guesswork.
9
+
10
+ Agents guess based on code alone. You need actual runtime data. Motel is the local OpenTelemetry server that collects traces and logs — use it as your evidence loop.
11
+
12
+ Default local server details:
13
+
14
+ - Base URL: `http://127.0.0.1:27686`
15
+ - OTLP traces: `POST /v1/traces`
16
+ - OTLP logs: `POST /v1/logs`
17
+ - Query API: `GET /api/*`
18
+ - OpenAPI: `GET /openapi.json`
19
+ - Header: `Content-Type: application/json`
20
+ - Auth: none by default
21
+
22
+ If the user provides a different motel URL, use that instead of the default.
23
+
24
+ ## Workflow
25
+
26
+ ### 1. Verify motel is running — and start it if not
27
+
28
+ Check `GET /api/health`. If it returns 200, continue.
29
+
30
+ If it fails (connection refused, timeout, non-200), motel isn't running.
31
+ Start it as a background daemon — **do not** launch the TUI, which is
32
+ interactive and will block your shell:
33
+
34
+ ```bash
35
+ motel start
36
+ ```
37
+
38
+ `motel start` ensures the machine-global managed daemon is running, writes
39
+ runtime files under `${XDG_STATE_HOME:-~/.local/state}/motel/`, and returns a
40
+ JSON status blob. It is idempotent and shared across local projects. If motel isn't on `PATH`, fall
41
+ back to `bunx @aryasaatvik/motel start`.
42
+
43
+ After starting, re-check `GET /api/health` (may take 1–2s to become
44
+ ready). If it still fails, read `${XDG_STATE_HOME:-~/.local/state}/motel/daemon.log` for the error
45
+ and surface it to the user.
46
+
47
+ Other lifecycle commands, for reference:
48
+
49
+ ```bash
50
+ motel status # JSON status (running? pid? originating workdir?)
51
+ motel stop # stop the shared managed daemon for all local projects
52
+ ```
53
+
54
+ Discover reporting services with `GET /api/services` when needed.
55
+
56
+ ### 2. Generate hypotheses
57
+
58
+ Before touching any code, generate **3-5 specific hypotheses** about why the bug occurs. Be precise — "the cache key doesn't include the user ID" is better than "something is wrong with caching."
59
+
60
+ ### 3. Instrument with tagged debug blocks
61
+
62
+ Add the minimum instrumentation needed to confirm or reject **all** hypotheses in parallel. Every debug block must:
63
+
64
+ - Be wrapped in `#region motel debug` / `#endregion motel debug` markers
65
+ - Include a `debug.hypothesis` attribute linking it to a specific hypothesis
66
+ - Use whatever tracing/logging mechanism the codebase already has (spans, structured logs, annotations — not raw `fetch` calls)
67
+
68
+ Tag every piece of debug instrumentation with structured attributes so you can query it later. Reuse these keys:
69
+
70
+ | Key | Purpose |
71
+ |-----|---------|
72
+ | `debug.session` | Groups all instrumentation for this debug session |
73
+ | `debug.hypothesis` | Links to a specific hypothesis (e.g. `"cache-miss"`, `"A"`) |
74
+ | `debug.step` | Position in the flow (e.g. `"entry"`, `"before-write"`, `"after-read"`) |
75
+ | `debug.label` | Human-readable description of what this point captures |
76
+
77
+ Choose log placements based on your hypotheses:
78
+
79
+ - Function entry with parameters
80
+ - Function exit with return values
81
+ - Values before and after critical operations
82
+ - Branch execution paths (which if/else ran)
83
+ - State mutations and intermediate values
84
+ - Suspected error or edge-case values
85
+
86
+ Guidelines:
87
+
88
+ - At least 1 instrumentation point is required; never skip instrumentation
89
+ - Do not exceed 10 — if you think you need more, narrow your hypotheses
90
+ - Typical range is 2-6
91
+
92
+ ### 4. Reproduce the issue
93
+
94
+ - If a failing test exists, run it directly
95
+ - If reproduction is straightforward (CLI command, curl, simple script), write and run it yourself
96
+ - Otherwise, ask the user to reproduce — provide clear numbered steps and remind them to restart if needed
97
+ - Once a reproduction pathway is established, reuse it for all subsequent iterations
98
+
99
+ ### 5. Analyze evidence
100
+
101
+ Query motel for the debug instrumentation:
102
+
103
+ ```bash
104
+ curl "http://127.0.0.1:27686/api/spans/search?service=<service>&attr.debug.hypothesis=<id>"
105
+ curl "http://127.0.0.1:27686/api/logs/search?service=<service>&attr.debug.session=<session>"
106
+ curl "http://127.0.0.1:27686/api/traces/search?service=<service>&attr.debug.hypothesis=<id>"
107
+ ```
108
+
109
+ For each hypothesis, evaluate: **CONFIRMED**, **REJECTED**, or **INCONCLUSIVE** — cite specific spans, logs, or attribute values as evidence.
110
+
111
+ ### 6. Fix only with evidence
112
+
113
+ Do **not** fix without runtime evidence. When you fix:
114
+
115
+ - Keep all debug instrumentation in place — do not remove it yet
116
+ - Make the fix as small and targeted as possible
117
+ - Reuse existing architecture and patterns; do not overengineer
118
+
119
+ ### 7. Verify the fix
120
+
121
+ Reproduce the issue again with instrumentation still active. Compare before/after evidence:
122
+
123
+ - Cite specific log lines or span attributes that prove the fix works
124
+ - If the fix failed: **revert code changes from rejected hypotheses** (do not let speculative fixes accumulate), generate new hypotheses from different subsystems, add more instrumentation, and iterate
125
+ - Iteration is expected. Taking longer with more data yields better fixes.
126
+
127
+ ### 8. Clean up
128
+
129
+ Only after the fix is verified **and** the user confirms there are no remaining issues:
130
+
131
+ - Run the cleanup script or remove blocks manually (see Cleanup section below)
132
+ - Run `git diff` to confirm only the intentional fix remains
133
+
134
+ ## Instrumentation Rules
135
+
136
+ Wrap every temporary debug block in these exact markers:
137
+
138
+ ```ts
139
+ // #region motel debug
140
+ // temporary debug instrumentation
141
+ // #endregion motel debug
142
+ ```
143
+
144
+ Use whatever the codebase already provides for tracing and logging. The markers are language-comment wrappers — adapt the comment syntax for non-JS/TS files (e.g. `# #region motel debug` for Python).
145
+
146
+ **Do not:**
147
+ - Log secrets, tokens, passwords, or raw PII
148
+ - Remove instrumentation before post-fix verification succeeds
149
+ - Use `setTimeout`, `sleep`, or artificial delays as a "fix"
150
+ - Let code changes from rejected hypotheses accumulate — revert them
151
+
152
+ ## Query Patterns
153
+
154
+ Two filter prefixes for attribute search:
155
+
156
+ | Prefix | Match type | Example |
157
+ |--------|-----------|---------|
158
+ | `attr.<key>=<value>` | Exact match | `attr.debug.hypothesis=cache-miss` |
159
+ | `attrContains.<key>=<substring>` | Case-insensitive substring | `attrContains.ai.prompt.messages=hello world` |
160
+
161
+ ```bash
162
+ curl http://127.0.0.1:27686/api/health
163
+ curl http://127.0.0.1:27686/api/services
164
+
165
+ # Trace search
166
+ curl "http://127.0.0.1:27686/api/traces/search?service=<service>&operation=<text>&attr.debug.session=<session>"
167
+
168
+ # Span search (supports traceId to scope to one trace)
169
+ curl "http://127.0.0.1:27686/api/spans/search?service=<service>&traceId=<trace-id>&attr.debug.hypothesis=<id>"
170
+ curl "http://127.0.0.1:27686/api/spans/search?service=<service>&attrContains.ai.prompt.messages=<phrase>"
171
+
172
+ # Log search (supports severity filter, case-insensitive body search)
173
+ curl "http://127.0.0.1:27686/api/logs/search?service=<service>&severity=ERROR&body=<text>"
174
+ curl "http://127.0.0.1:27686/api/logs/search?service=<service>&attrContains.debug.label=<substring>"
175
+
176
+ # AI call search (compact summaries with previews)
177
+ curl "http://127.0.0.1:27686/api/ai/calls?model=gpt-5.4&sessionId=<session>"
178
+ curl "http://127.0.0.1:27686/api/ai/calls?text=<phrase>&status=error"
179
+
180
+ # AI call detail (full prompt/response payloads)
181
+ curl "http://127.0.0.1:27686/api/ai/calls/<span-id>"
182
+
183
+ # AI stats
184
+ curl "http://127.0.0.1:27686/api/ai/stats?groupBy=model&agg=total_input_tokens"
185
+
186
+ curl http://127.0.0.1:27686/openapi.json
187
+ ```
188
+
189
+ List and search responses include `meta.nextCursor` when more data is available.
190
+
191
+ Motel gives you trace-correlated data — you can see which span a debug log belongs to, the parent operation, timing, and the full trace tree. Use `GET /api/traces/<trace-id>/spans` and `GET /api/spans/<span-id>/logs` to navigate the correlation.
192
+
193
+ For AI/LLM calls, use `/api/ai/calls` for compact searchable summaries (with prompt/response previews and token usage), and `/api/ai/calls/<span-id>` for full payloads.
194
+
195
+ ## Effect
196
+
197
+ If the target repo uses Effect, read `references/effect.md` before changing runtime wiring or adding instrumentation.
198
+
199
+ ## Cleanup
200
+
201
+ Use the bundled script at `scripts/clear-motel-debug.ts` when you want deterministic cleanup. It removes every block between `#region motel debug` and `#endregion motel debug` in JS/TS files and fails on unmatched markers.
202
+
203
+ If you cannot run the script, delete every marked block manually and then grep for `#region motel debug` to confirm none remain.