Decouple fosite token introspection from the HTTP request context using
context.WithoutCancel + 10s timeout. When claude.ai opens multiple
concurrent MCP connections and one disconnects, the token validation
for subsequent connections no longer fails with "context canceled".
Fixes Bug #6 from #bugs-synapbus.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When SYNAPBUS_BASE_URL is empty or set to "auto", the OAuth metadata
handler now reads X-Forwarded-Proto and X-Forwarded-Host headers to
construct correct OAuth URLs. This allows SynapBus to serve correct
OAuth metadata for both LAN and Cloudflare Tunnel access simultaneously.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The regex matched against HTML-escaped text where & entity chars
broke URL patterns. Now URLs are extracted and replaced with placeholders
before escapeHtml runs, then restored after all other inline processing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the Conversations page with a dedicated search page featuring:
- Large, prominent search input with autofocus
- Collapsible filter panel with time range presets (24h, week, month,
3 months, custom date range), channel filter (comma-separated,
- prefix to exclude), and agent filter (same syntax)
- Search-results-only display with helpful empty state when no search
has been performed
- Remove duplicate "Conversations" heading, rename to "Search"
- Update sidebar nav label and icon to match
Backend changes:
- Add channel, agent, after, before query parameters to
GET /api/messages/search endpoint
- Add Channels, ExcludeChannels, Agents, ExcludeAgents fields to
SearchOptions with SQL filter generation in store.go
- Support include/exclude semantics via - prefix for both channel
and agent filters
API client updated to pass new filter parameters.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
API keys are managed via admin CLI, not the web UI. Remove the
Management section from Settings, delete the api-keys route, and
clean up the Header page-title mapping.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace generic cube favicon and OAuth layered-planes logo with the
same constellation icon used in the sidebar and login page.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Auto-join public channels on first send (bug #1)
- Channel broadcasts no longer create duplicate DM copies; inbox DMs
only sent for @mentions (bug #2)
- Embedding pipeline auto-enqueues new messages via MessageListener
callback instead of requiring pod restart (bug #3)
- Admin socket defaults to /tmp in containers to avoid PVC filesystem
incompatibility with Unix sockets (bug #5)
- SSE events now fire for MCP-sent messages (not just REST API),
enabling live notification badges without page reload
- Fixed frontend SSE field name mismatch (channel_name → channel)
- Fixed SSE client not connecting after login redirect
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Switch Docker runtime from scratch to alpine:3.19 so kubectl exec works
for admin CLI operations. Add `synapbus channels create` and
`synapbus channels join` CLI commands with corresponding admin socket
handlers. Change default socket path to /data/synapbus.sock (absolute).
Also add Helm envFrom support and NodePort configuration.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use human agent's perspective only for unread counts (avoids system agent inflation)
- Replace onDestroy + get() with $effect cleanup in channel/DM pages (Svelte 5 compat)
- Fix notification store to parse array-of-objects API response format
- Add last_read_message_id to DM messages endpoint
- Fix test agent type seeding for GetHumanAgentForUser
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend:
- GET /api/notifications/unread returns channel + DM unread counts
- POST /api/notifications/mark-read updates inbox_state for channels/DMs
- SSE broadcaster wired into message send for real-time push
- last_read_message_id added to channel/DM message responses
Frontend:
- Notification store tracks unread counts per channel/DM
- SSE listener for new_message and unread_update events
- Red circular badges in sidebar (Slack-style)
- "New messages" separator line in channel/DM views
- Auto mark-as-read after 2 seconds of viewing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
sql.NullTime cannot scan SQLite's text-format timestamps from
modernc.org/sqlite. Switch to sql.NullString with manual time.Parse.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- JS/TS execution engine (goja + esbuild) with sandboxed runtime and call() bridge
- BM25 action discovery index over 23 registered actions
- ServiceBridge mapping call() invocations to existing service methods
- Admin CLI subcommands for webhook/k8s/gc operations
- Pagination support (offset/limit) in read_inbox, search_messages, get_channel_messages
- Fixed test assertions for call() envelope structure {ok, result}
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace 5 separate tool registrars (messaging, channels, swarm,
attachments, webhooks) with a single HybridToolRegistrar exposing
4 tools: my_status, send_message, search, and execute.
New foundation packages:
- internal/actions: action registry (22 actions) + BM25 search index
- internal/jsruntime: lightweight call() expression parser with
concurrency-limited execution pool
The `execute` tool dispatches call() expressions through a
ServiceBridge that maps action names to existing service methods,
preserving all original handler logic. The `search` tool enables
agents to discover available actions by keyword. The `send_message`
tool merges DM and channel sending with mutual exclusion.
All unit tests, integration tests, build, and vet pass.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Offset, After, Before date filters to ReadOptions and SearchOptions.
Add Channel name filter to SearchOptions. Introduce PaginatedMessages,
PaginatedChannels, and PaginatedTasks types with total counts. Update
ReadInbox, SearchMessages, and GetChannelMessages to return paginated
results. Add CountInboxMessages, CountSearchMessages, CountChannelMessages,
and CountTasks store methods. Update all callers in MCP tools, REST API
handlers, and search service. Add comprehensive tests for offset
pagination, date filtering, channel name filtering, and combined
filters with pagination.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Register all 23 agent-callable operations (messaging, channels, swarm,
attachments) with full parameter metadata and usage examples. Provide
in-memory BM25 text search over action documentation for tool discovery,
with simple stemming and compound-token matching so exact action names
rank highest.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pure Go JavaScript/TypeScript execution engine using goja + esbuild.
Provides sandboxed code execution with a call() bridge for agent
actions, automatic TypeScript detection and transpilation, timeout
enforcement, max-calls limits, and a concurrent execution pool.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add `my_status` MCP tool: single call returns agent identity, pending
DMs, channel mentions, system notifications, channel summaries, and
stats with truncation for large inboxes
- Add embeddings CLI: `synapbus embeddings status|reindex|clear` for
managing vectors when switching embedding providers
- Add automatic message retention worker with configurable period
(--message-retention, default 12m), warning notifications 1 month
before deletion, cascade cleanup, and incremental vacuum
- Add manual purge: `synapbus messages purge --older-than --agent --channel`
and `synapbus db vacuum` for on-demand cleanup
- Add `synapbus retention status` CLI for admin visibility
- Create system agent at startup for sending retention warnings
- Filter system agent from discover_agents results
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Parse @agentname patterns in channel message body. Mentioned agents
(who are channel members, excluding sender) get mention=true flag in
their inbox notification metadata. Channel message metadata includes
mentioned_agents list for all recipients.
- mentions.go: regex parser with email exclusion, dedup, 22 test cases
- BroadcastMessage: metadata now uses json.Marshal, includes mentions
- Tests verify mention flag, self-mention exclusion, non-member skip
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Updated tool descriptions to teach agents the right workflow:
- read_inbox: "Call this first when connecting"
- list_channels: "Call this when connecting to see available channels"
- send_message: guides to discover_agents first, points to send_channel_message
- search_messages: clarifies it searches inbox + channels
- send_channel_message: documents @agentname mentions
- discover_agents: explains it lists all agents when no query given
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Agents could send channel messages but had no MCP tool to read them.
Also, search_messages only searched DMs (to/from agent), missing channel
messages entirely. Now SearchMessages includes channel messages where
the agent is a member.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Agent registration success screen now shows tabbed client selector
(Claude Code, Gemini, Cursor, Windsurf, VS Code, Claude Desktop)
with per-client CLI commands, JSON config, and API Key/OAuth toggle.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix OAuth agent identity: add GetAgentName/GetUserID methods to fositeSession
so the introspection type assertion succeeds and MCP uses the selected agent
(e.g., "Alice Bot") instead of the human username ("alice")
- Fix channel broadcast: create a proper channel message (with channel_id) so
messages sent via MCP send_channel_message appear in the Web UI channel view
- Fix thread replies: pass conversation_id from thread panel so replies go into
the same conversation instead of creating a new one
- Fix OAuth token exchange: normalize localhost→127.0.0.1 in redirect_uri to
match what was stored during authorization (fixes Gemini CLI callback timeout)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix leave channel: handle ErrOwnerCannotLeave with error display, remove
all owned agents from channel
- Close thread panel when navigating between channels/DMs
- Remove Type dropdown from agent registration (agents are always AI;
human accounts created via CLI)
- Fix dashboard showing "Untitled conversation" — now shows last agent name
- Fix "1 msgs" → "1 msg" singular form on dashboard
- Fix conversation detail "-- N messages" → "— N message(s)" with em-dash
- Hide "done" status badge in MessageList and conversation detail
(consistent with DM view behavior)
- Add thread reply buttons and reply count to channel and DM messages
- Add agent selector for multi-agent users in channel and DM compose
- Add "Join Channel" prompt for non-members in channel compose area
- Show "(you)" indicator on channel member list for owned agents
- Add agent detail page with messages endpoint
- Improve release workflow and Dockerfile
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Channel pages now show message feed with compose bar instead of
just member lists. Messages display with agent avatars, names,
and timestamps. Collapsible info panel shows channel details.
- New /dm/[name] route for direct message conversations between
agents with from→to indicators and status badges.
- Sidebar DM links now navigate to /dm/{name} instead of agent
edit forms.
- Backend: add GetChannelMessages and GetDMMessages store/service
methods with corresponding API handlers and routes.
- Makefile: build target now depends on web target so binary
always embeds latest UI assets.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move module path from github.com/smart-mcp-proxy/synapbus to
github.com/synapbus/synapbus across all Go imports (47 files).
Add constellation logo options generated via FLUX 1.1 Pro.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: add specification for production readiness & website launch
Covers DevOps hooks, CI/CD, Prometheus observability, Docker/Helm
deployment, and synapbus.dev website with documentation and blog.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: add implementation plan and research for production readiness
Covers 5 workstreams: git hooks, CI/CD, observability, deployment
artifacts, and website. All constitution gates pass.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add pre-commit and pre-push git hooks
Pre-commit runs go vet, golangci-lint (optional), and fast tests.
Pre-push runs full test suite and build verification.
Installable via `make hooks`.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* ci: add GitHub Actions for PR checks and releases
ci.yml: lint, test, build on PRs to main.
release.yml: multi-platform binaries + Docker image on version tags.
Targets: linux/amd64, linux/arm64, darwin/amd64, darwin/arm64, windows/amd64.
Docker pushed to ghcr.io/smart-mcp-proxy/synapbus.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add Dockerfile, docker-compose, and Helm chart
Multi-stage Docker build (node + golang + scratch), ~30MB image.
docker-compose.yml for local development with volume persistence.
Helm chart with configurable Deployment, Service, PVC, Ingress,
and Prometheus ServiceMonitor.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add Prometheus metrics and Kubernetes health endpoints
Add internal/metrics package with Prometheus collectors (HTTP requests,
duration, messages, agents, connections) and chi-compatible middleware.
Add internal/health package with /healthz (liveness) and /readyz
(readiness with DB ping) endpoints. Wire into main.go with promhttp
handler at /metrics.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: update Go version to 1.25, fix Docker build issues
- Update Dockerfile golang image from 1.23 to 1.25 (matches go.mod)
- Add tzdata package for timezone support in scratch image
- Use npm install --legacy-peer-deps for web frontend build
- Update CI/release workflows to use Go 1.25
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: resolve CI failures - golangci-lint v2 and npm peer deps
- Upgrade golangci-lint-action to v7 with v2.1 (supports Go 1.25)
- Use npm install --legacy-peer-deps instead of npm ci for web builds
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: replace golangci-lint with go vet (golangci-lint doesn't support Go 1.25 yet)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The `to` parameter was incorrectly marked as Required() in the MCP tool
schema, preventing channel-only messages. The service layer already
validates that either `to` or `channel_id` must be provided.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Major feature additions across backend and frontend:
Backend:
- Unix domain socket admin server with JSON-RPC protocol
- CLI subcommands: user/agent management, audit, backup, messages, channels
- Managed API keys (sb_ prefix) with permissions, channel limits, expiry
- Thread/reply support in messaging core (reply_to column)
- Context-based trace owner_id propagation for proper audit filtering
- Two-step auth middleware supporting both agent keys and managed API keys
Frontend:
- Complete Slack-like dark theme redesign with custom CSS properties
- Sidebar with Channels, Direct Messages, and Admin sections
- Thread panel (slide-in) for viewing message replies
- API key management page with create form, key display, and
ready-to-use MCP/Claude Code config snippets with copy-to-clipboard
- All pages restyled: login, dashboard, agents, conversations, settings
E2E Tests:
- Fixed test runner binary path resolution
- Added pyproject.toml for test dependencies
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace deprecated SSE transport with Streamable HTTP (MCP spec
2025-03-26). Add OptionalAuthMiddleware for agent Bearer token
auth on /mcp endpoint — authenticates when token present, passes
through for unauthenticated tools like register_agent.
Also fix .gitignore to only ignore root synapbus binary, not
cmd/synapbus source directory.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Go's embed excludes files/directories starting with '_' by default.
SvelteKit outputs JS bundles under _app/, which would be silently
excluded by the dist/* pattern. Use all:dist to ensure all SPA assets
are embedded in the binary.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
onMount callbacks never fire in Svelte 5 runes mode compiled output,
causing the SPA to show a loading spinner indefinitely. Replace all
onMount calls with $effect + _initialized guard pattern, and convert
$: reactive statements to $derived(). Rebuild embedded SPA.
- Replace onMount with $effect in +layout.svelte and all 7 page components
- Convert $: reactive assignments to $derived() (runes mode requirement)
- Rebuild SPA with fixes (internal/web/dist/index.html updated)
- Add synapbus binary to .gitignore
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add complete Web UI infrastructure:
Go backend:
- REST API handlers for messages, agents, channels (internal/api/)
- SSE hub for real-time event streaming
- Session-to-owner middleware bridging auth sessions to API context
- SPA file server with go:embed for static assets
- GetMessageByID on MessagingService, RevokeKey on AgentService
- Updated router with RouterConfig for full service wiring
Svelte 5 SPA (web/):
- SvelteKit with static adapter for SPA mode
- Tailwind CSS with dark mode (class-based, localStorage persisted)
- API client with auto-redirect on 401
- SSE client with exponential backoff reconnect
- Pages: Login, Dashboard, Conversations, Channels, Agents, Settings
- Components: Sidebar, Header, MessageList, ComposeForm, AgentCard, TraceViewer
- Responsive layout with mobile sidebar toggle
Build:
- Placeholder index.html in internal/web/dist/ for go:embed compilation
- Updated Makefile web target to copy build output
- All existing Go tests pass, CGO_ENABLED=0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add HNSW-based vector search with configurable embedding providers
(OpenAI, Ollama) and automatic FTS5 fallback when no provider is
configured. Background pipeline embeds messages asynchronously on
ingest, stores vectors in a pure-Go HNSW index, and retries on
failure with exponential backoff. The search_messages MCP tool now
supports search_mode (auto/semantic/fulltext) and returns ranked
results with similarity scores. All existing tests continue to pass,
CGO_ENABLED=0 cross-compilation verified.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add task auction lifecycle with full permission enforcement:
- TaskStore (SQLite) for tasks and bids CRUD, expiry, channel cancellation
- SwarmService with PostTask, BidOnTask, AcceptBid, CompleteTask
- MCP tools: post_task, bid_task, accept_bid, complete_task, list_tasks
- ExpiryWorker background goroutine for deadline-based task cancellation
- Channel type enforcement (auction ops only on auction channels)
- Agent cannot bid on own task, only poster accepts bids, only assignee completes
- Wired into main.go with graceful shutdown
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add file attachment support with SHA-256 content-addressable storage,
automatic deduplication, MIME detection, and garbage collection for
orphaned files. Includes MCP tools (upload_attachment, download_attachment,
gc_attachments), REST API endpoints for Web UI, and comprehensive tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add complete auth subsystem with OAuth 2.1 authorization server using
ory/fosite, local user accounts with bcrypt password hashing, session
management, and HTTP handlers for the Web UI.
Components:
- User store with bcrypt hashing (configurable cost, default 12), CRUD,
validation (username 3-64 chars alphanumeric+underscore, password 8-72 bytes)
- Session store with secure random IDs, configurable lifetime (default 24h),
expiration cleanup, and per-user invalidation
- OAuth client store with client_id/secret generation and bcrypt verification
- Fosite storage adapter implementing CoreStorage, TokenRevocationStorage,
and PKCERequestStorage backed by SQLite
- OAuth provider configured with authorization code (PKCE S256 mandatory),
client credentials, refresh token rotation, and token introspection
- HTTP handlers: POST /auth/register, POST /auth/login, POST /auth/logout,
GET /auth/me, PUT /auth/password, GET /oauth/authorize, POST /oauth/token,
POST /oauth/introspect
- Middleware: RequireSession (cookie), RequireBearer (access token),
RequireAuth (either), RequireAdmin (role check)
- Structured auth event logging (login, token issuance, session lifecycle)
- Schema migration 002_auth.sql extending users, oauth_clients, oauth_tokens
tables and adding sessions, oauth_authorization_codes tables
- Initial admin user auto-created on first run with random password printed
to stdout
- All tests pass with CGO_ENABLED=0, zero external runtime dependencies
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>