Open-source project
chattocorp/chatto avatar
chattocorp/chatto

Chatto: a self hosted team chat where the infrastructure is the product

A fully-featured team and group chat application that you can easily selfhost.

2,796 stars126 forksGoAGPL-3.0

At a glance

What is it?
An AGPL chat server written in Go, with event sourcing, an embedded NATS runtime, an identity module growing inside the same repository, and a local stack driven entirely by mise tasks.
Who is it for?
Chatto is not a skin on an existing chat product. The pieces that other projects treat as configuration are implemented here as libraries, including an event sourcing framework, an embedded NATS runtime, data cryptography primitives and an application configuration loader, and the project is candid that all four exist because an identity module needs them.
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 18 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the project claims to be

The repository description is plain: a fully featured team and group chat application that you can easily selfhost. The README widens it to teams and communities, and adds the two facts that matter for a self hosted product, free and easy to self-host, with cloud hosting described as available soon behind a link to chatto.run.

The topic tags describe what the feature set has grown into: chat, communication, gdpr-compliant, privacy-first, screensharing, video-calls and voice-calls. Two of those are claims rather than descriptions, and both are difficult to verify from outside, so they are worth noting as positions the project takes rather than properties you can confirm by reading the source.

What can be confirmed is the surface area. Documentation lives at docs.chatto.run, there is an official community instance at chat.chatto.run, and the repository carries a security policy, a contributing guide, a changelog and a licensing document. The README is not the documentation; it is a pointer plus a description of how the maintainers work on the code, which is unusual and, for this project, the more useful half.

The language is Go, the default branch is main, the licence reported by the repository is AGPL-3.0, and the version line is still in beta at 0.5.0.

Four shared libraries that exist because of identity

The most revealing paragraph in the README is the one about Authling. The repository temporarily incubates the early Authling identity provider module, and Authling is developed and released independently from Chatto, with the intention of moving to its own repository once it no longer needs frequent atomic changes with four specific things.

Those four things are the interesting part, because each one is a library with its own README under `pkg/`: an event sourcing framework, an embedded NATS runtime, data cryptography primitives, and an application configuration loader. That is the actual architecture story of this project. Rather than picking an identity provider off a shelf, the maintainers are building one, and the pieces it needs became shared infrastructure first.

An embedded NATS runtime deserves a note because NATS is normally a separate service you run. Embedding it means a Chatto deployment does not need a message broker alongside it, which removes one of the classic reasons self hosted chat gets abandoned: the number of moving parts. Putting it under `pkg/natsruntime` also means the data layer's behaviour is versioned with the application rather than assumed from whatever broker happens to be nearby.

The other three are equally load bearing. Event sourcing is what lets a message log be replayed and rebuilt. Data cryptography primitives is what lets the server hold content it should not be able to read. An application configuration loader is unglamorous and is the thing every self hosted project gets wrong. Having all four extracted, documented and named as modules tells you the project is being decomposed deliberately, even while it is still assembled.

The last line of that paragraph is a governance signal too: Authling is intended to leave this repository once it stops needing atomic changes. A monorepo with a documented exit plan is a project that knows its current shape is transitional.

The local stack is a mise task graph, not a README of shell commands

Development instructions start with trust, because the repository stores its tasks in mise rather than in a Makefile or a set of npm scripts.

sh
mise trust
mise install
mise setup
(cd authling && mise trust && mise install && mise deps)
mise dev

`mise dev` is the whole local environment in one supervised process group: the Chatto backend, a Vite frontend, Authling as the identity provider, Mailpit for catching verification email, and LiveKit for the voice and video path. Vite reloads frontend changes, and the README is specific that you restart after changing Go code, which is the honest behaviour of a Go server behind a dev supervisor. `mise setup` builds the shared API types, the Lingua package and the Runling package before anything runs.

HTTPS comes from Portless, which provides routes for the browser facing services on a shared port. Inside Conductor the pattern is a per workspace host, so Chatto is at `chatto.<workspace>.localhost:42444`, Authling at `authling.<workspace>.localhost:42444`, Mailpit at `mailpit.<workspace>.localhost:42444`, LiveKit at `livekit.<workspace>.localhost:42444` and Runling at `runling.<workspace>.localhost:42444`. Outside Conductor the same services use a `local` suffix instead. Underneath, the services listen on loopback ports from base port 4000, or from `$CONDUCTOR_PORT` when Conductor is driving.

Getting a first account takes two steps that read like a test fixture and are one: create an account in Authling, read the verification code out of Mailpit, then pick Authling on the Chatto login screen, where Chatto asks for a username at first login. The stack also seeds owner `alice` and member `bob`, both on the development-only password `foobar123`, and the README says in the same sentence that these are for local development only.

State has a defined location and a defined reset. Embedded NATS data lives in `cli/data/nats/`, search data in `cli/data/search/`, and Authling identity data under a Conductor context directory. With the stack stopped you remove `cli/data/` to reset Chatto. There is also a migration note for worktrees holding NATS data in the former `cli/data/jetstream/` path, which points at CONTRIBUTING.md, so the data layout has changed at least once already.

Synthetic test data with a reproducible generator

A separate section covers test data, and the detail level suggests someone has been burned by flaky fixtures. With `mise dev` running, one command populates a server with generated users, rooms and messages.

sh
mise seed -- --seed 42 --users 20 --rooms 5 --messages 200 --thread-replies 40

That is 20 users with generated names and 200 messages across five rooms, where the message total includes the 40 thread replies. Users join different rooms, with joins and some leaves interleaved with the messages so the history looks like real membership churn rather than everyone appearing at once. Sign in as `alice` to browse the result, since generated users have no password.

The reproducibility contract is stated precisely, which is the part that matters for tests. The same seed and counts reproduce the same content under the same generator version, while IDs and timestamps change between runs. So you get stable assertions on text and unstable assertions on identity, which is exactly what you want from a fixture generator.

Two operational warnings come with it. Each run adds data rather than replacing it, and a failed run can leave partial data behind, so the command is not idempotent and not transactional. Adding `--json` prints the generated IDs and text, which is how an end to end test captures what it needs to assert on, and `--help` lists the rest.

The last line is the boundary condition: seeding is available only in development and test builds. That is a deliberate compile time exclusion rather than a runtime check, so a production binary simply does not contain the path. The section points at Synthetic Test Data in CONTRIBUTING.md for end to end use.

Three beta releases in four days, two with breaking changes

The release history is the clearest signal about where this project is. v0.5.0-beta.4 landed on 2026-09-19, v0.5.0-beta.5 on 2026-09-20, and v0.5.0-beta.6 on 2026-09-21, and two of the three carry an explicit breaking changes heading.

beta.4 lists one breaking change on the admin side, batch loading member rows from paginated IDs, which is a backend contract change rather than a user visible one. Its bug fixes are almost entirely frontend texture: aligning the empty Markdown caret in Firefox, keeping ambient notifications silent, making hover feedback instant and animating overlays, opening profiles in the current room sidebar, and refreshing permissions without rebuilding the page. That last one implies permissions are fetched rather than baked into a bundle, which is the right architecture for a system whose permissions just changed.

beta.5 moved outward. It registered an official mobile OAuth client, added an experimental iOS client with native sign-in, unified responsive dialog and sheet presentation, and synced private availability choices across devices. It also fixed OAuth provider popups completing and sessions being preserved on unlink. The combination of an experimental iOS client and a registered official OAuth client in the same week suggests a mobile push that is planned rather than started.

beta.6 brought interaction-scoped message posting as a breaking change on permissions, extracted shared Chatto integration helpers into `@chatto/client`, added bot badges beside account names, and unified message and thread search with automatic reindexing. The last one is quietly significant: two search paths collapsed into one, with reindexing to match, which is the kind of consolidation that is cheap before you have users and expensive after.

Interaction-scoped posting deserves a sentence. It narrows what a bot or integration can do to what the current interaction allows, which is the correct direction for a permissions model and a breaking change to get right before 1.0 rather than after.

A JavaScript side that is nearly as large as the Go side

The root package.json describes itself as a private workspace named chatto-workspace, licensed AGPL-3.0-or-later, using pnpm 11.25.0 with Turborepo for task orchestration. The script list describes the shape of the codebase better than the tree does.

There are build scripts per surface: `build:api-types`, `build:lingua`, `build:chatto-client`, `build:runling`, `build:frontend`, `build:storybook`, and `build:docs`. There are matching check, lint and test scripts for the frontend, Runling and ChattoBot. The aggregate `check`, `lint` and `test` scripts all run with `--concurrency=1`, which is a deliberate choice to serialise the suite rather than fight for cores.

Three of the packages are named in the README with their own scope or licence. `@chatto/client` provides shared request, message, thread, reaction and typing helpers for bot integrations, and beta.6 is where those were extracted into one place. Runling is described as an independent workflow and agent orchestrator under `packages/runling/`, published to npm as `runling`, keeping its own version and MIT licence, and used by the Chatto bot. ChattoBot is a separate private workspace package with a realtime bot and a Runling console.

That is three distinct testing entry points, which the README addresses directly: `mise check-runling`, `mise test-runling` and `mise test-runling-package` verify Runling without running the complete Chatto suite, and `mise check-chattobot` and `mise test-chattobot` do the same for the bot. A project where one suite cannot verify one component is telling you the components are genuinely independent.

The build caching story is documented rather than implied. Library builds use a local `.turbo/cache`, app builds and verification tasks run without Turbo caching, and remote caching and telemetry are disabled by repository configuration. ADR-102 in `docs/adr/` is cited as the record of where those task and cache boundaries come from. Keeping the cache decision in an ADR is what stops it from being relitigated every quarter.

Licensing, examples, and the parts of the tree worth naming

The licence section is layered, and the README points at two files for the exact boundary. Chatto itself is AGPL-3.0-or-later by default. The independently versioned shared framework modules, the standalone frontend, the integration surfaces, the documentation and the examples are Apache-2.0. Runling is MIT.

For a self hosted chat product that split is reasonable and unusual at the same time. The AGPL default covers the server you actually run, and the Apache carve out means a frontend or a library can be reused without the copyleft reaching your own code. Runling going further as MIT makes sense for something published to npm for bot authors. LICENSING.md and REUSE.toml hold the precise boundary, and the presence of both files plus a LICENSES directory and a NOTICE file is the REUSE convention being followed rather than gestured at.

The NOTICE file carries a restriction with no precedent in the licence text itself: the project licences do not grant permission to use the Chatto names or logos as official branding for a fork or modified version. That is a trademark position stated separately from copyright, and it is worth knowing before you plan a white label deployment.

The examples directory is where the deployment story lives: `examples/dockercompose/`, `examples/k8s/`, `examples/k8s-client/` and `examples/runling-bot/`. Kubernetes alongside a plain compose file tells you both a single machine install and a clustered install are supported shapes, and the runling bot example doubles as the integration test described in the README.

The rest of the root is a mix worth noting for anyone deciding what this project is. There is a Go workspace file, `go.work` with its sum, a `.goreleaser.yml` for release binaries, `release-please` config and manifest files for automated versioning, a `knip.json` for dead code detection, a `turbo.json`, a `mise.toml`, a `.mcp.json`, and then five separate agent configuration directories: `.agents/`, `.claude/`, `.codex/`, `.conductor/` and `.opencode/`, alongside AGENTS.md and CLAUDE.md. A project with an agent configuration in five tools is a project where a large share of the code is written by models, which is worth factoring into how you read the roadmap. The repository has 2,796 stars, 126 forks, 208 open issues, is not archived, and was last pushed on 2026-09-24.

Editorial conclusion

Chatto is not a skin on an existing chat product. The pieces that other projects treat as configuration are implemented here as libraries, including an event sourcing framework, an embedded NATS runtime, data cryptography primitives and an application configuration loader, and the project is candid that all four exist because an identity module needs them. That is the shape of a project still climbing towards its final architecture rather than one defending a settled one, and the release line shows it: three beta builds in four days, two of them carrying breaking changes to permissions and admin batch loading. The layered licence is the other thing to read before deploying, since AGPL by default gives way to Apache-2.0 for the framework modules, the frontend and the docs, Runling is MIT, and forks may not use the Chatto name as branding. With 2,796 stars, 126 forks, 208 open issues, a push on 2026-09-24 and a version still at 0.5.0 beta, this is an ambitious project moving quickly in public rather than a stable product with a maintenance tail.

Frequently asked questions

What is Chatto?

A team and community chat application you can self host, written in Go, with a live dashboard, screensharing, voice and video calls through LiveKit, team spaces, and an experimental iOS client. Documentation is at docs.chatto.run, and cloud hosting is described as coming soon.

How do I run Chatto locally?

With mise. Run `mise trust`, `mise install`, `mise setup`, then set up Authling in its own directory with `mise trust`, `mise install` and `mise deps`, and finally `mise dev`. That single command runs the Chatto backend, a Vite frontend, Authling, Mailpit and LiveKit in one supervised process group, with HTTPS routes provided by Portless.

What is Authling and why is it in the Chatto repository?

Authling is an early identity provider module that the repository temporarily incubates. It is developed and released independently and is intended to move to its own repository once it no longer needs frequent atomic changes with the shared event sourcing framework, embedded NATS runtime, data cryptography primitives and application configuration loader.

What licence is Chatto under?

Chatto is AGPL-3.0-or-later by default. The independently versioned shared framework modules, the standalone frontend, integration surfaces, documentation and examples are Apache-2.0, and Runling is MIT. The exact boundary is in LICENSING.md and REUSE.toml, and the NOTICE file adds that the licences do not permit using the Chatto names or logos as official branding for a fork.

How do I generate test data for Chatto?

With `mise seed` while the dev stack is running, for example `mise seed -- --seed 42 --users 20 --rooms 5 --messages 200 --thread-replies 40`. The same seed and counts reproduce the same content under the same generator version, while IDs and timestamps change. Each run adds data, a failed run can leave partial data, `--json` prints generated IDs and text, and seeding exists only in development and test builds.

Is Chatto production ready?

The current version line is 0.5.0 beta, with releases beta.4 through beta.6 published on consecutive days in September 2026 and two of them carrying breaking changes to permissions and admin batch loading. The mobile client is described as experimental, and the repository has 208 open issues. It is moving fast and in public rather than settling.

Official sources

  1. chattocorp/chatto on GitHub
  2. License: AGPL-3.0
  3. Project website
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/chattocorp-chatto.svg)](https://hysenlabs.com/projects/chattocorp-chatto)