A cross-platform chat application built with Kotlin Multiplatform. It provides a web app, an Android APK, and optional desktop clients, with a Kotlin backend, Weaviate for vector search, and OpenAI-compatible AI APIs.
- Backend: Kotlin (Ktor), serves API and static web assets. Reads config from project-root
.env. - Frontend: Kotlin/JS WebApp (production build is copied to
backend/staticand served there). - Android: Kotlin Multiplatform Android app; APK can be built and served for download.
- Vector store: Weaviate (run via Docker by
silk.sh). Used for context and file search. - AI: Any OpenAI-compatible API; configure
API_BASE_URL,OPENAI_API_KEY, andAI_MODELin.env. - Workflow: Named, persistent Claude Code agent sessions. Each workflow creates a dedicated chat room with CC mode always active — no need to type
/cc.
Todo is treated as a long-term core module. Any todo-related feature must follow:
- Update/align roadmap first:
docs/todo-roadmap.md - Then implement code changes.
- Write back status/changelog to roadmap after implementation.
Persistent Cursor rule:
.cursor/rules/todo_planning_governance.mdc
All day-to-day operations (build, run, stop, logs, Weaviate) are driven by the silk.sh script in the project root.
| Path | Description |
|---|---|
silk.sh |
Main script: deploy, start/stop, build, logs, Weaviate management. |
.env |
Local config (create from .env.example). Not committed. |
.env.example |
Template and documentation for required/optional env vars. |
backend/ |
Kotlin backend (Ktor), static files, chat history. |
backend/.../agents/ |
Agent framework: AgentRuntime, ACP protocol layer, Claude Code adapter descriptor. |
cc_bridge/ |
ACP Bridge Adapter: external Python process running Claude CLI; connects to backend /agent-bridge via ACP. |
frontend/webApp/ |
Kotlin/JS web frontend. |
frontend/androidApp/ |
Android app; APK output can be copied to backend/static. |
frontend/desktopApp/ |
Desktop client (optional). |
frontend/shared/ |
Shared KMP code for frontends. |
backend/workflows/ |
Workflow data store (workflow_store.json). |
search/ |
Weaviate schema and indexing (e.g. schema.py). |
Configuration is done via a .env file in the project root. The script silk.sh loads it automatically (and strips CRLF line endings).
- Copy the example:
cp .env.example .env - Edit
.envand set at least:- Backend / public URL:
BACKEND_HOST,BACKEND_HTTP_PORT(default8006) - Protocol: set
BACKEND_SCHEME=https(or directly setBACKEND_BASE_URL=https://...) - AI:
OPENAI_API_KEY,API_BASE_URL,AI_MODEL - Weaviate:
WEAVIATE_URL(e.g.http://<host>:8008)
- Backend / public URL:
- Optional: external search (e.g.
SERPAPI_KEY), feature flags. See.env.examplefor comments.
Do not commit .env; it is listed in .gitignore.
Follow these steps to get Silk running using silk.sh. The script expects Java 17, Python 3, and (for Weaviate) Docker. Gradle is used via the project’s wrapper.
cd /path/to/silk # or your repo rootcp .env.example .env
# Edit .env: set BACKEND_HOST, BACKEND_HTTP_PORT, OPENAI_API_KEY, API_BASE_URL, AI_MODEL, WEAVIATE_URLUse your real API base URL and key; set BACKEND_HOST to the IP or hostname other devices will use to reach this machine (e.g. for the web UI and APK download).
This builds the WebApp and APK, frees the ports used by Silk, starts Weaviate (Docker), then starts the backend and the web frontend:
./silk.sh deployWhen it finishes, the script prints the URLs (backend, web UI, APK download). Use ./silk.sh status to confirm all services.
If you have already run deploy or built manually:
./silk.sh start./silk.sh status # Backend, frontend, Weaviate, APK path
./silk.sh logs # Tail backend/frontend logs| Service | Port | Note |
|---|---|---|
| Backend | 8006 | API + static + APK URL |
| Web frontend | 8005 | HTTP server for WebApp |
| Weaviate HTTP | 8008 | Vector DB |
| Weaviate gRPC | 50051 | Vector DB |
If a port is in use, deploy will try to free it; for start, the script may prompt. You can stop everything with ./silk.sh stop.
All commands are run from the project root. silk.sh loads .env automatically.
| Command | Description |
|---|---|
./silk.sh deploy |
Clean ports, build WebApp + APK, start Weaviate, backend, and frontend. |
./silk.sh start |
Start Weaviate, backend, and frontend (builds WebApp if missing). |
./silk.sh stop |
Stop backend, frontend, and Weaviate. |
./silk.sh restart |
Stop then start. |
./silk.sh status |
Show status of backend, frontend, Weaviate, and latest APK. |
./silk.sh logs |
Tail backend and frontend logs. |
./silk.sh build |
Build WebApp only; output is copied to backend/static. |
./silk.sh build-apk |
Build Android APK; copies to backend/static and sets silk.apk link. |
./silk.sh build-all |
Build WebApp and APK. |
./silk.sh weaviate start|stop|status|schema |
Manage Weaviate (Docker) and schema. |
APK download URL (when backend is up): https://<BACKEND_HOST>:8006/api/files/download-apk (or http:// if BACKEND_SCHEME=http).
Run the repository lint gate before sending broad Kotlin or Gradle-script changes:
./gradlew silkLintOnly refresh config/lint/detekt/ baselines with ./gradlew silkLintBaseline when existing findings are intentionally accepted.
Workflows give each user a dedicated Claude Code programming session with its own persistent chat history. Unlike regular chats where you type /cc to enter CC mode, a workflow chat has CC mode always on — every message goes directly to the Claude Code agent.
- Open the Workflow tab in the left navigation bar.
- Click + 创建, enter a name, and confirm.
- Select the workflow to open its chat panel — Claude Code is ready immediately.
- Type any programming task; Claude Code will read, write, and edit files via the Bridge Agent.
- Use standard CC commands (
/new,/cancel,/status,/cd,/session,/compact,/help) inside the workflow chat.
- Creating a workflow automatically creates a chat group behind the scenes and links them together.
- When you open a workflow, the WebSocket connection detects it and silently activates CC mode — no
/ccneeded. - Workflows are per-user; each user's workflow list and sessions are isolated.
- Workflow data is stored in
backend/workflows/workflow_store.json.
| Method | Path | Description |
|---|---|---|
| GET | /api/workflows?userId=... |
List workflows |
| POST | /api/workflows |
Create workflow ({userId, name, description, initialDir}); requires directory trust |
| DELETE | /api/workflows/{id}?userId=... |
Delete workflow |
Before creating a workflow or changing its working directory, the selected directory must be explicitly trusted for the current bridge machine. Trust records are per-user and per-bridge (strict v1: exact bridge ID match). Trusted parent directories automatically cover their children.
| Method | Path | Description |
|---|---|---|
| GET | /users/{userId}/trusted-dirs/check?path=... |
Check if a directory is trusted on the current bridge |
| POST | /users/{userId}/trusted-dirs |
Add trust for a directory ({path}) |
| DELETE | /users/{userId}/trusted-dirs |
Remove trust for a directory ({path}) |
| GET | /users/{userId}/trusted-dirs |
List all trusted directories for the user |
Workflows require a running ACP Bridge Adapter — see CC Bridge below.
Silk supports a Claude Code (CC) mode that lets users interact with a Claude Code CLI from any chat session. This turns Silk into a programming assistant interface — users can ask Claude to read, write, and edit code on the filesystem.
CC mode uses an ACP (Agent Client Protocol) Bridge architecture: the Silk backend does not run the Claude CLI itself. Instead, a separate Python process (cc_bridge/acp_adapter.py) connects to the backend via WebSocket using the ACP JSON-RPC protocol, receives commands, and executes the Claude CLI locally. This decouples the backend deployment from the Claude execution environment.
- ACP Bridge Adapter running and connected to the Silk backend (see CC Bridge below)
- Claude CLI installed on the machine running the adapter (
npm install -g @anthropic-ai/claude-codeor equivalent)
The following environment variables are used by the ACP Bridge Adapter (set on the machine running acp_adapter.py, not the Silk backend):
# Claude CLI binary path (default: auto-detected from PATH)
# CLAUDE_CODE_PATH=claude
# Max tool-call rounds per execution (default: 100)
# CLAUDE_CODE_MAX_TURNS=100
# Per-execution timeout in seconds (default: 36000 = 10 hours)
# CLAUDE_CODE_TIMEOUT=36000
# Max output characters per execution (default: 30000)
# CLAUDE_CODE_MAX_OUTPUT_CHARS=30000In any Silk chat (group or private), send /cc to enter Claude Code mode:
/cc Enter CC mode (new session each time)
<any text> Send as prompt to Claude Code
/exit Exit CC mode, return to normal Silk chat
/new Start a new CC session (reset context)
/session List historical sessions
/session <id> Resume a previous session by ID prefix
/cd <path> Change working directory (creates new session)
/cd Reset to default working directory
/compact Compress session context
/cancel Cancel running task and clear queue
/queue View queued messages
/queue clear Clear the message queue
/status Show current CC state (session, directory, running/idle)
/help Show all CC commands
- Per-user isolation: each user has their own CC state per group; one user entering CC mode does not affect others
- CC responses are private: only the user who activated CC sees the responses; other group members see the user's messages but not CC output
- Message queue: if a task is running, new messages are queued (max 10) and auto-executed when the current task finishes
- Session persistence: CC sessions are managed by the Bridge Agent (
~/.silk/cc_sessions.json); sessions expire after 7 days of inactivity - Permission mode: currently uses
bypassPermissions(all tool operations are allowed without confirmation)
CC mode is implemented in backend/src/main/kotlin/com/silk/backend/agents/:
| Package/File | Responsibility |
|---|---|
agents/core/AgentRuntime.kt |
Command routing, per-user state, message queue, workflow persistence |
agents/core/CommandRouter.kt |
Parse /cc, /new, /status, @agent etc. |
agents/acp/AcpClient.kt |
ACP JSON-RPC client (talks to adapter) |
agents/acp/AcpRegistry.kt |
Manage ACP WebSocket connections per (userId, agentType) |
agents/core/AcpExtensions.kt |
_silk/* extension calls (set_cwd, list_dir, compact, list_local_sessions) |
The integration point is AgentRuntime.handleIfActive() called from ChatServer.broadcast() (in WebSocketConfig.kt).
The Claude CLI runs on a separate machine (or the same machine in a different process) via the ACP Bridge Adapter, which connects to Silk via WebSocket using ACP (JSON-RPC 2.0). This is useful when:
- The backend runs in a container or VM without Claude CLI installed
- You want to run Claude CLI on a machine with direct access to your codebase
- You need to separate the backend deployment from the Claude execution environment
User (browser) ──→ Silk backend ──ACP/WebSocket──→ ACP Adapter (acp_adapter.py) ──→ Claude CLI
The ACP Adapter (cc_bridge/acp_adapter.py) connects to the Silk backend's /agent-bridge WebSocket endpoint, authenticates with a token, and handles ACP requests (session/new, session/prompt, _silk/* extensions) by executing Claude CLI commands locally and streaming results back as session/update notifications.
-
Generate a Bridge Token in the Silk web UI:
- Go to Settings → Claude Code section
- Click Generate Token (or Regenerate Token if one already exists)
- Copy the token
-
Install dependencies on the machine where you want to run Claude CLI:
cd cc_bridge pip install -r requirements.txt # websockets>=12.0
-
Ensure Claude CLI is available on that machine:
claude --version # should print the Claude CLI version -
Configure — create
cc_bridge/.env:BRIDGE_SERVER=<silk-backend-host>:8006 BRIDGE_TOKEN=<your-token> # BRIDGE_WORKING_DIR=/path/to/workdir # optional # BRIDGE_LOG_LEVEL=INFO # optional
-
Start the ACP Bridge Adapter:
cd cc_bridge ./bridge.sh start # background (recommended) # or: python acp_adapter.py --server <host>:8006 --token <token> # foreground
-
Verify connection in the Silk web UI:
- Settings page should show a green status dot with Connected
- Bridge IP displays the IP address of the machine running the adapter
- Click Refresh Status to update the connection status
| Command | Description |
|---|---|
./bridge.sh start |
Start adapter in background |
./bridge.sh stop |
Stop adapter (graceful shutdown) |
./bridge.sh restart |
Restart adapter |
./bridge.sh status |
Check running status |
./bridge.sh logs |
Tail the log file |
| File | Responsibility |
|---|---|
cc_bridge/bridge.sh |
Management script: start/stop/restart/status/logs |
cc_bridge/acp_adapter.py |
ACP server: handles session/prompt, streams updates, _silk/* extensions |
cc_bridge/executor.py |
Claude CLI subprocess management |
cc_bridge/session_manager.py |
Session persistence and lifecycle |
cc_bridge/fs_listing.py |
Directory listing helper (used by _silk/list_dir) |
cc_bridge/requirements.txt |
Python dependencies (websockets>=12.0) |
- Backend only:
./gradlew :backend:run(still need.envand optionally Weaviate). - Web dev:
./gradlew :frontend:webApp:browserDevelopmentRun(dev server; for production use./silk.sh buildthen serve via backend or./silk.sh start). - Env:
silk.shsources.envwith CRLF stripped. Prefer LF line endings in.envto avoid issues.
If the APK build fails with “Unable to delete directory” under frontend/androidApp/build/snapshot/, remove that directory and run ./silk.sh build-apk again.
MIT