v1.0
What's Changed
- feat: per-workspace JWT auth for container→host endpoints by @mcdonc in #232
- feat: chat history pagination — load older messages on scroll by @mcdonc in #244
- feat(ws): auto-reconnect WebSocket with exponential backoff by @mcdonc in #247
- perf(e2e): extract API tests to reduce E2E wall time by @mcdonc in #243
- Add workspace-open timing instrumentation by @mcdonc in #249
- fix(terminal): reassemble PTY UTF-8 across read chunks (terminal ghosting) by @runyaga in #250
- Stop pushing :latest tags to GHCR, pin workspace base image by @mcdonc in #257
- Add [skip ci] to automated base image bump commits by @mcdonc in #259
- Bump workspace base image to 2026.06.11-2603487 by @mcdonc in #258
- Run tests automatically on pushes to release branches by @mcdonc in #260
- docs: update ARCHITECTURE.md and HACKING.md to reflect current state by @mcdonc in #263
- fix(build): regenerate web plugin registrant when the plugin set changes by @runyaga in #254
- feat(terminal): ⌘/Ctrl-click terminal paths open in the file viewer by @runyaga in #252
- docs: convert to Zensical docs site by @mcdonc in #266
- feat: add customize/ example for custom host container deployments by @mcdonc in #268
- Update workspace base image: bash shell, remove sudo by @mcdonc in #287
- Fix crun fchownat errors with rootless userns by @mcdonc in #291
- Use tmux as terminal initial command by @mcdonc in #288
- fix(plugins): send workspace JWT to browser-delegate bridge calls by @runyaga in #275
- Bump workspace base image to 2026.06.12-170fe20 by @github-actions[bot] in #292
- fix(workspace): set tmux extended-keys-format to csi-u by @mcdonc in #295
- feat(workspace): add Shut Down Container button by @mcdonc in #305
- feat(workspace): per-user HOME directories with handle-based naming by @mcdonc in #302
- fix(workspace): auto-create handle on workspace connect, not ui_ready by @mcdonc in #309
- Bump workspace base image to 2026.06.12-c965428 by @github-actions[bot] in #308
- fix(devenv): share podman image storage across checkouts by @mcdonc in #311
- chore: stop tracking pubspec.lock by @mcdonc in #312
- feat(terminal): add tmux window management for terminal tabs by @mcdonc in #314
- feat(terminal): shared terminal backend with permission model by @mcdonc in #321
- fix(devenv): guard su/util-linux to Linux-only by @runyaga in #335
- feat(chat): AI agent integration via Pi RPC by @mcdonc in #336
- fix(container): serialize container creation per workspace by @mcdonc in #337
- fix(terminal): shared terminal E2E fixes and state persistence by @mcdonc in #340
- fix(e2e): relax PageUp assertion on Firefox by @mcdonc in #346
- fix(container): populate home with /etc/skel so .bashrc works by @mcdonc in #347
- fix(container): setup-home.sh script with default PS1 by @mcdonc in #348
- feat(container): per-user Pi agent config (#300) by @mcdonc in #349
- fix(terminal): target joiner session in select_window for shared terminals by @mcdonc in #352
- feat(acl): grant collaborators share-terminals permission by @mcdonc in #350
- feat(cli): add ~. escape to disconnect from klangk shell by @mcdonc in #353
- feat(agent): give MrBoops a real home directory with Pi config by @mcdonc in #358
- docs(chat): rewrite chat docs with AI agent section by @mcdonc in #343
- feat(container): restore passwordless sudo for klangk user by @mcdonc in #361
- fix(container): warm userns mapping to avoid 27s first-create delay by @mcdonc in #363
- docs: add invitation and files feature documentation with screenshots by @mcdonc in #366
- docs: clean up features index, getting started, and CLI reference by @mcdonc in #369
- feat(terminal): add KLANGK_DISABLE_TMUX toggle for plain shell by @runyaga in #360
- fix(container): add UTF-8 locale for tmux unicode support by @mcdonc in #372
- Bump workspace base image to 2026.06.16-fc124ea by @github-actions[bot] in #373
- fix(terminal): auto-exit tmux copy mode on scroll to bottom by @mcdonc in #381
- fix(terminal): send Shift+PgUp/PgDn to PTY for tmux scrollback and mouse scroll wheel in klangk shell by @mcdonc in #383
- feat(container): make passwordless sudo configurable via KLANGK_ALLOW_SUDO by @mcdonc in #386
- docs: document password reset token flow and JWT renewal gap by @mcdonc in #394
- fix(api): use explicit resource function for workspace role ACL checks by @mcdonc in #387
- docs: document workspace JWT lifetime limitation and lack of renewal by @mcdonc in #395
- fix(security): restrict CORS origins instead of allowing all by @mcdonc in #391
- feat(plugins): plugin configuration system (#385) by @mcdonc in #401
- feat(container): git credential helper for browser-delegated auth by @mcdonc in #402
- fix(devenv): track devenv.lock to pin nix inputs by @mcdonc in #406
- fix(cli): add retry with backoff for transient HTTP failures (#341) by @mcdonc in #404
- fix(cli): skip broadcast messages while waiting for workspace_ready by @mcdonc in #415
- feat(plugins): lifecycle hooks and flattened tools by @mcdonc in #413
- fix(podman): add 30s timeout to podman subprocess calls by @mcdonc in #416
- feat(bridge): replace bridge token with browser ID by @mcdonc in #417
- feat(terminal): cross-viewport text selection via tmux mouse mode by @mcdonc in #418
- fix(e2e): increase WebSocket timeouts for shared terminal tests by @mcdonc in #424
- fix(ws): stop auto-reconnect after 5 minutes by @mcdonc in #425
- feat(git-credential): GitHub OAuth device flow by @mcdonc in #426
- fix(workspace): add navigation to loading/disconnected screens by @mcdonc in #433
- feat(chat): display user handle instead of email by @mcdonc in #435
- feat(frontend): stale build detection with reload banner by @mcdonc in #434
- fix: plug memory leaks in long-running server processes by @mcdonc in #438
- fix(e2e): raise tab-speed threshold to 3s for CI headroom by @mcdonc in #436
- fix(devenv): stop generating podman storage.conf by @mcdonc in #441
- docs(features): add AI Coding Harnesses chapter by @mcdonc in #445
- chore: remove KLANGK_PODMAN_STORAGE env var by @mcdonc in #443
- fix(podman): raise create/start timeout to 120s by @mcdonc in #446
- cli: rename 'klangk list' to 'klangk ls' by @mcdonc in #448
- fix(chat): read agent identity from DB, not env vars at runtime by @mcdonc in #449
- fix(chat): show handles instead of emails in tab completion and presence by @mcdonc in #450
- fix: clean up sharing data on workspace delete by @mcdonc in #455
- fix: prevent deletion of system agent user by @mcdonc in #457
- Replace aiosqlite with SQLAlchemy async engine for connection pooling by @mcdonc in #458
- fix(chat): show handles instead of emails in presence avatar tooltips by @mcdonc in #466
- fix(agent): detect process death and broadcast disconnect immediately by @mcdonc in #459
- fix(container): set HERDR_SOCKET_PATH to tmpfs for macOS virtiofs compat by @mcdonc in #474
- docs: document packages available in workspace containers by @mcdonc in #476
- feat: default EDITOR to nano in workspace containers by @mcdonc in #479
- fix: stale version banner reload and sizing by @mcdonc in #480
- fix: prevent Firefox WebSocket reconnect throttling by @mcdonc in #483
- fix: graceful handling of expired access and workspace tokens by @mcdonc in #486
- rename test-cli-e2e to test-backend-e2e by @mcdonc in #489
- feat: broadcast workspace token expiry warnings by @mcdonc in #490
- chore: rename CLI command from klangk to klangkc by @mcdonc in #492
- docs: document escape sequence to exit klangkc shell by @mcdonc in #495
- feat(terminal): respawn shell on exit via tmux by @mcdonc in #493
- refactor: extract CLI into standalone package (src/cli) by @mcdonc in #499
- feat: add PyPI publish workflow for CLI by @mcdonc in #500
- chore: add socat to workspace base image by @mcdonc in #503
- Bump workspace base image to 2026.06.18-296cd3e by @github-actions[bot] in #504
- fix: add fallback_version for hatch-vcs by @mcdonc in #519
- feat: SSH agent forwarding over WebSocket for klangkc shell by @mcdonc in #518
- docs: fix SSH agent docs, reorganize features nav by @mcdonc in #522
- fix(e2e): stabilise shared-terminal and PageUp tests under CI load by @mcdonc in #494
- docs: screenshots, CLI updates, hatch-vcs fix by @mcdonc in #523
- fix: remove stale version tags from workspace image builds by @mcdonc in #524
- feat(container): install zsh in base image by @mcdonc in #525
- docs: add workspaces screenshot by @mcdonc in #527
- Bump workspace base image to 2026.06.19-1012c13 by @github-actions[bot] in #528
- fix: add GitHub SSH host keys to workspace base image by @mcdonc in #531
- feat: allow users and admins to change handles by @mcdonc in #529
- Bump workspace base image to 2026.06.19-2b69622 by @github-actions[bot] in #532
- fix(agent): rekey sessions by workspace ID to survive container restarts by @mcdonc in #535
- fix(agent): skip broadcast on deleted workspace to avoid FK constraint by @mcdonc in #543
- docs: add klangkc sandbox feature spec by @mcdonc in #536
- fix wording by @mcdonc in #544
- fix(security): add ACL check to exec_start WebSocket command by @mcdonc in #546
- feat: add klangkc restart command by @mcdonc in #545
- ci: add CodeQL security scanning workflow by @mcdonc in #550
- fix: resolve symlinks in mount path validation by @mcdonc in #551
- refactor: remove function-scope imports by @mcdonc in #552
- fix: URL-encode file paths in file viewer API calls by @mcdonc in #553
- fix: refresh cached handle on WebSocket connections after change by @mcdonc in #554
- fix(security): prevent shell injection via tmux window name by @mcdonc in #557
- fix(security): add upload size limit and stream file uploads to disk by @mcdonc in #558
- fix(security): add opt-out for X-Forwarded-* header trust by @mcdonc in #561
- fix(security): set restrictive permissions on CLI config file by @mcdonc in #563
- fix(security): prevent XSS in OIDC callback error page by @mcdonc in #562
- fix(security): add workspace token auth to browser-delegate endpoints by @mcdonc in #560
- feat: add trivy-workspace script for scanning workspace image by @mcdonc in #571
- Bump workspace base image to 2026.06.20-5fc1dbf by @github-actions[bot] in #575
- docs: rewrite terminal chapter — explain tmux first by @mcdonc in #577
- docs: terminal fixes and workspaces.md deduplication by @mcdonc in #578
- feat(cli): switch config from TOML to YAML by @mcdonc in #576
- docs: add GitHub repo link to site header by @mcdonc in #581
- feat: make Claude Code a plugin instead of base image install by @mcdonc in #582
- Bump workspace base image to 2026.06.20-fb4974d by @github-actions[bot] in #584
- docs: explain handle/HOME relationship and single-UNIX-user design by @mcdonc in #586
- docs: rewrite homepage by @mcdonc in #590
- docs: fix devenv command on homepage by @mcdonc in #591
- feat: resolve @mentions by handle instead of email by @mcdonc in #588
- fix: suppress duplicate request logging from uvicorn by @mcdonc in #598
- fix(security): address CodeQL path injection and logging findings by @mcdonc in #597
- fix(e2e): write cli.yaml not cli.toml in token expiry test by @mcdonc in #601
- fix: add 5s timeout on WebSocket ready to avoid Firefox throttle by @mcdonc in #604
- feat: replace marquee plugin with Boing Ball demo by @mcdonc in #602
- fix: event-driven Firefox WebSocket throttle avoidance by @mcdonc in #607
- fix: always pre-check HTTP before WebSocket connect by @mcdonc in #610
- feat: add klangk.org landing page and update docs favicon by @mcdonc in #611
- feat(cli): add workspace share/unshare/members commands by @mcdonc in #609
- perf: optimize boingball animation and add stereo panning by @mcdonc in #613
- docs: add Boing Ball screenshot to plugins chapter by @mcdonc in #614
- docs: document container policy.json requirement by @mcdonc in #618
- fix: colorize generated password log message in green by @mcdonc in #615
- docs: add Running with Docker page, split Getting Started by @mcdonc in #621
- fix: debounce presence join/leave broadcasts during reconnection by @mcdonc in #620
- fix(security): address CodeQL code scanning findings by @mcdonc in #625
- fix: narrow broad except clauses and fix error log levels by @mcdonc in #623
- Update dependencies to resolve security alerts by @mcdonc in #628
- Simplify README by @mcdonc in #630
- Audit AGENTS.md: add secrets rule, remove Web Search by @mcdonc in #633
- Stream zip downloads via temp file instead of memory by @mcdonc in #634
- Replace RuntimeError with domain-specific exceptions by @mcdonc in #635
- Fix Node.js 20 deprecation warnings in GitHub Actions by @mcdonc in #649
- Cover previously excluded code, fix dead other_msgs bug by @mcdonc in #636
- Bump workspace base image to 2026.06.21-3ae0aff by @github-actions[bot] in #650
- Debug WebSocket connect delay in Firefox by @mcdonc in #651
- Run update-plugins automatically during devenv startup by @mcdonc in #654
- Update release docs to reference semver by @mcdonc in #656
- Use version file for plugin refs instead of hardcoded main by @mcdonc in #655
- Add access token refresh endpoint and automatic renewal by @mcdonc in #659
- Apply nginx container ACL to browser-delegate/stream by @mcdonc in #674
- Add deferred-imports pre-commit hook by @mcdonc in #675
- Stop git-credential plugin from using KLANGK_BRIDGE_TIMEOUT_SECONDS by @mcdonc in #676
- Merge dockerexec.py into podman.py by @mcdonc in #677
- Automatic workspace token renewal via file-based storage by @mcdonc in #672
- Fix info leak: hide exception details in workspace list snackbar by @mcdonc in #679
- Log exceptions in bare catch blocks across frontend by @mcdonc in #678
- Fix token refresh idempotency for expired tokens by @mcdonc in #681
- fix: prevent agent process death on terminal PTY EOF by @mcdonc in #682
- Add System Info tab to debug panel by @mcdonc in #680
- Scope browser ID by instance ID by @mcdonc in #683
- Add API fuzz testing script by @mcdonc in #688
- fix: log email sent messages after send completes by @mcdonc in #695
- docs: add API endpoint security reference by @mcdonc in #684
- Fix SQLite pool exhaustion under concurrent load by @mcdonc in #691
- Fix fuzz test report losing request counts by @mcdonc in #698
- fix: mask token in verification URL log message by @mcdonc in #696
- Remove dead code from setup_clankers.py by @mcdonc in #699
- fix: don't expose internal error details to client by @mcdonc in #701
- Pin npm extension version for reproducible builds by @mcdonc in #705
- fix: bypass Firefox WebSocket throttle with channel.ready timeout by @mcdonc in #706
- fix: reduce reconnect backoff and ready timeout for faster recovery by @mcdonc in #709
- Bump workspace base image to 2026.06.21-c68ea66 by @github-actions[bot] in #707
- fix: update API fuzzer to use /api/v1 prefix and add missing endpoints by @mcdonc in #710
- Add workspace export/import UI to settings panel by @mcdonc in #702
- Fix duplicate reconnect timers causing rapid counter advance by @mcdonc in #715
- fix: agent resolves container ID from registry, not cached by @mcdonc in #713
- fix: return 400 for passwords exceeding bcrypt 72-byte limit by @mcdonc in #718
- docs: add request/response samples to api-endpoints.md by @mcdonc in #720
- fix: return 400 for filenames exceeding OS NAME_MAX limit by @mcdonc in #722
- fix: verify_password returns False for passwords > 72 bytes by @mcdonc in #727
- feat: admin add-user dialog offers send verification email option by @mcdonc in #723
- fix: center settings and sharing panels on wide viewports by @mcdonc in #728
- fix: settings panel layout and reconnect timer stacking by @mcdonc in #729
- fix: hide own join/leave system messages in chat by @mcdonc in #731
- fix: stop infinite agent restart loop when container is missing by @mcdonc in #732
- refactor: replace inline shell commands with container-side scripts by @mcdonc in #733
- Normalize workspace script names by @mcdonc in #737
- fix: check bind mount sources exist before creating container by @mcdonc in #741
- Rename .klangk/sandbox.yaml to .klangk-sandbox.yaml by @mcdonc in #743
- Catch ConnectionError in sandbox command by @mcdonc in #745
- fix: stop agent session before removing container on workspace delete by @mcdonc in #746
- Fix /version endpoint path missing /api/v1 prefix by @mcdonc in #749
- Add forward-agent to CLI config, remove KLANGKC_FORWARD_AGENT env var by @mcdonc in #753
- Multi-server config with separate state and multi-user credentials by @mcdonc in #756
- fix: run sandbox setup after SSH agent forwarding by @mcdonc in #765
- fix: prevent second instance from killing first instance's containers by @mcdonc in #766
- Fix token-expiry E2E test for new config/state split by @mcdonc in #768
- Use kebab-case for YAML config keys by @mcdonc in #759
- fix: add /api/v1 prefix to OIDC callback redirect URI by @mcdonc in #769
- Add haiku-rag example sandbox and uv to workspace image by @mcdonc in #762
- fix: pass SSH_AUTH_SOCK to exec sessions for sandbox setup by @mcdonc in #771
- fix: resolve PID file dir portably (macOS has no /run/user) by @runyaga in #773
- fix: relay SSH agent during sandbox setup exec sessions by @mcdonc in #778
- feat: auto-create terminal window in klangkc shell by @mcdonc in #780
- fix: source bashrc for non-interactive sandbox setup scripts by @mcdonc in #789
- feat: add --open/-o flag to klangkc sandbox by @mcdonc in #791
- feat: allow plugins to be installed from local paths by @mcdonc in #795
- revert: undo BASH_ENV changes from #789 by @mcdonc in #796
- fix: don't swallow on-image-build plugin output by @mcdonc in #798
- fix: remove BASH_ENV from workspace Dockerfile by @mcdonc in #801
- Don't alias /bin/sh to /bin/bash by @mcdonc in #803
- Bump workspace base image to 2026.06.24-fc6981c by @github-actions[bot] in #804
- fix: skip bashrc user-session setup during image build by @mcdonc in #807
- fix: remove .klangk-image-build marker after hooks run by @mcdonc in #812
- Fix flaky spectator-cannot-send-input E2E test by @mcdonc in #811
- feat: add hermes plugin (NousResearch agent via llm-proxy) by @mcdonc in #800
- Add OpenClaw example sandbox by @mcdonc in #777
- refactor: rename examples/ to sandboxes/ by @mcdonc in #816
- fix: align playwright browser versions between nix and npm by @mcdonc in #819
- deps: pin klangk_plugin_api to v0.1.0 by @mcdonc in #821
- fix: stop reconnect loop after 10 attempts by @mcdonc in #818
- feat: mount plugin-contributed routes in GoRouter by @mcdonc in #820
- fix: regenerate package-lock.json for playwright 1.59.1 pin by @mcdonc in #823
- fix: reduce mouse wheel scroll speed in tmux by @mcdonc in #830
- fix: run playwright browser setup after npm install by @mcdonc in #832
- fix: use tmux.conf wheel bindings for scroll speed by @mcdonc in #839
- feat: add password visibility toggle to all password fields by @mcdonc in #840
- fix: show Connection Lost after reconnect attempts exhausted by @mcdonc in #834
- Copy full plugin repos into container; support skills and prompts by @mcdonc in #843
- feat: browse full container filesystem from files tab by @mcdonc in #842
- fix: pin libghostty to 0.0.9 to fix CI build errors by @mcdonc in #854
- fix: clean up _workspace_locks in stop_and_remove_container by @mcdonc in #855
- fix: sanitize Content-Disposition filenames by @mcdonc in #856
- fix: catch OSError in delete_file and rename_file endpoints by @mcdonc in #857
- fix: detect and signal streaming download failures by @mcdonc in #858
- fix: prevent stderr deadlock and subprocess leak in export streaming by @mcdonc in #859
- feat: add admin endpoint to reset user login lockout by @mcdonc in #860
- Make mounts and env vars selectable/copyable in workspace settings by @mcdonc in #852
- fix: only abort stream on non-zero exit when no data was produced by @mcdonc in #863
- fix: replace Unicode box-drawing chars with ASCII dashes in plugin banners by @mcdonc in #862
- feat: add configurable terminal banner via KLANGK_TERMINAL_BANNER by @mcdonc in #866
- fix: improve klangkc login error when URL points to wrong path by @mcdonc in #867
- chore: fix module name in test_cli docstring by @mcdonc in #868
- fix(auth): return 401 for OIDC-only users on password login by @mcdonc in #879
- fix: scope agent presence to its running workspace by @mcdonc in #880
- fix: cancel token renewal task on workspace session reset by @mcdonc in #881
- fix(wshandler): require admin to restart/shutdown container by @mcdonc in #882
- fix: stop agent RPC subprocess on workspace teardown by @mcdonc in #883
- fix: require ownership to delete shared terminal by @mcdonc in #884
- fix: stop caching agent mention regex by @mcdonc in #885
- fix: bound port allocation range and unblock event loop by @mcdonc in #886
- fix: handle registration race for duplicate email by @mcdonc in #887
- fix: prevent orphaned agent runs on concurrent @mentions by @mcdonc in #891
- fix(emailsvc): HTML-escape invited_by_email in invitation emails by @mcdonc in #892
- fix: evict expired resend/password-reset rate-limit entries by @mcdonc in #896
- refactor(ws): remove unreachable time-based reconnect give-up by @mcdonc in #902
- refactor(test): extract _conn_in_workspace fixture helper by @mcdonc in #903
- fix(e2e): harden flaky frontend e2e tests against backend load by @mcdonc in #904
- refactor(test): adopt _conn_in_workspace in test_ui_ready by @mcdonc in #907
- fix: guard verify_password against NULL hash in 4 auth endpoints by @mcdonc in #893
- refactor(podman): extract _exec_args helper, add extra_env (#900) by @mcdonc in #906
- refactor(terminal): route podman exec through exec_container helpers (#897) by @mcdonc in #908
- refactor(workspaces): route populate_home_skel through exec_container by @mcdonc in #909
- refactor(model): extract _fetchone for single-row SELECTs by @mcdonc in #910
- fix: reset agent restart counter on successful prompt by @mcdonc in #912
- refactor(ws): extract _find_window terminal-window lookup helper by @mcdonc in #911
- fix(agent): restart subprocess on prompt timeout for clean next turn by @mcdonc in #915
- perf(api): batch ACL reads in /my-permissions (878ms → ~floor) by @mcdonc in #914
- perf(ws): skip HTTP pre-check on non-Firefox browsers (saves ~250ms) by @mcdonc in #921
- perf(acl): batch the per-request ACL read in check_permission by @mcdonc in #926
- feat: dynamically update workspace list on create/delete/share (#825) by @mcdonc in #925
- perf(files): cache directory listings client-side + graceful 404s by @mcdonc in #927
- fix(ws): clear _reconnecting on no-workspace reconnect by @mcdonc in #931
- fix(auth): slide login lockout window so old failures don't count (#928) by @mcdonc in #932
- fix(ui): poll stale-build check every 5 minutes instead of 2 by @mcdonc in #934
- fix(agent): don't persist agent disconnect/reconnect to chat history by @mcdonc in #935
- fix: re-validate OIDC cli_redirect at callback time (token disclosure) by @mcdonc in #940
- fix(terminal): pass window name/session as argv, not interpolated by @mcdonc in #941
- feat(workspaces): paginate list endpoints + CLI pagination by @mcdonc in #942
- feat(frontend): paginate workspace list with per-section load more by @mcdonc in #946
- refactor(api): collapse add_workspace_member ACL grants into a loop (#951) by @mcdonc in #956
- refactor(ws): replace message if/else chain with dispatch table by @mcdonc in #957
- refactor(settings): decompose WorkspaceSettingsPanel.build into helpers (#954 part 1) by @mcdonc in #959
- feat: sort + name filter on workspace list (backend + CLI + frontend) by @mcdonc in #950
- fix(security): stop trusting client-supplied X-Forwarded-* by default (#937) by @mcdonc in #944
- refactor(app): extract GoRouter redirect guards from _createRouter by @mcdonc in #958
- refactor(chat): decompose WorkspaceChat.build into helpers (#954 part 2) by @mcdonc in #960
- refactor(util): extract shared file-read helper from secret resolvers by @Shridharrrr in #977
- refactor(workspace_page): decompose build + extract testable overlays (#954 part 3) by @mcdonc in #978
- test(frontend): add WorkspaceSettingsPanel tests + chat loading-spinner test (#954) by @mcdonc in #980
- fix(files): bump directory-listing cache TTL to 20s by @mcdonc in #982
- Refactor: extract SshAgentForwarder collaborator from Connection (#961) by @mcdonc in #984
- Refactor: extract ExecController collaborator from Connection (#961) by @mcdonc in #985
- Refactor: extract TerminalController collaborator from Connection (#961) by @mcdonc in #986
- feat(util): support
cmd:env-var prefix that runs a command by @mcdonc in #987 - Refactor: extract SharedTerminalController collaborator from Connection (#961, final) by @mcdonc in #988
- feat(admin): paginate, sort, filter /admin/users; drop groups from cards by @mcdonc in #983
- feat(util): route most env-var reads through resolve_env_secret; nginx.sh prefix support by @mcdonc in #990
- Add pagination, sorting, and filtering on the /admin/users invitations page by @mcdonc in #991
- chore(devenv): add ruff to packages by @mcdonc in #992
- refactor(model): split model.py (2065L) into per-domain package + extract schema by @mcdonc in #993
- feat(admin): paginate, sort, filter /admin/users groups tab (#949) by @mcdonc in #994
- Replace handle_websocket if/elif dispatch with a command table by @mcdonc in #995
- refactor(api): split api.py (2800L, 84 routes) into per-domain package by @mcdonc in #996
- fix(backend): use dynamic versioning so uv sync reinstalls entry points by @mcdonc in #999
- refactor(frontend): break up _createWorkspace (319L → 201L) by @mcdonc in #998
- refactor(cli): extract shared ShellSession from _run_shell and _exec_on_ws by @mcdonc in #1000
- refactor(wshandler): split wshandler.py into per-concern sub-package by @mcdonc in #1002
- refactor(frontend): extract chat sub-widgets from WorkspaceChatState (#969) by @mcdonc in #1003
- refactor(container): extract PortAllocator, BrowserRouter, IdleMonitor collaborators by @mcdonc in #1004
- refactor(container): break up _start_container_inner into stage methods by @mcdonc in #1005
- refactor(wshandler): break up long handler functions (terminal_start, workspace_connect, join_shared) by @mcdonc in #1006
- refactor(frontend): break up oversized build() methods (login_page, ide_layout) by @mcdonc in #1011
- refactor(frontend): extract CreateWorkspaceDialog from WorkspaceListPage (#963) by @mcdonc in #1010
- feat: wire up default_command via tmux send-keys by @mcdonc in #1012
- refactor(cli): divorce sandbox from shell connection (#1009) by @mcdonc in #1014
- feat: auto-start workspace containers on server boot by @mcdonc in #1019
- feat(api): add GET /workspaces/{id}/status endpoint by @mcdonc in #1020
- chore(sandboxes): update openclaw config, remove todo-sandbox by @mcdonc in #1021
- fix(sandbox): configure openclaw allowedOrigins and trustedProxies for hosted proxy by @mcdonc in #1023
- feat(api): eagerly start container when workspace created with auto_start by @mcdonc in #1025
- fix(schema): add migration for workspaces.auto_start column by @mcdonc in #1027
- feat: run default_command in tmux on eager container start by @mcdonc in #1028
- fix: wait for shell init before sending default_command keystrokes by @mcdonc in #1030
- feat(frontend): show container status icons on workspace cards (#1016) by @mcdonc in #1031
- feat: run default_command in dedicated tmux window, trigger after sandbox setup by @mcdonc in #1032
- docs(auto-start): add workspace screenshot to chapter header by @mcdonc in #1037
- feat(frontend): make workspace icon the running/stopped indicator by @mcdonc in #1036
- fix(frontend): unregister service workers before reload by @mcdonc in #1038
- docs(policy): add default-closed contribution policy (CONTRIBUTING/SECURITY/templates) by @mcdonc in #1044
- ci(policy): add default-closed auto-close + auto-reopen workflows (INERT) by @mcdonc in #1045
- chore(policy): add runyaga to slop allowlist by @mcdonc in #1046
- chore(policy): add tseaver to slop allowlist by @mcdonc in #1048
- chore(policy): add bd-mkt and Shridharrrr to slop allowlist by @mcdonc in #1049
- fix(sandboxes/openclaw): write all env exports to .bashrc up front by @mcdonc in #1040
- docs(policy): flip default-closed wording to present tense by @mcdonc in #1047
- ci(policy): add valid-reopened label on auto-reopen (triage queue signal) by @mcdonc in #1050
- fix(backend): add setup_state lifecycle to prevent premature default_command (#1033) by @mcdonc in #1051
- feat(cli): automatic JWT refresh for klangkc by @mcdonc in #1052
- chore: remove claude-code from default plugins list by @mcdonc in #1053
- refactor(backend): decompose import_workspace and oidc_callback by @mcdonc in #1055
- refactor(frontend): break up oversized build() methods by @mcdonc in #1054
- refactor(frontend): break up SettingsPage and FileViewerPanel god widgets by @mcdonc in #1056
- refactor(frontend): extract ImportWorkspaceDialog with full test coverage by @mcdonc in #1057
- refactor(frontend): break up _AdminUsersPageState — extract groups, invitations, member management (#970) by @mcdonc in #1058
- fix(devenv): resolve pubspec.yaml PLACEHOLDER during enterShell by @mcdonc in #1060
- fix(backend): create role groups on import and duplicate (#849) by @mcdonc in #1071
- refactor(frontend): extract TerminalTabsView and WorkspaceConnector (#971) by @mcdonc in #1061
- fix(frontend): clear stale presence/members/terminals on WebSocket disconnect by @mcdonc in #1072
- fix(backend): snapshot state.connections before iteration (#1069) by @mcdonc in #1073
- fix(frontend): allow re-reconnect after drop during connectWorkspace (#1068) by @mcdonc in #1074
- fix(cli): use _send_ignore_closed for exec_stop in _ExecSession.run() by @mcdonc in #1075
- fix(cli): wrap blocking SSH agent query in run_in_executor by @mcdonc in #1076
- fix(cli): cancel all tasks in _TerminalSession.run() on failure by @mcdonc in #1077
- fix(frontend): clear chatHistory on chat_history to prevent duplicates (#1064) by @mcdonc in #1078
- fix(backend): call conn.cleanup() for dead sockets in broadcast methods by @mcdonc in #1080
- docs: note plugins (compile-time) vs sandboxes (runtime) in both chapters by @mcdonc in #1091
- Split system env out of bash.bashrc into /etc/profile.d (#1093) by @mcdonc in #1094
- feat: health-check-aware monitoring and klangkc monitor (#1015) by @mcdonc in #1086
- feat(container): add klangk-hosted-url script (#1081) by @mcdonc in #1097
- Periodic Trivy workspace scan + no-fix CVE report (#570) by @mcdonc in #1099
- ci: fix setup-trivy version (v0.2.0 does not exist) by @mcdonc in #1100
- Rename workspace_ready -> container_ready; poll sentinel server-side (#1095) by @mcdonc in #1098
- Atomic workspace creation: no more orphaned ACL entries (#128) by @mcdonc in #1102
- Run health check as bash login shell; document shell conventions (#1087) by @mcdonc in #1103
- Use openclaw health as the openclaw sandbox health check + e2e test (#1089) by @mcdonc in #1105
- fix(auth): harden default password policy and brute-force protection by @mcdonc in #1104
- feat(frontend): stream workspace export to disk (#700) by @mcdonc in #1101
- Surface health-check failure reason (stdout/stderr) (#1088) by @mcdonc in #1106
- Run klangkc exec as a bash login shell; --raw for transports (#1041) by @mcdonc in #1107
- Make herdr a plugin (opt-in); drop baked-in install + socket setup (#1108) by @mcdonc in #1110
- Convert hermes from a plugin to a runtime sandbox; delete the bashrc bailout (#1109) by @mcdonc in #1111
- Health check runs as a non-login bash shell (bash -c) by @mcdonc in #1113
- Allowlist github-actions[bot] so base-image bump PRs aren't auto-closed by @mcdonc in #1116
- docs(hermes): document gateway is not exposed on an HTTP port by @mcdonc in #1118
- docs(openclaw): warn the gateway is contactable by anyone on the network by @mcdonc in #1119
- docs: add Available Sandboxes chapter for OpenClaw and Hermes by @mcdonc in #1122
- Web UI: expose Auto start checkbox + normalize workspace dialog fields by @mcdonc in #1123
- Default command is a per-workspace singleton in the owner's session (#1114) by @mcdonc in #1125
- fix(workspaces): notify on role-based share so Shared-with-Me updates live by @mcdonc in #1129
- fix(frontend): clear all 20 pre-existing dart analyze warnings by @mcdonc in #1130
- Admin user dialogs: inline password-length validation + confirm-password fields by @mcdonc in #1128
- Demote podman-timing log lines from INFO to DEBUG by @mcdonc in #1132
- test(frontend): find dialog TextFields by identity, not position by @mcdonc in #1134
- fix(agent): refuse to seed agent with another user's handle by @mcdonc in #1143
- fix(workspaces): remove chat access from the spectators role by @mcdonc in #1144
- fix(workspaces): reject system agent in role grants (#1135) by @mcdonc in #1141
- Allow admins to disable the chat agent via KLANGK_AGENT_DISABLED by @mcdonc in #1147
- Give the agent operating-environment context (#1140) by @mcdonc in #1151
- Add KLANGK_PRODUCT_NAME white-label config by @mcdonc in #1154
- Remove the now-unused workspace_members WebSocket event by @mcdonc in #1153
- feat(branding): runtime logo override via KLANGK_LOGO_URL by @mcdonc in #1155
- Rename agent: MrBoops→clanker, KLANGK_CHAT_AGENT_→KLANGK_AGENT_, klangk-setup-pi (#1139) by @mcdonc in #1156
- Provision the agent home eagerly and inject KLANGK_AGENT_HOME (#1157) by @mcdonc in #1161
- Prevent users from taking the live agent's handle (#1160) by @mcdonc in #1163
- Add e2e tests for agent-home behaviors + fix silent klangk-setup-pi failure (#1162) by @mcdonc in #1164
- Run the default command as the agent in a standalone service session (#1158) by @mcdonc in #1166
- Surface the service window as an operable terminal tab in the UI (#1159) by @mcdonc in #1168
- Remove the haiku-rag sandbox (#1169) by @mcdonc in #1170
- feat(email): Jinja2 email templates + overlay, Reply-To, expiry fix by @mcdonc in #1167
- Surface live health in workspace list payload so steady-state unhealthy icons render by @mcdonc in #1183
- Add e2e test: klangkc monitor detects health states going up and down by @mcdonc in #1180
- Fix sandbox autostart under agent-owned service session by @mcdonc in #1176
- Delete dead build_message() and send_email() from emailsvc by @mcdonc in #1196
- Pin webkit executablePath to fix E2E cross-browser job by @mcdonc in #1194
- Configurable legal & support links (Terms / Privacy / AUP / Support) via /config by @mcdonc in #1190
- feat: runtime SSL/CA cert injection into workspaces + backend (#1181) by @mcdonc in #1198
- Add 1080p CLI terminal recorder for the intro video by @mcdonc in #1204
- Render chat URLs (incl. hosted-app URLs) as clickable links by @mcdonc in #1202
- Rename workspace "default command" to "service command" by @mcdonc in #1205
- Show workspace health/running status in klangkc ls by @mcdonc in #1207
- Fix klangkc shell shared service-cmd join (wait for shared_terminals) by @mcdonc in #1209
- service_health: send current-health snapshot on connect (#1175 item 1) by @mcdonc in #1210
- docs(chat): clarify what the AI agent is — and isn't by @mcdonc in #1211
- Graceful runtime restart on SIGHUP (#1212) by @mcdonc in #1213
- Install supervisor into the workspace base image by @mcdonc in #1215
- devenv: re-run uv sync when uv.lock or a member pyproject changes by @runyaga in #1214
- Bump workspace base image to 2026.07.03-7a5caf9 by @github-actions[bot] in #1216
- feat(cli): add --command/-c flag to klangkc create by @mcdonc in #1218
- fix(exec): single-arg login commands run as shell syntax; strip -- separator by @mcdonc in #1217
- devenv: sync uv deps before enterShell, not just for the backend process by @mcdonc in #1219
- fix(terminal): kill zombie service-cmd window on send-keys failure by @mcdonc in #1220
- fix(agent): serialize _ensure_started spawn to prevent double-spawn by @mcdonc in https://github.com/mcdonc/klangk/pull/1222
- terminal: serialize ensure_service_session firing per container by @mcdonc in https://github.com/mcdonc/klangk/pull/1221
- fix(devenv): run uv sync unconditionally; drop gate that skips stale venv by @mcdonc in https://github.com/mcdonc/klangk/pull/1227
- feat(admin): list workspaces in the delete-user confirmation by @mcdonc in https://github.com/mcdonc/klangk/pull/1228
- fix(health): give the startup command a grace period before health checks can flag unhealthy by @mcdonc in https://github.com/mcdonc/klangk/pull/1229
- refactor: remove underscore prefixes from cross-boundary public API by @mcdonc in https://github.com/mcdonc/klangk/pull/1234
- fix(nginx): proxy WebSocket upgrades to the slash-less /hosted// root by @runyaga in https://github.com/mcdonc/klangk/pull/1233
- fix(auth): logout no longer stops the user's containers (#1235) by @mcdonc in https://github.com/mcdonc/klangk/pull/1236
- feat(health): make service_health WS stream a trustworthy signal by @mcdonc in https://github.com/mcdonc/klangk/pull/1239
- scripts: pass --signature-policy to podman build/pull by @mcdonc in https://github.com/mcdonc/klangk/pull/1231
- fix(container): eager-start honors KLANGK_HOSTING_* via derive_hosting_info by @mcdonc in https://github.com/mcdonc/klangk/pull/1241
- test(main): make TestStartupShutdownRestart order/isolation-independent by @mcdonc in https://github.com/mcdonc/klangk/pull/1243
- feat(hosting): KLANGK_HOSTED_PORTS_PER_WORKSPACE to configure/disable ports (#1237) by @mcdonc in https://github.com/mcdonc/klangk/pull/1245
- fix(workspaces): fire service command on every fresh container create by @mcdonc in https://github.com/mcdonc/klangk/pull/1246
- test(api): set OIDC state cookie on client, not per-request by @mcdonc in https://github.com/mcdonc/klangk/pull/1253
- test(agent): eliminate un-awaited-coroutine RuntimeWarnings (#1251) by @mcdonc in https://github.com/mcdonc/klangk/pull/1252
- test(model): close pooled connections in migration tests by @mcdonc in https://github.com/mcdonc/klangk/pull/1254
- fix(db): close aiosqlite connections orphaned by task cancellation by @mcdonc in https://github.com/mcdonc/klangk/pull/1255
- fix(auth): email-verification routes create users with derived handles (#1256) by @mcdonc in https://github.com/mcdonc/klangk/pull/1259
- fix(ws): raise WebSocket max message size to 16 MB in production by @mcdonc in https://github.com/mcdonc/klangk/pull/1267
- fix(workspaces): run import/export tar off the event loop by @mcdonc in https://github.com/mcdonc/klangk/pull/1269
- fix(container): serialize state teardown under the workspace lock by @mcdonc in https://github.com/mcdonc/klangk/pull/1268
- fix(workspaces): run ensure_home_symlink FS I/O off the event loop (#1262) by @mcdonc in https://github.com/mcdonc/klangk/pull/1270
- refactor(wshandler): remove dead save_state_snapshot by @mcdonc in https://github.com/mcdonc/klangk/pull/1280
- fix(schema): migrate workspaces tables to add mounts/env columns (#1264) by @mcdonc in https://github.com/mcdonc/klangk/pull/1285
- fix(api): stop bare-list workspace endpoints from silently capping at 10 (#1266) by @mcdonc in https://github.com/mcdonc/klangk/pull/1287
- fix(frontend): add mounted checks to terminal link tap callbacks by @mcdonc in https://github.com/mcdonc/klangk/pull/1284
- fix(util): close file handle in read_file_value by @mcdonc in https://github.com/mcdonc/klangk/pull/1282
- fix(frontend): add mounted check to FileDropZone.uploadFiles by @mcdonc in https://github.com/mcdonc/klangk/pull/1283
- Remove liveness-probe comments from openclaw sandbox.yaml by @mcdonc in https://github.com/mcdonc/klangk/pull/1289
- fix(model): pagination off-by-one in has_more by @mcdonc in https://github.com/mcdonc/klangk/pull/1290
- fix(frontend): replace lazy List.cast() with eager List.from() in WsClient by @mcdonc in https://github.com/mcdonc/klangk/pull/1292
- fix(nginx): raise worker_connections from 64 to 1024 by @mcdonc in https://github.com/mcdonc/klangk/pull/1293
- fix(frontend): resync mounts, env, and image in didUpdateWidget by @mcdonc in https://github.com/mcdonc/klangk/pull/1291
- docs(customize): reframe for runtime-first customization, build only for plugins by @mcdonc in https://github.com/mcdonc/klangk/pull/1294
- refactor(backend): key workspace storage by workspace_id, not user_id by @mcdonc in https://github.com/mcdonc/klangk/pull/1295
- fix(frontend): prevent chat history duplication on reconnect by @mcdonc in https://github.com/mcdonc/klangk/pull/1309
- fix(frontend): guard _loadFiles against concurrent call desync by @mcdonc in https://github.com/mcdonc/klangk/pull/1314
- fix(backend): acquire session lock around token renewal start by @mcdonc in https://github.com/mcdonc/klangk/pull/1312
- fix(backend): serialize get_session/stop_session to prevent race (#1298) by @mcdonc in https://github.com/mcdonc/klangk/pull/1310
- fix(frontend): cancel filter debounce on sort change by @mcdonc in https://github.com/mcdonc/klangk/pull/1321
- fix(frontend): catch sendBrowserResponse errors in BrowserDelegate by @mcdonc in https://github.com/mcdonc/klangk/pull/1320
- fix(frontend): guard showMenu .then callback with mounted check by @mcdonc in https://github.com/mcdonc/klangk/pull/1319
- fix(backend): make get_or_create_session atomic with setdefault by @mcdonc in https://github.com/mcdonc/klangk/pull/1318
- fix(frontend): guard onDragDone against concurrent uploads by @mcdonc in https://github.com/mcdonc/klangk/pull/1317
- fix(backend): remove workspace state save/restore (#1316) by @mcdonc in https://github.com/mcdonc/klangk/pull/1322
- feat: allow workspace owner or admin to transfer ownership by @mcdonc in https://github.com/mcdonc/klangk/pull/1323
- feat(backend): auto-generate persistent instance ID by @mcdonc in https://github.com/mcdonc/klangk/pull/1325
- fix(tests): update sandbox E2E profile paths for workspace_id keying by @mcdonc in https://github.com/mcdonc/klangk/pull/1328
- feat(backend): auto-generate persistent instance ID by @mcdonc in https://github.com/mcdonc/klangk/pull/1326
- fix(frontend): replace raw exception strings with user-friendly error messages by @mcdonc in https://github.com/mcdonc/klangk/pull/1335
- fix(backend): handle invalid JSON in workspace archive import by @mcdonc in https://github.com/mcdonc/klangk/pull/1336
- fix(backend): validate OIDC state cookie is a dict before accessing keys by @mcdonc in https://github.com/mcdonc/klangk/pull/1337
- fix(security): enforce email_verified in OIDC callback with per-IdP trust-email by @mcdonc in https://github.com/mcdonc/klangk/pull/1329
- fix(frontend): route _reconnect through WorkspaceConnector to prevent double workspace_connect by @mcdonc in https://github.com/mcdonc/klangk/pull/1315
- fix(backend): guard OIDC session minting and update_email against system agent by @mcdonc in https://github.com/mcdonc/klangk/pull/1338
- fix(backend): remove duplicate cleanup from broadcast iteration helpers by @mcdonc in https://github.com/mcdonc/klangk/pull/1313
- Load OIDC login hook by file path instead of Python import by @mcdonc in https://github.com/mcdonc/klangk/pull/1341
- fix(backend): stamp instance_id in workspace exports, reject foreign imports by @mcdonc in https://github.com/mcdonc/klangk/pull/1339
- demo(video): add intro video recording infrastructure by @mcdonc in https://github.com/mcdonc/klangk/pull/1342
- fix(backend): emit health death frame before removing container state by @mcdonc in https://github.com/mcdonc/klangk/pull/1352
- fix(frontend): resolve shared workspace name in app bar by @mcdonc in https://github.com/mcdonc/klangk/pull/1354
- docs: update image version references to v1.0 by @mcdonc in https://github.com/mcdonc/klangk/pull/1355
New Contributors
- @github-actions[bot] made their first contribution in #292
- @Shridharrrr made their first contribution in #977
Full Changelog: v2026.06.10...v1.0