Skip to content

feat(api): read-only JSON API for automation and AI agents - #67

Merged
thiagoesteves merged 2 commits into
mainfrom
thiagoesteves/json-api
Jul 20, 2026
Merged

feat(api): read-only JSON API for automation and AI agents#67
thiagoesteves merged 2 commits into
mainfrom
thiagoesteves/json-api

Conversation

@thiagoesteves

Copy link
Copy Markdown
Owner

What

Adds Observer.Web.Router.observer_api/2: an opt-in, read-only JSON API over the same collectors the dashboard renders, aimed at automation and AI agents (the direction observer_cli 2.0 just validated with its JSON output).

  • GET / - endpoints + visible nodes
  • GET /system?node= - runtime info, VM limits, allocator utilization
  • GET /processes?node=&sort_by=reductions|memory|message_queue_len&limit= - etop-style ranking (limit capped at 1000)
  • GET /ets?node= - table metadata (size, memory, owner, protection)
  • GET /apps?node= - running applications

The mount is deliberately separate from the dashboard (no session/LiveView) so hosts place it inside their own API auth pipeline:

scope "/" do
  pipe_through [:api, :my_api_auth]
  observer_api "/observer/api"
end

Security notes

  • Access resolves through the same Observer.Web.Resolver behaviour; {:forbidden, _} renders a 403. All endpoints are read-only, so :all and :read_only are both accepted.
  • ?node= values only resolve against currently known cluster nodes - crafted values never reach RPC and never allocate atoms; sort/limit params are whitelisted and bounded.
  • Pids/references are serialized via inspect; unreachable nodes render a 502 instead of crashing.

Why

Part of the roadmap derived from comparing ObserverWeb against OTP observer, observer_cli and Phoenix LiveDashboard: a machine-readable surface makes ObserverWeb the richest BEAM data source an agent can query, reusing collectors that already exist.

Risk assessment

  • Impact: additive opt-in macro; hosts that don't mount it see zero change.
  • Blast radius: new Observer.Web.Api plug + router macro; collectors and dashboard untouched.
  • Regression risk: low - suite green (405 tests, 96.0% coverage), credo/sobelow/dialyzer/format clean.
  • Rollback plan: revert the commit; hosts drop the observer_api mount.

Checklist

  • mix test green (405 tests)
  • mix coveralls 96.0% (threshold 95%)
  • mix credo --strict, mix sobelow, mix dialyzer, mix format --check-formatted clean
  • Small focused diff, no leftover debug output

🤖 Generated with Claude Code

Add Observer.Web.Router.observer_api/2, an opt-in mount exposing the
existing collectors as bounded, read-only JSON endpoints: /system
(runtime info, limits, allocators), /processes (etop-style ranking
with sort/limit), /ets (table metadata) and /apps, plus an index
listing endpoints and visible nodes.

The mount is separate from the dashboard so hosts place it inside
their own API authentication pipeline. Access resolves through the
same Observer.Web.Resolver behaviour ({:forbidden, _} renders 403).
Node parameters only resolve against currently known cluster nodes -
crafted values never reach RPC or allocate atoms - and process/table
identifiers are serialized with inspect.

Risk assessment:
- Impact: additive opt-in macro; hosts that do not mount observer_api
  see zero change.
- Blast radius: new Observer.Web.Api plug and router macro; collectors
  and dashboard untouched.
- Regression risk: low - read-only endpoints over existing context
  modules, params whitelisted/bounded; suite green (405 tests, 96.0%
  coverage).
- Rollback plan: revert the commit; hosts drop the observer_api mount.
@thiagoesteves
thiagoesteves force-pushed the thiagoesteves/json-api branch from 32f4326 to 13147ff Compare July 20, 2026 12:25
Observer.Web.Api's send_json/3 is a bare Plug that calls send_resp/2 directly,
a pattern Sobelow can't distinguish from an HTML XSS sink even though the
content-type is always explicit JSON. Mark it skipped and pass --skip in both
the sobelow CI step and the local test.ci alias so the annotation is honored.

Also wires observer_api into dev.exs behind a bearer-token pipeline so the
new endpoints can be exercised locally.
@thiagoesteves thiagoesteves moved this to In Progress in Observer Web Jul 20, 2026
@thiagoesteves
thiagoesteves merged commit 7b37afa into main Jul 20, 2026
3 checks passed
@thiagoesteves
thiagoesteves deleted the thiagoesteves/json-api branch July 20, 2026 13:26
@github-project-automation github-project-automation Bot moved this from In Progress to Done in Observer Web Jul 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant