Add cursor-based GET /teams/:id/tasks and GET /teams/:id/events APIs.
Team detail page loads older messages on scroll/click and deduplicates
collaboration chat messages with improved thread ordering.
- Add migrations plus Team/Member/Task/Event APIs; Redis Streams consumer projects inbox/events into DB as source of truth
- Inject Team Secret (Redis URL, team token) via envFrom; shared RWX PVC at /team; sync ConfigMap roster to /team/team.json
- Create member Pods through InstanceService; extend K8s (PVC/Secret/Pod/ConfigMap); stale-task sweep and Team/member deletion with cleanup
- Add /teams, /teams/new, /teams/🆔 creation wizard (roster, presets, shared env/OpenClaw plan), per-member desktops, collaboration timeline, debug dispatch (defaults to Leader when target omitted)
- add configurable /dev/shm mounts for instance pods with a bounded SHM_SIZE_GB override
- introduce pod security modes and use chromium-compat for OpenClaw instead of privileged
- keep privileged mode only as an explicit admin fallback
- remove the node-level clawmanager-node-tuner manifest to avoid changing host security defaults
- fix k3s HTTPS and API/proxy service port mappings
- add tests for SHM parsing and pod security mode behavior
Address three HIGH-severity issues from the memory-leak and bloat
analysis (issue #56).
1. Graceful shutdown (main.go)
- Replace gin's r.Run() with an explicit http.Server so the process
can intercept SIGINT / SIGTERM.
- On signal: drain active HTTP requests (10 s timeout), then stop
SyncService, WebSocket Hub, and InstanceAccessService cleanup
goroutine in order.
- Ensures database connections, K8s watchers, and background loops
are released cleanly on deploy or restart.
2. WebSocket Hub init race (websocket_service.go)
- GetHub() used a bare nil-check with no synchronisation; two
goroutines could each create a Hub and start a Run() loop.
- Replaced with sync.Once to guarantee exactly one Hub instance.
- Added a stop channel to Hub.Run() so the hub can be shut down
gracefully, closing all connected clients.
3. InstanceAccessService goroutine leak (instance_access_service.go)
- cleanupExpiredTokens() looped on ticker.C with no exit path,
leaking the goroutine for the lifetime of the process.
- Added a stopChan; cleanupExpiredTokens now selects on both the
ticker and the stop signal.
- Exposed Stop() on the service; InstanceHandler.Shutdown() calls
it during graceful shutdown.
Tests:
- TestGetHubReturnsSameInstance: singleton guarantee
- TestGetHubConcurrentAccess: 50-goroutine race test
- TestHubStopClosesClients: verifies client cleanup on Stop()
- TestInstanceAccessServiceStopTerminatesCleanup: Stop() is safe and
the service remains functional for token ops afterward
All existing tests continue to pass; full project build and regression
verified.
Ref: #56
Summary
-------
Logging in as an admin and navigating to Workspace → My Instances
returned every instance in the cluster instead of the admin's own.
Role was overloaded to both widen the admin console surface AND
widen the self-scoped list endpoint, so the workspace view broke
the owner-isolation contract users expect.
Root cause
----------
`InstanceService.GetVisibleInstances(userID, role, ...)` branched
on role: admin callers fell through to `instanceRepo.GetAll`,
non-admin callers fell through to `GetByUserID`. The single
`GET /instances` handler passed the caller's role into that
function, so the same URL meant "my instances" for users and
"every instance in the system" for admins.
Fix
---
Split the two views at the API surface, not inside the service:
- `GET /instances` is now always caller-scoped. The handler calls
`GetByUserID` unconditionally and never reads the caller's role.
- `GET /admin/instances` is a new route, gated by the existing
admin middleware trio (`Auth` + `SetUserInfo` + `NewAdminAuth`).
It calls a new `InstanceService.GetAllInstances` that does not
look at any userID.
- `GetVisibleInstances` is removed; nothing else in the codebase
called it.
Frontend follows: `AdminDashboard` and `InstanceManagementPage`
switch to a new `adminInstanceService.getInstances()` that hits
`/admin/instances`. Per-instance admin actions (start, stop,
delete, proxy, etc.) are intentionally out of scope for this PR
and continue to use the existing endpoints.
Tests
-----
Two new service tests in `instance_visibility_test.go`:
- `TestGetByUserIDFiltersByCaller` pins the workspace contract:
regardless of how many admins or other users exist, a caller
only ever sees their own instances through this path.
- `TestGetAllInstancesReturnsEveryUser` covers the admin-console
path, including pagination.
`go build ./...`, `go test ./...`, and `npm run build` all pass.
Scope note
----------
This PR fixes the listing leak only. Per-instance handlers in
`instance_handler.go` retain their existing inline role checks
and will be audited separately.
Background
This update focuses on three areas:
- Improve model onboarding capabilities by supporting unified configuration across multiple model service platforms
- Optimize the AI audit detail page to improve trace troubleshooting and readability
- Upgrade the OpenClaw runtime image and automatically enable the Gateway after instance startup
Changes
1. Support multiple model service platforms
- Introduce a vendor template mechanism for model onboarding, allowing quick selection of different model service platforms through a searchable dropdown
- Preconfigure fixed `base_url` values for common platforms to reduce manual input and configuration errors
- Support custom `base_url` for `Local / Internal`, compatible with local gateways, internal proxies, and self-hosted compatible services
- Add vendor icons to improve recognizability on the model configuration page
- Optimize the model creation experience so newly created cards appear at the top, making them easier to find when many models exist
- Optimize provider model discovery logic to support OpenAI-compatible services with non-standard version paths
2. Optimize the AI audit detail page
- Rework the trace detail layout to improve information hierarchy and readability
- Change audit timestamps to a combined relative + absolute format for more intuitive troubleshooting
- Add an execution flow view so the full process can be inspected by execution node
- Add a minimap to quickly locate execution nodes and keep navigation aligned with detail scrolling
- Remove duplicated or low-value information blocks to simplify the trace detail experience
- Optimize status rendering and failure reason unwrapping to prevent error payloads from polluting the status field
3. Upgrade the OpenClaw image and automatically enable the Gateway
- Upgrade the default OpenClaw runtime image to the new image address
- Automatically initialize and enable the Gateway when the new image starts, reducing manual instance-side operations
- Update the system default image configuration and add migration logic for existing default values