Download
Desktop client v0.3.17

Your team's hub. On your own servers.

Chat, threads, video calls, shared documents and an AI assistant — one application your team signs into with your own identity provider, running on hardware you control. No seats to buy, no tenant somewhere else.

4.2 MB · one file, no installer. Other platforms

Chat · one morning in a channel

A bug reported, diagnosed, and written up — without leaving the app

One continuous conversation: the report, a colleague confirming it, the fix worked out in a thread, the call that settled it, and the release note it produced.

# release-2-4 — Northwind Platform Demo

# release-2-4

Cutting 2.4.0 — staging sign-off before Thursday

9

Staging is on 2.4.0-rc3. Uploads over about 40 MB fail at 100% — the progress bar completes, then the document never appears in the folder.

Delivered

2 2 people reacted: looking into it

Kenji Tanaka

Same here. Nothing in the backend log at all, which is the odd part.

Layla Haddad

Power BI — التقارير الكبيرة تفشل منذ أمس.

Translation: Power BI — large reports have been failing since yesterday.

Daniel Okoro

Found it. client_max_body_size is still 32m on the staging proxy. nginx truncates the POST, DRF sees a short body and returns 400 before our view ever runs — so the failure is in the proxy log, not ours. Production is 512m.

Sofia Ferrara

Reproduced with a 47 MB PDF. Same 400, same silence in the app log.

Daniel Okoro

Patching staging now. It only ever affected staging.

Marta Kowalczyk

Let's pin the value in the deploy compose as well, so the two environments can't drift apart again.

Release 2.4 — upload limits

Started by Daniel · 6 min · Screen share · staging nginx config

Agreed on the call: one limit, one place, pinned in the deploy compose. Written up in the release note below.

Seen

is typing

Playing 0 of 0

What the morning produced

The conversation ends as something people can read

Documents, pages and announcements are first-class objects in the same hub, not links to a different product. This is the release note that came out of the thread above, as a reader sees it.

Platform › Release notes Demo
v2.4.0 #release-2.4#infrastructure

Upload limits now live in one place

A 32 MB request-body cap left on the staging proxy was silently truncating large uploads. The value is now pinned in the deploy compose file, identical across environments.

What was happening

nginx cut the request body at 32 MB on staging. The browser finished sending, so the progress bar reached 100%, but Django received a short body and rejected it with a 400 before the upload view ran. Nothing reached the application log, which is why the failure looked like it came from nowhere.

What changed

The limit moved out of the per-host nginx config and into the deploy compose file, where both environments read the same value. Staging and production are now both 512m. The two other ceilings — Django spooling to disk, and the 500 MB client-side guard in the SDK — were already environment-independent and are unchanged.

What to do

Nothing, if you use the hosted upgrade path. If you run your own compose file, copy the CONTENTHUB_MAX_UPLOAD entry from the sample and rebuild the proxy container.

AI assistant

It does the work first, then answers

Ask it something and it does not guess from a training set. It searches your messages, opens your documents, reads the file you attached — and shows you every step it took, how long each one ran, and what it looked at. The answer arrives with its working attached.

Assistant Demo

Assistant

Answers from your hub

Advisory Auto
Where else is an upload limit configured? Staging just truncated a 47 MB file.

Working…

Search messages — client_max_body_size 0.9s
Search the hub — upload limit 1.4s
Read an attached file — nginx.conf 0.7s
Waiting for the model to answer 2.3s

Three places set an upload ceiling. deploy/nginx.conf caps the request body — 32m in the staging block, 512m in production, which is the difference you hit. DATA_UPLOAD_MAX_MEMORY_SIZE in backend/settings.py only decides when Django spools to a temp file, so it will not reject a large upload. The SDK also refuses anything over 500 MB client-side before it starts. Only the nginx value differs between environments.

deploy/nginx.conf#infra · 4 Feb

Playing 0 of 0

Why the steps matter

An assistant that answers instantly is either recalling something generic or making it up. One that takes four seconds and tells you it read nginx.conf is one you can check — and checking is the difference between a useful colleague and a confident stranger.

  • Its own tools, on your data. Searching messages and hub content, reading an attached file, fetching a page through your own metasearch — each one an admin-managed entry in a registry, not a black box
  • Pick who answers. Route automatically, or name a specific agent. An endpoint that starts failing drops out of the picker on its own and comes back when it recovers
  • Two modes. Advisory consults and explains. Builder actually creates sites, lists and pages — and nothing is created until a human approves the plan
  • It remembers, and you can see what. Long-term notes are per person, visible, and deletable by the person they are about
  • It reads what you send it. PDF, Word and text for any model; images for the models that can see

Separate from chat, available inside it

The assistant is its own conversation, with its own history — but the same assistant can be switched on inside any channel or direct message, where it answers with that conversation as its context. Two features, one hub, and your own model endpoints behind both.

Calls & screen sharing

Video that never leaves your network

Calls run through a mediasoup SFU and a coturn TURN server that you deploy alongside everything else. Media is relayed by your own containers, so a call between two people in your office does not transit anyone else's cloud.

  • Group video and audio, with screen sharing per monitor or per window
  • A device check before you join, so the wrong microphone is caught early
  • Calls survive navigation — moving to another channel shrinks the call into a draggable mini-player instead of dropping it
  • Presence flips to in-call automatically, so nobody pings you mid-meeting
  • A short quality rating after each call, kept with the call record
Mixed scripts

A message written in Arabic stays written in Arabic

Teams do not all write in one script, and the awkward case is not a whole message in another language — it is a sentence that mixes them. Both panels below hold the identical string. Only the direction rule differs.

dir="auto" — the browser default

Power BI — التقارير الكبيرة تفشل منذ أمس.

Resolves from the first strong character — the P of “Power” — and lays the whole sentence out left-to-right. The Arabic clause ends up on the wrong side of the product name, and the full stop on the wrong end of the sentence.

Majority script — what ContentHub does

Power BI — التقارير الكبيرة تفشل منذ أمس.

Counts strong characters — 25 right-to-left against 7 left-to-right — and lays the line out the way it was written, reading from the right, with the Latin product name correctly embedded inside it.

Where the rule applies

Direction is decided per block, not per message, so a single reply can hold an English paragraph, an Arabic one and a table without any of them fighting each other.

  • Every paragraph, heading, list and table cell re-detects its own direction
  • Code and command output are pinned left-to-right, so a snippet never mirrors inside a right-to-left reply
  • Quoted replies and forwarded messages keep the direction of what they quote
  • Single newlines stay real line breaks, so a numbered list written in Arabic does not collapse into one run-on paragraph

To be clear about what this is not: the interface itself is English. This is about the text your team writes, which is where mixed scripts actually show up.

The rest of it

Everything a team hub needs, in one deployment

One application, one database, one login. Nothing below is a paid add-on or a third-party service you have to sign up for separately.

  • Search that finds the sentence

    A Meilisearch index over every message you have access to — typo-tolerant, ranked, and scoped to your own channels and conversations.

  • Notifications people keep switched on

    Web push in the browser and email digests for what you missed, both handled by a background worker. The desktop client draws its own notification cards and honours Windows Focus Assist.

  • Documents, pages and lists

    Folders and documents with revision history, editable pages, announcements, and structured lists you can build from a template — all in the same hub as the conversation about them.

  • An assistant that can actually look things up

    It calls tools mid-answer — searching messages, reading a document, fetching a page through your own self-hosted metasearch — and shows each step. Attachments are read too: PDF, Word and text for any model, images for the ones that can see.

  • Your identity provider, not ours

    Sign-in over OpenID Connect, so accounts and group membership stay in the directory you already run. Token auth is there for anything scripted.

  • Presence and read state that stay honest

    Typing indicators, online and away presence, and per-message read receipts arrive over the same WebSocket as the messages, backed by Redis.

Self-hosting

One compose file, and nothing that phones home

Every part of ContentHub runs on your own hardware — including the parts most self-hosted chat tools hand off to a third party, like call routing and search.

Your infrastructure

Clients

Desktop client

Electron

Browser

React + Vite

Edge

Reverse proxy

nginx · TLS

Application

Django + Channels

ASGI · HTTP + WebSocket

Background worker

Celery + beat

State & search

PostgreSQL

messages, docs, users

Redis

presence · sockets · queue

Meilisearch

full-text index

Media

mediasoup SFU

call routing

coturn

TURN / NAT traversal

Signs in against your OpenID Connect provider — accounts never leave your directory.

What you need

  • A host with Docker and Docker Compose
  • A TLS certificate — the browser will not grant camera or microphone access without one
  • A UDP port range open for call media, plus TURN on 3478 and 5349
  • An OpenID Connect provider if you want single sign-on; it ships wired to Authentik

No SaaS in the critical path

Search, presence, push notifications, call signalling and media relay are all services you deploy. Nothing phones home, and there is no vendor who can read your messages — because there is no vendor.

Download

Get the desktop client

A real application rather than a browser tab, and a small one: it renders through the WebView2 runtime Windows already ships with instead of carrying its own copy of Chromium, so the whole download is 4.2 MB. It runs as a single instance, keeps a tray icon, and needs no installer.

  • Windows

    Windows 10 & 11 · 64-bit

    One 4.2 MB .exe — no installer, no admin rights. Uses the WebView2 runtime already on Windows 10 and 11.

    Download
  • macOS

    Apple silicon & Intel

    Already builds in CI. Unsigned and un-notarised, so not published yet.

  • Linux

    AppImage · x86-64

    Already builds in CI, awaiting a tagged release.

  • Android

    Phone & tablet

    Planned. Web push and the responsive layout already work in a mobile browser.

  • iOS

    iPhone & iPad

    Planned. Installs as a home-screen web app in the meantime.

Version 0.3.17 — an early release, still on a 0.x version for a reason. It connects to a hub address set when the build is made; choosing your own hub from the app is on the way, along with unread badges and notification cards. Releases on GitHub.

Builds are not code-signed yet, so Windows will show a SmartScreen prompt the first time — choose More info, then Run anyway.

No client for your platform yet? The hub is a full web application — every feature on this page works in a browser, and installs to your home screen.

The download keeps one fixed filename, with its MD5 published beside it at /download/ContentHub-Native.exe.md5 — check what you downloaded, or poll it to spot a new build.