The observation log had accumulated 46 open entries against a last review of 2026-08-14. Seven of them target skills tracked in this repository and were verified still-unapplied against the current files. `ci-check` gains four things it was missing. It never mentioned `cargo audit`, which CI runs pinned at 0.22.1 in `tauri-build` — the one gate that turns red with zero local changes, because an upstream advisory breaks a branch that was clean yesterday, and the one a hand-written mirror silently drops because no edit provokes it. It never mentioned that `release.yml` is tag-triggered and PR-ungated, so a smoke/sign/strip step added only there first executes on the release; #1376 shipped a smoke harness whose own bug then blocked a release, and #1378 fixed it structurally by extracting `Server/scripts/docker-smoke.sh` for both workflows. And it had no guidance for reading a red check at all: a new section adds causality-before-forensics triage (diff the changed-file set against the failing job's input surface before opening a log — a workflow-only diff cannot cause a Go goroutine leak), the lockfile-fork diagnosis for dependency bumps (a 1 → 2 entry-count transition means the update forked the dependency and revoked the features it was borrowing, so aligning versions is the fix, not setting the feature the new copy demands), and the known-flake table promoted to a signature-to-recovery index, now including the apt-mirror hang that cancels `tauri-build` by timeout. The baseline rule that came with the triage section needed adjusting rather than transcribing. Its source observation recorded `golangci-lint`'s known-red complexity baseline as 23 cyclop / 6 dupl / 21 funlen / 12 nestif; #1389 cleared that to zero, so quoting those numbers would have taught the reader to excuse a failure that is now genuinely theirs. The rule is recorded without them, stating that the repo currently carries no known-red gate and what to do if one is ever reintroduced. `protocol-change` claimed the schema is the source of truth without saying what it covers. It holds message-type names only, so a payload-field change touches the Go command/message files, the client types and `docs/protocol.md` and never the schema — routing one through the regenerate cycle is wasted work. A table splits the three cases, with the relay-handler caveat: a server that re-serialises drops unknown fields, so a forwarded field is not backward compatible with older servers. `task-observer`'s numbering discipline treated collisions as a parallel-human accident. They are structural in fan-out workflows, because a dispatched subagent has the skill active in its own context and writes to the same log. `bughunt-run` covered findings blocked by a circuit breaker but not findings that went stale: a later hunt routinely fixes a blocked finding as a side effect of an overlapping sibling, and a saved debris patch stops applying once a refactor rewrites its files. Of 6 findings blocked on 2026-08-14, 2 were already fixed 5 days later. `docs/contributing.md` gains the commit-body convention that was being followed without being written down anywhere — reasoning over diff-restatement, a `Verified:` paragraph proving both directions, and an explicit `Not included:` line. That last one is what keeps adjacent scope from becoming either silent drift or an unnecessary blocking question. Verified: each edit was checked against the live file before applying, which changed two outcomes. Observation 50 (make the hunt's stop rule measure coverage, not just quietness) is already implemented — `bughunt-run` documents `coverage + dry is the real stop`, `stalledCoverage` and `coverage.uncoveredAtStop`, landed by #1399 — so it is marked actioned rather than re-applied. Observation 42 looked covered by the same grep and was not: the existing text handles breaker-blocked findings, a different case from a finding a sibling fix already closed. Confirmed absent before editing: `cargo audit` and `release.yml` in ci-check, `payload` in protocol-change, `subagent` in task-observer. `npm run check:hygiene` passes (prettier clean on all five files); `npm run check:docs` passes. Not included: the 21 open observations targeting `superpowers:*` plugin skills, which live in a versioned plugin cache and are overwritten on update — they are being routed to a separate user-owned extras skill outside this repository. The 6 targeting `graphify` are deferred pending a decision on whether that skill is still in use here now that #1413 removed its repository integration. The 5 new-skill candidates are noted only; a review is not permitted to create skills. Refs skill-observations #25, #35, #39, #41, #42, #43, #45, #58, #59, #63
OwnCord
A self-hosted chat app I build for me and my friends — text channels, voice and video, and a server you actually own.
Alpha, and a hobby project. This is something I build for fun and run for a small group of friends. It isn't a product, there's no support, and it isn't production-ready. Expect rough edges, rapid changes, and the occasional breaking change.
Don't use it for anything sensitive.
It's a Go server plus a Tauri desktop client: real-time messaging, voice/video via LiveKit, file sharing, and a web admin panel. Run the server on a spare box or a VPS, hand your friends an invite code, and that's the whole thing.
How it's built
Most of the implementation is generated with AI tooling, with quality held up by automated checks — CI, tests, linting — and by me and my friends actually using it. That keeps iteration fast, and it also means behaviour can change quickly between releases.
What works right now
| Area | Status |
|---|---|
| Core chat flow | Working in alpha |
| Voice/video | Working in alpha |
| Admin panel | Working in alpha |
| Security hardening | Ongoing review passes; findings and their statuses are tracked in the dated audits in docs/ (see the Docs Index below) |
Platform Support (Current Releases)
| Component | Windows x64 | Linux x64 | Linux ARM64 |
|---|---|---|---|
| Server binary | Yes | Yes | Not yet |
| Desktop client | Yes (NSIS installer) | Yes (AppImage, .deb) | Yes (AppImage, .deb) |
| Docker server | N/A | Build from source (compose) | Not yet |
Start Here
- New user quick path: docs/quick-start.md
- Linux Docker deployment: docs/deployment.md
- Remote access without router config: docs/tailscale.md
- Manual router/network setup: docs/port-forwarding.md
Quick Start
Option A: Prebuilt binaries
- Download assets from Releases (binaries, checksums, signatures, and a full source snapshot per release).
- Run the server binary:
- Windows:
chatserver.exe - Linux:
./chatserver
- Windows:
- Open
https://localhost:8443/adminand complete the setup wizard — it creates your Owner account and configures the server for you (settings are saved toconfig.yamlautomatically). - Generate invite codes in the admin panel and share them with friends.
Option B: Docker (Linux server)
cd Server
cp .env.example .env
cp livekit.yaml.example livekit.yaml
# Edit both files before starting
docker compose up -d
See the full setup guide in docs/deployment.md.
The client uses TOFU (Trust On First Use) for self-signed certificates: it prompts once, then pins the certificate for future connections.
What OwnCord Already Has
- Real-time channels and direct messages over WebSocket
- Voice/video channels via LiveKit — the LiveKit server binary is downloaded and managed for you
- Invite-only registration and role-based permissions
- Web admin panel with logs, backups, and update tooling
- File uploads and inline media rendering
- TOTP 2FA support and API rate limiting
- Desktop client auto-update with signature verification
- WASM plugin system (slash commands; sandboxed, default-disabled — enable via
plugins.enabledand build with-tags wazero) - GIF picker — off by default; each server supplies its own
Klipy key via
gif.api_key(setup)
See deeper feature and architecture docs in docs/architecture/ and docs/protocol.md.
Architecture
Two main components:
- Go server (REST API, WebSocket hub, SQLite, admin panel)
- Tauri v2 desktop client (Rust backend + TypeScript frontend)
+---------------------+ +---------------------+
| OwnCord Client | | OwnCord Server |
| (Tauri v2) | | (Go) |
| | | |
| +---------------+ | WSS | +---------------+ |
| | Chat UI |--+------->| | WebSocket Hub| |
| +---------------+ | | +---------------+ |
| +---------------+ | HTTPS | +---------------+ |
| | REST Client |--+------->| | REST API | |
| +---------------+ | | +---------------+ |
| +---------------+ | LiveKit | +---------------+ |
| | Voice/Video |--+------->| | LiveKit SFU | |
| +---------------+ | | +---------------+ |
+---------------------+ | +---------------+ |
| | SQLite DB | |
| +---------------+ |
+---------------------+
Build and Test
Prerequisites
- Go 1.26+
- Node.js 24+ (see
Client/.nvmrc) - Rust stable (client builds)
Build from source
# Server (Windows)
cd Server
go build -o chatserver.exe -ldflags "-s -w -X main.version=1.2.0-alpha.3" .
# Server (Linux)
cd Server
CGO_ENABLED=0 go build -o chatserver -ldflags "-s -w -X main.version=1.2.0-alpha.3" .
# Client
cd Client
npm install
npm run tauri build
Core verification commands
Everything CI gates on, from the repository root:
npm run check # server + client + Rust
npm run check:server # or one stack at a time
node scripts/run.mjs --list # exactly what each task runs, and where
Or run the stacks directly — the facade is a convenience, not the only path, and server work needs no Node at all:
# Server
cd Server
go test ./...
# Client
cd Client
npm run typecheck
npm run lint
npm test
For the full command set, use docs/contributing.md.
Configuration
On first run, the server generates config.yaml and a local data/ directory:
data/
├── chatserver.db
├── certs/
├── uploads/
└── backups/
Key options include TLS mode, upload limits, LiveKit settings, and admin CIDR restrictions. See docs/server-configuration.md.
Security and Vulnerability Reporting
- For vulnerabilities, use GitHub Security Advisories (private disclosure flow).
- Do not open public issues for security bugs.
- Read full policy and hardening notes in docs/security.md.
Update Signing Notes (Maintainers)
Client and server update signing keys are intentionally separate.
Required Actions secrets for release signing:
TAURI_SIGNING_PRIVATE_KEYTAURI_SIGNING_PRIVATE_KEY_PASSWORDSERVER_UPDATE_SIGNING_PRIVATE_KEYSERVER_UPDATE_SIGNING_PRIVATE_KEY_PASSWORD
When rotating the server updater key, update Server/updater/server_update_public_key.txt and use staged rollover for live fleets.
Docs Index
docs/README.md is the complete index — every document in
docs/, grouped by whether it is guidance, a reference contract, a dated audit,
or a plan. The most-used entries:
- docs/quick-start.md — get a server running
- docs/deployment.md — production deployment
- docs/contributing.md — setup, branch model, how to run the checks CI runs
- docs/security.md — reporting a vulnerability
- docs/architecture/ — system blueprints (diagrams + flows)
- docs/architecture/ux/ — client UX specification (target-state flows, per-view states, event→reaction maps)
- docs/api.md, docs/protocol.md, docs/schema.md, docs/server-configuration.md — reference contracts
- docs/plans/README.md — plan index; records each plan's state and is the authority over a plan's own header
Audits are dated snapshots and are not maintained after the fact — read them as history. docs/README.md lists all nine, newest first.
Contributing
- Create a branch from
dev(the active development branch). - Keep changes focused and tested.
- Open a PR targeting
dev—devis merged tomainfor releases.
See docs/contributing.md for the full process.
License
AGPL-3.0


