- Rust 49%
- JavaScript 24.7%
- HTML 9.9%
- Shell 7.5%
- CSS 6.2%
- Other 2.7%
Phase 4 closes (Phase 5 = bundled mycelium subprocess + server `auto:` bind mode). Refs: #1 |
||
|---|---|---|
| .cargo | ||
| crates | ||
| decisions | ||
| deploy | ||
| docs | ||
| limitations | ||
| plan | ||
| scripts | ||
| sessions | ||
| .gitignore | ||
| apikeys.db | ||
| buildenv.sh | ||
| Cargo.toml | ||
| CLAUDE.md | ||
| IMPLEMENTATION_SUMMARY.md | ||
| LICENSE | ||
| Makefile | ||
| pipeline-config.yaml | ||
| PROJECT_STRUCTURE.md | ||
| prompt.md | ||
| README.md | ||
| TECH_SPEC.md | ||
hero_assistance
A markdown-centric team collaboration platform built as a first-class Hero OS service. Channels and threads, real-time chat with reactions, @mentions, file attachments, full-text search, collaborative canvases (CRDT via Yjs/yrs), and voice huddles via LiveKit.
Service model: hero_assistance_server exposes JSON-RPC over a Unix
domain socket (~/hero/var/sockets/hero_assistance/rpc.sock).
hero_assistance_ui serves the HTML/JS frontend and proxies
browser-originated RPC/WS (~/hero/var/sockets/hero_assistance/ui.sock).
Both are run by hero_proc. Typical operator deploys them behind
hero_proxy → hero_router for identity injection and TLS.
Quick start (local development)
make devstart # wipes DB + starts in dev mode + seeds 4 test users
That target:
- Stops any running hero_assistance service.
- Wipes
~/hero/var/data/hero_assistance/collab.db*and attachment files. cargo install --releaseinto~/hero/bin.hero_assistance --start --auth-mode=dev --seed-dev-users— registers both services under hero_proc, dev-mode identity, and seeds a canonical 4-user fixture (Alice=id 1, Bob=2, Carol=3, Dave=4) + one "General" workspace + one#generalchannel with all 4 users as members. Alice is the channel admin.
Then open http://localhost:9988/hero_assistance/ui — that's
hero_router's port, which forwards to hero_assistance_ui's socket.
The user picker appears; pick any of the 4 seeded users. Open
another tab (or incognito) and pick a different user to simulate
multi-user chat.
If you want a non-destructive start (keep existing DB, no seed):
make install # release build + install
hero_assistance --start --auth-mode=dev # dev mode, no seed
# Or proxy mode (default) for testing real auth:
hero_assistance --start
make devstart is destructive — intended for iterative dev
where starting from a known clean slate every session is the point.
Do not run it against a DB you care about.
Why --auth-mode=dev on the CLI instead of an env var? hero_proc
spawns its children with a clean env — anything you export in the
parent shell never reaches hero_assistance_server. CLI flags are the
supported knob that survives the hero_proc spawn boundary. Env vars
still work when you launch the binaries directly (handy for tests),
but under hero_proc --start only flags propagate. See
deploy/README.md for the full flag ↔ env ↔ precedence table.
Prerequisites
- Rust 1.80+ with the
2024edition (rustup update stable) - SQLite 3 installed (bundled via
rusqlitefeature, so system SQLite isn't strictly required) - A running
hero_proc+hero_router+ optionalhero_proxy(install from their respective Forge repos) - Optional: LiveKit server for huddles — see
deploy/README.md
Auth modes
| Mode | Behavior |
|---|---|
proxy (default) |
Expect X-Hero-User from hero_proxy. Reject unauthenticated RPCs. |
dev |
User picker fallback, no headers required. Logs a prominent warning at startup. Never ship to production. |
Three ways to set the mode, most-specific wins:
hero_assistance_server --auth-mode=<dev\|proxy>— direct-launch flag.hero_assistance --start --auth-mode=<dev\|proxy>— CLI wrapper; forwards tohero_assistance_servervia the hero_proc action spec AND setsCOLLAB_AUTH_MODEon thehero_assistance_uiaction. Both processes agree.COLLAB_AUTH_MODEenv var — fallback for tests and direct- binary launches. Ignored under hero_proc supervision (clean env).
Running the two binaries by hand (bypassing hero_proc), export
COLLAB_AUTH_MODE=dev once and launch both; clap's env fallback
picks it up transparently. If you mix the two paths (CLI flag on
server, env on UI) you can drift — hero_assistance --start --auth-mode=X
keeps them in sync.
Architecture (5 crates)
crates/
├── hero_assistance_server/ JSON-RPC service on rpc.sock (SQLite-backed)
├── hero_assistance_ui/ axum HTTP + WS relay serving static assets on ui.sock
├── hero_assistance_sdk/ Auto-generated typed Rust client (via openrpc_client!)
├── hero_assistance/ CLI (`hero_assistance --start`, --stop, --status)
└── hero_assistance_examples/ Runnable examples: basic_usage, health, load_test
Data layout:
~/hero/var/data/hero_assistance/collab.db— SQLite DB (WAL mode)~/hero/var/data/hero_assistance/files/— attachment blobs, namespaced by workspace then attachment id~/hero/var/logs/core/YYYY/DOY/logs.sqlite— structured logs viahero_proc's log aggregator
Wire protocol: JSON-RPC 2.0 over HTTP/1.1 over Unix Domain Socket.
The openrpc.json spec at crates/hero_assistance_server/openrpc.json
is the source of truth; hero_assistance_sdk is generated from it via the
openrpc_client! macro. 80+ methods, stable error codes per
src/rpc_error.rs.
Key features
- Workspaces / channels / DMs — standard Slack topology, with public + private channels and direct-message kinds.
- Messages — send, edit, delete (soft), pin, full-text search (SQLite FTS5), attachments with per-user ownership (B5), and threaded replies.
- Reactions — atomic
message.toggle_reactreturning{action: "added"|"removed"}; no reactions on tombstoned messages (H6). - @mentions — parsed on send, delivered via WS push
(
mention.created) and surfaced as OS-level browser notifications when the tab is backgrounded (H10). - Canvases — Yjs/yrs CRDT-backed collaborative docs with Tiptap editor; multi-client real-time sync over binary WS; role-gated (owner, editor, viewer); viewer mode enforces read-only in-browser (Phase 4-EXT 1A).
- Voice huddles — LiveKit SFU integration, JWTs signed by
livekit.rs::generate_token.deploy/docker-compose.ymlstands up LiveKit + Redis for a self-hosted deployment. - Rate limiting — 60 RPC/min global + 10/min on
message.sendper authenticated caller, two-phase check-then-commit; bypasses dev-mode unauthenticated calls. - Observability —
rpc.dispatchtracing events on every call, atomic counters exposed viasystem.metrics,/healthshows active WS connection count. - Federation —
collab.users.availableunions local users with hero_proxy'susers.list; UI invite/DM pickers see system-wide identities (K-4-2).
Testing
# Unit tests (rate_limit, rpc_error, validation, activity)
cargo test -p hero_assistance_server --bin hero_assistance_server
# Integration tests (spawn real server per test, ephemeral sockets)
cargo test -p hero_assistance_server --test integration
# Full workspace
cargo test --workspace
As of the post-Plan-A P0/P1 sweep: 40 unit + 30 integration tests, with specific coverage of the ship-blocker regressions surfaced during hardening (B1–B6), the 6.1c typed-error wire codes, pin/unpin
- require_caller + claim_federated from the external-audit P0/P1 batch, and the channel.create auto-member fix.
Operations
Operational docs:
deploy/README.md— LiveKit setup, env vars, ports.docs/BACKUP.md— online DB backup + restore; retention hints.plan/known-issues.md— tracked issues deferred from Plan A, organized by phase of origin (H-3-, K-4-, K-6-, P-A-, P-B-, P-C-, P-D-*).
Metrics to watch in production:
/healthonui.sock:active_ws_connections(should be >0 when users are connected; rebooting the UI pulls it to 0 and it climbs back as clients reconnect).system.metricsRPC:rpc_calls_total,rpc_errors_total,avg_latency_ms,workspaces,users,channels,messages.- Log stream (
hero_proc'slogs.sqlite): greprpc.dispatchfor per-call timing + error codes; greptask=huddle_reaperortask=attachment_cleanupfor background-task activity; greptrace_id=to correlate user-reported issues with sanitized-32603 Internalresponses.
Browser support
Minimum: Chrome/Edge 100+, Firefox 100+, Safari 15.4+.
See crates/hero_assistance_ui/BROWSER_SUPPORT.md for the full API
coverage rationale.
Plan + roadmap
The per-phase execution history lives in plan/:
phase-6x-plan-a.md— the consolidated backlog executed most recently (Sprint 1–3 + 6.1c + P2)slack-feature-parity.md— the original 7-phase planfeature-huddles.md,feature-huddles-v2.md,feature-voice-to-canvas.md— feature-specific design docsknown-issues.md— deferred items
Commit messages tag their plan step (Phase-6x Plan A / Phase B,
etc.) so git log reads as a timeline of what was shipped when.
Contributing
- Follow the established commit-message format: one header line
describing the change + a body explaining why, with references
to the plan step or known-issue ID. Use
Co-Authored-By:for pair / AI-assisted work. - New handlers return
RpcResult<Value>, notanyhow::Result— seesrc/rpc_error.rsfor the typed-error contract. - Input validation uses the typed newtype pattern (
Name,Email,ChannelName,MessageContent, etc.) fromsrc/validation.rs. Handlers callparse_input::<T>(params)to deserialize + validate. - Run
cargo testand the Python backend smoke before committing; run the Playwright browser smoke when touchingchat-app.jsorcanvas-app.js.
License
See Cargo.toml.