Monoscope: self-hosted observability with telemetry that stays in your own S3 buckets
Monoscope lets you ingest and explore your logs, traces and metrics. We store these in S3 compatible buckets. Query in natural language via LLMs.
At a glance
- What is it?
- Monoscope is an AGPL-3.0 observability platform written in Haskell that ingests logs, traces and metrics through OpenTelemetry, keeps the data in S3-compatible storage you own, and layers natural-language querying and scheduled AI agents on top. The docker-compose quick start is three commands; the real work is the S3 and Kafka configuration the README leaves to you.
- Who is it for?
- Adopt Monoscope if you already run OpenTelemetry collectors and want telemetry to land in an S3 bucket you control, and if you are willing to operate TimescaleDB, Kafka and the S3 wiring yourself. Skip it if you want a managed backend with no infrastructure work, or if you need the Slack and PagerDuty alert channels, which the README lists only under the cloud offering.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 5 days ago.
- What is it written in?
- Mainly Haskell, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 25, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The bill you are trying to avoid, and who Monoscope is for
Observability vendors price on ingest and retention, so the cost of keeping a year of logs grows with the size of the logs, not with how often anyone reads them. Monoscope attacks that directly: the README states it stores telemetry in S3-compatible buckets, and both the cloud and self-hosted options are described as bring-your-own-bucket, with the line "your data stays yours." Object storage is cheap per gigabyte and does not care how long the data sits there, which is the whole argument for putting years of logs in it.
The audience is narrower than the tagline suggests. This is for a team that already emits OpenTelemetry data, has an S3 bucket, and has someone who can run a database and a message broker. The README advertises 750+ integrations out of the box, which in practice means it accepts standard OTLP traffic rather than shipping 750 bespoke connectors. If your stack does not speak OpenTelemetry and you are not prepared to add instrumentation, the ingestion path is closed to you. The repository is Haskell, which matters less for operators than for contributors: the Dockerfile builds from a pre-built dependencies image, so you are not compiling GHC on your laptop unless you choose to.
What actually runs: OTLP in, TimescaleDB and S3 behind, LLM on top
The docker-compose.yml shows two services. The application container listens on 8080 for the HTTP API and 4317 for gRPC, and 4317 is the standard OpenTelemetry OTLP port, so instrumented apps point their exporter at it. The second service is timescale/timescaledb-ha:pg18-all, started with shared_preload_libraries set to 'pg_stat_statements,timescaledb' and a 200-connection ceiling. TimescaleDB is a PostgreSQL extension for time-series data, and its presence tells you the query path is relational and SQL-shaped rather than a custom columnar store.
S3 is the long-term home, and the README is explicit that the buckets are yours in both deployment modes. The .env.example file hints at the rest of the pipeline: REQUEST_PUBSUB_TOPICS names a topic, ENABLE_PUBSUB_SERVICE toggles the subscriber, and the Live Tail comment explains that streaming "works with or without Kafka." When KAFKA_BROKERS is set, live tail rides a topic named live_tail; the comment recommends creating it with short retention. That is a deliberate design choice worth noticing: the real-time path is decoupled from the durable write path, so a slow consumer cannot stall ingestion.
The natural-language layer sits above all of this. Monoscope exposes a Model Context Protocol server at /api/v1/mcp, and the README says every public REST endpoint is auto-registered as a verb-first tool such as list_monitors or search_events, with composite tools like search_events_nl that turns a natural-language question into KQL. Querying with an LLM is therefore a translation step into a query language, not a separate retrieval engine.
Installing Monoscope with docker-compose and sending a first event
The README's quick start is deliberately short. Clone the repository, change into it, and bring the stack up.
git clone https://github.com/monoscope-tech/monoscope.git
cd monoscope
docker-compose upAfter the containers start, the README says to visit http://localhost:8080 and log in with the default credentials admin/changeme. Those values come from BASIC_AUTH_USERNAME and BASIC_AUTH_PASSWORD in the compose file and .env.example, so change them before the port is reachable from anywhere but your machine.
The CLI is a separate install, fetched with a shell script. The README shows the two commands needed to authenticate and then push a single event into the pipeline.
curl https://monoscope.tech/install.sh | sh
monoscope auth login
monoscope send-event -m "Hello from Monoscope"The expected result is that the message appears in the dashboard. For volume rather than a single line, the README offers a generator that emits traces at a fixed rate.
monoscope telemetrygen --kind=trace --rate=5 --count=50If you would rather instrument a real application, the README gives per-language snippets. The Python path installs the OpenTelemetry distribution and bootstrap, then runs the app under the auto-instrumentation wrapper pointed at the local collector port.
pip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap -a install
OTEL_SERVICE_NAME="my-app" \
OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4317" \
opentelemetry-instrument python myapp.pyThe endpoint matches the gRPC port published by the compose file, so no extra collector is required for a first test. What you should see is a new service named my-app appear alongside the events you sent from the CLI.
The configuration the quick start does not cover
Three commands get a working demo. They do not get a working deployment, and the gap is the part worth planning for. The compose file sets MIGRATE_AND_INITIALIZE_ON_START=True, which means schema migrations run when the application boots. That is convenient on a laptop and risky against a production database, because a failed migration is now a failed start.
The .env.example ships a placeholder API_KEY_ENCRYPTION_SECRET_KEY of monoscope123456monoscope12345678. It is a literal string in a public repository. Anything encrypted with it, including stored API keys, should be considered readable by anyone who has seen this file, so rotate it before you store a real key.
The file also documents a failure mode that is easy to miss: an invalid WhatsApp monitor template SID prevents startup. A malformed optional value in an environment file can therefore stop the service from booting at all. The Slack variables (SLACK_CLIENT_ID, SLACK_CLIENT_SECRET, SLACK_SIGNING_SECRET, SLACK_APP_ID) are present, but the README's comparison table lists Slack and PagerDuty alert channels under the cloud column and only "basic email" under self-hosted, so do not assume the Slack integration is a supported self-hosted path just because the keys exist.
S3 itself is the largest unstated piece. The README says data lives in S3-compatible buckets, and the compose file does not show the bucket, region or credential variables. You will be filling those in from the documentation site rather than from the quick start.
Where the agentic CLI pipeline is genuinely different
Most observability CLIs print human-readable tables and leave you to parse them. Monoscope's CLI emits a stable JSON envelope per command, and the README documents the shape of each one in a table. facets returns an object keyed by field path with value and count pairs; events search returns events, count, has_more and cursor; issues list returns data plus a pagination object with has_more, total, cursor, page and per_page.
That stability is what makes the chained example work. The README's pipeline pulls the busiest service from facets, extracts one error event ID with --id-only, then asks for the surrounding five minutes with a per-trace summary showing which other services were affected. Each step feeds the next through jq without a custom parser in between.
Setting MONOSCOPE_AGENT_MODE=1, or passing --agent, forces JSON output and disables interactive prompts. The README notes this is auto-detected when CI or CLAUDE_CODE is set. The practical consequence is that a CI job and an AI coding agent get the same machine-readable surface, and neither can accidentally hang on a prompt. The Claude Code skills plugin installs through either the Claude Code plugin marketplace or npx skills add monoscope-tech/skills, which covers agents other than Claude Code.
When Monoscope is the wrong tool
The self-hosted column of the README's own comparison table is the honest summary of the trade-off. Compute is "You manage," auth and SSO is "DIY," and alert channels are "Basic email" against Slack and PagerDuty in the cloud column. If your incident response depends on PagerDuty routing or SSO enforcement, self-hosting Monoscope means either building those integrations or accepting a thinner alerting path. The README does not document rollback for a failed migration, and with MIGRATE_AND_INITIALIZE_ON_START enabled there is no documented procedure for reverting a schema change.
There is also a naming problem that has nothing to do with the software. The related search data around this project is dominated by people looking for something else entirely: the optical instrument, a television product, medical equipment, an Amazon listing. Someone searching for "Monoscope" in a general search engine is usually not looking for an observability platform. That is a discoverability issue for the project, and a reminder that the repository path monoscope-tech/monoscope is the unambiguous identifier.
The last push to the repository was on 2026-08-07, and the most recent release, v0.6.25, carries the same date. The version number itself is the useful signal: at 0.6.x, the project has not declared a 1.0 stability boundary, and the README's roadmap section is referenced in the table of contents but not reproduced in the documentation available here.
How it compares to Grafana Loki and a plain object-store pipeline
The nearest comparison is Grafana Loki, which also stores logs cheaply and indexes labels rather than full text. The difference in approach is where the query engine lives. Loki is a purpose-built log store with its own index format and LogQL as the query surface; Monoscope puts TimescaleDB in front of the data and exposes KQL, with the natural-language path translating a question into that query language through an LLM. If your team already thinks in SQL and wants traces, metrics and logs correlated in one relational model, that is a real difference. If you want a log store that scales on labels alone and nothing else, Loki's narrower design is the point.
The other alternative is assembling the pipeline yourself: an OpenTelemetry Collector writing Parquet to S3, plus a query engine such as DuckDB or Athena on top. That gives you total control over the file format and no application to operate, and it also gives you no dashboards, no monitors, no issue triage and no agents. Monoscope's value is the layer above storage, and the README's feature list (live tail, unified view, session replays, scheduled reports) is what you would otherwise build. Choose the DIY path when the storage format matters more than the interface; choose Monoscope when the interface is the work you want to skip.
Licence, upgrade cost and what to verify
Monoscope is AGPL-3.0. That is a copyleft licence with a network clause: if you modify the software and let users interact with it over a network, the AGPL's source-disclosure obligation is generally understood to apply to your modified version. Running the unmodified container internally is a different situation from forking it and offering it as a service. This is a description of the licence family, not legal advice, and the LICENSE file in the repository is the authority.
The upgrade path is container-based. The compose file pins ghcr.io/monoscope-tech/monoscope:latest, and the README's release list shows a steady cadence through 2026: v0.6.23 on 2026-06-11, v0.6.24 on 2026-06-29, v0.6.25 on 2026-08-07. Pulling latest means you take whatever migration the new image carries, and because MIGRATE_AND_INITIALIZE_ON_START is enabled by default, that migration runs on boot. Pinning a tag instead of latest is the difference between choosing when that happens and finding out.
The dependency surface is the real cost. The Dockerfile installs librdkafka, libgrpc, libpq, libldap, libsasl2 and several compression libraries, which reflects a stack that speaks Kafka, gRPC, PostgreSQL and LDAP. That is a lot of moving parts for a small team, and the pre-built dependencies image exists precisely because building them from scratch is slow. Budget for the operational work, not just the container start.
Editorial conclusion
Adopt Monoscope if you already run OpenTelemetry collectors and want telemetry to land in an S3 bucket you control, and if you are willing to operate TimescaleDB, Kafka and the S3 wiring yourself. Skip it if you want a managed backend with no infrastructure work, or if you need the Slack and PagerDuty alert channels, which the README lists only under the cloud offering. Before committing, verify three things on your own host: that the S3 credentials in your compose file actually write and read objects, that the gRPC port 4317 receives a test span from your collector, and that the default admin/changeme credentials and the placeholder API_KEY_ENCRYPTION_SECRET_KEY have been replaced.
Frequently asked questions
What is Monoscope?
It is an open-source observability platform that ingests logs, traces and metrics and stores them in S3-compatible buckets you own. It adds natural-language querying through LLMs and scheduled AI agents that detect anomalies and email daily or weekly reports.
What is Monoscope?
Monoscope is an AGPL-3.0 project written in Haskell, available as a managed cloud service or self-hosted through docker-compose. In both modes the README states you bring your own S3 buckets.
Is Monoscope a word?
The search data around this name is dominated by the optical instrument and unrelated products, so a general search rarely surfaces the observability project. The unambiguous identifier is the repository path monoscope-tech/monoscope.
What is Monoscope?
It is the open-source observability platform from monoscope-tech that stores telemetry in your own S3 buckets and lets you query it in natural language. The README's quick start brings it up locally with docker-compose up on port 8080.
How does Monoscope compare to a monocular or a telescope?
Those searches refer to optical instruments and have nothing to do with this project. Monoscope in this context is an observability platform for logs, traces and metrics, and its repository path is monoscope-tech/monoscope.
How does Monoscope compare to binoculars?
Binoculars are an optical product and share only the name. The software project described in the README ingests OpenTelemetry data, stores it in S3-compatible buckets, and exposes an MCP server at /api/v1/mcp for tool-based querying.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/monoscope-tech-monoscope)