@loicngr/kobo 2.1.26 → 2.1.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +7 -4
- package/CHANGELOG.md +15 -0
- package/CONFIGURATION.md +124 -71
- package/CONTRIBUTING.md +1 -1
- package/README.md +1 -1
- package/SECURITY.md +33 -6
- package/dist/mcp-server/kobo-tasks-server.js +36 -1021
- package/dist/mcp-server/managed-mcp-dispatcher.js +960 -0
- package/dist/mcp-server/workspace-dialogue-client.js +26 -1
- package/dist/server/index.js +52 -19
- package/dist/server/middleware/host-check-middleware.js +8 -5
- package/dist/server/middleware/network-auth-middleware.js +51 -29
- package/dist/server/middleware/security-headers-middleware.js +19 -0
- package/dist/server/middleware/traffic-limits-middleware.js +74 -0
- package/dist/server/routes/auth.js +73 -0
- package/dist/server/routes/internal-mcp.js +137 -0
- package/dist/server/routes/mcp-credentials.js +30 -0
- package/dist/server/routes/mcp.js +156 -76
- package/dist/server/routes/workspaces.js +19 -3
- package/dist/server/services/agent/engines/claude-code/resolve-binary.js +1 -1
- package/dist/server/services/agent/orchestrator.js +27 -17
- package/dist/server/services/dev-server-service.js +68 -4
- package/dist/server/services/environment-check-service.js +3 -2
- package/dist/server/services/external-mcp-credentials-service.js +110 -0
- package/dist/server/services/forge/github/provider.js +15 -3
- package/dist/server/services/forge/types.js +8 -0
- package/dist/server/services/internal-mcp-capability-service.js +98 -0
- package/dist/server/services/mcp-connection-info-service.js +1 -1
- package/dist/server/services/memory-mcp-service.js +9 -7
- package/dist/server/services/memory-service.js +15 -0
- package/dist/server/services/network-access-service.js +43 -73
- package/dist/server/services/network-session-service.js +182 -0
- package/dist/server/services/settings-service.js +29 -7
- package/dist/server/services/terminal-websocket-service.js +5 -0
- package/dist/server/services/websocket-service.js +5 -0
- package/dist/server/utils/paths.js +2 -1
- package/dist/server/utils/startup-display.js +1 -2
- package/dist/shared/models.js +6 -0
- package/docker-compose.vps.yml +6 -0
- package/docs/deployment-vps.md +24 -12
- package/docs/getting-started.md +1 -1
- package/docs/troubleshooting.md +1 -1
- package/package.json +14 -14
- package/src/client/dist/pwa/assets/ActivityFeed-CiTe2VUQ.js +2 -0
- package/src/client/dist/pwa/assets/{AutoLoopFinalReviewSettings-DOr41E2Y.js → AutoLoopFinalReviewSettings-v3jXoH_Q.js} +1 -1
- package/src/client/dist/pwa/assets/{ChangelogPage-DOCgZMpn.js → ChangelogPage-C5KjAOMG.js} +1 -1
- package/src/client/dist/pwa/assets/{ClosePopup-CRV2hxHS.js → ClosePopup-rU8Bm-mC.js} +1 -1
- package/src/client/dist/pwa/assets/ComparisonPanel-XXyzPEzW.js +2 -0
- package/src/client/dist/pwa/assets/CreatePage-MYCexRJu.js +2 -0
- package/src/client/dist/pwa/assets/{DashboardPage-dBpJaQSb.js → DashboardPage-DyhUu26C.js} +1 -1
- package/src/client/dist/pwa/assets/DiffViewer-CvsmC9d5.js +8 -0
- package/src/client/dist/pwa/assets/{DocumentsPanel-AqLx0MzB.js → DocumentsPanel-ItndGxeB.js} +1 -1
- package/src/client/dist/pwa/assets/{DrawerToggleButton-BLWaFgh0.js → DrawerToggleButton-DfzS_CD8.js} +1 -1
- package/src/client/dist/pwa/assets/GitPanel-C1ybi9bZ.js +3 -0
- package/src/client/dist/pwa/assets/{GitPanel-CRaLJzjc.css → GitPanel-yHvU38dp.css} +1 -1
- package/src/client/dist/pwa/assets/{HealthPage-DeryVLyz.js → HealthPage-C1u35ANL.js} +1 -1
- package/src/client/dist/pwa/assets/MainLayout-BEAGPqei.js +2 -0
- package/src/client/dist/pwa/assets/{MemoryPanel-B34DENtz.js → MemoryPanel-CZzI7_nY.js} +1 -1
- package/src/client/dist/pwa/assets/MemoryProposalList-DqNTycY1.js +1 -0
- package/src/client/dist/pwa/assets/{QBadge-CW3Lw-kL.js → QBadge-DiwbRpte.js} +1 -1
- package/src/client/dist/pwa/assets/{QBanner-BT2ZemYu.js → QBanner-Cw89HSjk.js} +1 -1
- package/src/client/dist/pwa/assets/QBtn-kfhHFy7Q.js +1 -0
- package/src/client/dist/pwa/assets/{QBtnDropdown-BPcK_rVs.js → QBtnDropdown-D7ml7zHo.js} +1 -1
- package/src/client/dist/pwa/assets/{QBtnGroup-CnM4vSJA.js → QBtnGroup-Bioxjp9q.js} +1 -1
- package/src/client/dist/pwa/assets/{QBtnToggle-DccOOtbh.js → QBtnToggle-Bod-x9im.js} +1 -1
- package/src/client/dist/pwa/assets/{QChip-Be16M4Ig.js → QChip-DvhtPv_L.js} +1 -1
- package/src/client/dist/pwa/assets/{QExpansionItem-CpwQ8L_F.js → QExpansionItem-BVb067oc.js} +1 -1
- package/src/client/dist/pwa/assets/{QItemSection-MdJ1_ZK7.js → QItemSection-ahqRK4JF.js} +1 -1
- package/src/client/dist/pwa/assets/{QList-Cx1UfaUm.js → QList-CAUl0v66.js} +1 -1
- package/src/client/dist/pwa/assets/{QMarkupTable-UhP7fVUp.js → QMarkupTable-B4LLAly-.js} +1 -1
- package/src/client/dist/pwa/assets/{QPage-CqkGHokx.js → QPage-DIy_mRoT.js} +1 -1
- package/src/client/dist/pwa/assets/{QScrollArea-BkNSVl7s.js → QScrollArea-CUDWkEHh.js} +1 -1
- package/src/client/dist/pwa/assets/QSelect-DOnv_ry0.js +1 -0
- package/src/client/dist/pwa/assets/{QSpinnerDots-xdWyaE1i.js → QSpinnerDots-Bea6hAuJ.js} +1 -1
- package/src/client/dist/pwa/assets/{QTooltip-Dp8fitHV.js → QTooltip-B5QJIU3p.js} +1 -1
- package/src/client/dist/pwa/assets/{SchedulePanel-Ck8LKDCa.js → SchedulePanel-IJOcrHgk.js} +1 -1
- package/src/client/dist/pwa/assets/{SearchPage-BAUZg1zq.js → SearchPage-BpTRWtne.js} +1 -1
- package/src/client/dist/pwa/assets/{SettingsPage-Dcq1Jeoo.css → SettingsPage-B4rmd2WX.css} +1 -1
- package/src/client/dist/pwa/assets/SettingsPage-CFaRN9Pk.js +9 -0
- package/src/client/dist/pwa/assets/{SplitWorkspacePage-CH8OHmtn.js → SplitWorkspacePage-BZ8wN4ii.js} +1 -1
- package/src/client/dist/pwa/assets/{TerminalPanel-Dz9EE-Ph.css → TerminalPanel-BcbwuFVR.css} +1 -1
- package/src/client/dist/pwa/assets/TerminalPanel-pY-RGBb6.js +16 -0
- package/src/client/dist/pwa/assets/{ToolCallItem-CLtGTV6w.js → ToolCallItem-C9ksVseJ.js} +4 -4
- package/src/client/dist/pwa/assets/{TouchPan-9SH2dx6m.js → TouchPan-DRynDIve.js} +1 -1
- package/src/client/dist/pwa/assets/{TourReplayButton-Dw4sGf9B.js → TourReplayButton-D4h1QR6C.js} +1 -1
- package/src/client/dist/pwa/assets/WorkspaceAttentionLabels-Bkj2DhOn.js +1 -0
- package/src/client/dist/pwa/assets/WorkspacePage-BTJnap9a.js +4 -0
- package/src/client/dist/pwa/assets/{browser-CC4W8r76.js → browser-BcOi2ES2.js} +2 -2
- package/src/client/dist/pwa/assets/build-path-tree-mDco3pi7.js +1 -0
- package/src/client/dist/pwa/assets/custom-sounds-T5HKzrWh.js +1 -0
- package/src/client/dist/pwa/assets/de-suqWUSXa.js +17 -0
- package/src/client/dist/pwa/assets/detached-fullscreen-CHqMxB-8.js +1 -0
- package/src/client/dist/pwa/assets/dom-CRPVbmiy.js +2 -0
- package/src/client/dist/pwa/assets/ecl-94qehhXe.js +1 -0
- package/src/client/dist/pwa/assets/{editor.api-BwfxvQ88.js → editor.api-CRrihXg2.js} +9 -9
- package/src/client/dist/pwa/assets/editor.worker-xrHNhPSq.js +33 -0
- package/src/client/dist/pwa/assets/{efforts-B3I7w5bs.js → efforts-C-p9DzkL.js} +2 -2
- package/src/client/dist/pwa/assets/es-Dcptbz5U.js +17 -0
- package/src/client/dist/pwa/assets/expand-template-gIwrPbeS.js +1 -0
- package/src/client/dist/pwa/assets/{format-CJIzi3Vf.js → format-DeBnwmgW.js} +48 -48
- package/src/client/dist/pwa/assets/{formatters-DQ8cP7nO.js → formatters-CxZZ_WTb.js} +1 -1
- package/src/client/dist/pwa/assets/fr-Db70bqVq.js +17 -0
- package/src/client/dist/pwa/assets/{freemarker2-DbpVO-cL.js → freemarker2-h7OLlqTn.js} +1 -1
- package/src/client/dist/pwa/assets/{handlebars-BHve0PpA.js → handlebars-BCWmi1-q.js} +1 -1
- package/src/client/dist/pwa/assets/{html-BhUkdFPz.js → html-MUMpfUBd.js} +1 -1
- package/src/client/dist/pwa/assets/i18n-DLprfNLs.js +1 -0
- package/src/client/dist/pwa/assets/index-C0MApoXN.css +1 -0
- package/src/client/dist/pwa/assets/index-DLoUeovT.js +20 -0
- package/src/client/dist/pwa/assets/it-Cloo58Nn.js +17 -0
- package/src/client/dist/pwa/assets/{javascript-BLAorPa3.js → javascript-CHDwijEy.js} +1 -1
- package/src/client/dist/pwa/assets/{liquid-CJGF-h-f.js → liquid-dFrnLevt.js} +1 -1
- package/src/client/dist/pwa/assets/{mdx-Cm0oNz_l.js → mdx-BHS7JVD4.js} +1 -1
- package/src/client/dist/pwa/assets/monaco-contributions-DCWZe7nX.js +53 -0
- package/src/client/dist/pwa/assets/{monaco.contribution-hr9s26Ud.js → monaco.contribution-Dx0gcAn4.js} +2 -2
- package/src/client/dist/pwa/assets/network-auth-DDMAzwYH.js +1 -0
- package/src/client/dist/pwa/assets/{notify-theme-EcbxuH_8.js → notify-theme-JuVT96rq.js} +1 -1
- package/src/client/dist/pwa/assets/{permissionModes-DLWiBfdb.js → permissionModes-D-Nexnoo.js} +1 -1
- package/src/client/dist/pwa/assets/{private.use-form-DY1BkePL.js → private.use-form-BcspuzM9.js} +1 -1
- package/src/client/dist/pwa/assets/{project-color-vDuTaTJn.js → project-color-DihsE4yN.js} +1 -1
- package/src/client/dist/pwa/assets/{python-BEjbzFAQ.js → python-BtjZnK9y.js} +1 -1
- package/src/client/dist/pwa/assets/{razor-BJPT7Wxx.js → razor-DBcOGz0a.js} +1 -1
- package/src/client/dist/pwa/assets/reactivity.esm-bundler-Dplx1ILy.js +1 -0
- package/src/client/dist/pwa/assets/render-chat-markdown-C9ihAYBt.js +67 -0
- package/src/client/dist/pwa/assets/runtime-core.esm-bundler-BAUgNzMK.js +1 -0
- package/src/client/dist/pwa/assets/{typescript-DPqM46Ef.js → typescript-B320c7wU.js} +1 -1
- package/src/client/dist/pwa/assets/{use-checkbox-v4aAbE6K.js → use-checkbox-DUxgXR4e.js} +1 -1
- package/src/client/dist/pwa/assets/{use-id-BrdYXce0.js → use-id-B7ieAx2m.js} +1 -1
- package/src/client/dist/pwa/assets/use-is-mobile-CHmaewI1.js +1 -0
- package/src/client/dist/pwa/assets/{use-search-index-status-BwwrB410.js → use-search-index-status-B95GPaJP.js} +1 -1
- package/src/client/dist/pwa/assets/use-slide-transition-BJh9xGMa.js +1 -0
- package/src/client/dist/pwa/assets/use-tours-CU5oA7cz.css +1 -0
- package/src/client/dist/pwa/assets/use-tours-C_5R1Y5D.js +2 -0
- package/src/client/dist/pwa/assets/{use-worktree-restore-tzd2FESU.js → use-worktree-restore-Cj8eGE9s.js} +1 -1
- package/src/client/dist/pwa/assets/{workspace-templates-CubzsZUU.js → workspace-templates-B9UETKER.js} +1 -1
- package/src/client/dist/pwa/assets/{xml-C6SVzw5_.js → xml-uK8LK4OB.js} +1 -1
- package/src/client/dist/pwa/assets/{yaml-OpCqnv4g.js → yaml-B2D1l_tz.js} +1 -1
- package/src/client/dist/pwa/index.html +10 -10
- package/src/client/dist/pwa/sw.js +1 -1
- package/src/mcp-server/README.md +13 -19
- package/src/mcp-server/kobo-tasks-server.ts +42 -1146
- package/src/mcp-server/managed-mcp-dispatcher.ts +1071 -0
- package/src/mcp-server/workspace-dialogue-client.ts +26 -1
- package/src/client/dist/pwa/assets/ActivityFeed-DfYrVNEh.js +0 -2
- package/src/client/dist/pwa/assets/ComparisonPanel-b5nTBjK6.js +0 -2
- package/src/client/dist/pwa/assets/CreatePage-B7VPHEqm.js +0 -2
- package/src/client/dist/pwa/assets/DiffViewer-BLQz2Qyx.js +0 -8
- package/src/client/dist/pwa/assets/GitPanel-Ba7ltCsM.js +0 -3
- package/src/client/dist/pwa/assets/MainLayout-B2XvjdWi.js +0 -2
- package/src/client/dist/pwa/assets/MemoryProposalList-BpN_OU8J.js +0 -1
- package/src/client/dist/pwa/assets/QBtn-BUSdPaf4.js +0 -1
- package/src/client/dist/pwa/assets/QSelect-DrLpbvcr.js +0 -1
- package/src/client/dist/pwa/assets/SettingsPage-Cj6kSVT5.js +0 -9
- package/src/client/dist/pwa/assets/TerminalPanel-CBmZ0IzQ.js +0 -16
- package/src/client/dist/pwa/assets/WorkspaceAttentionLabels-wd_sObJa.js +0 -1
- package/src/client/dist/pwa/assets/WorkspacePage-D4ODPOG-.js +0 -4
- package/src/client/dist/pwa/assets/build-path-tree-BBuyB-my.js +0 -1
- package/src/client/dist/pwa/assets/custom-sounds-BbPNRzAs.js +0 -1
- package/src/client/dist/pwa/assets/de-D9VzPDGF.js +0 -17
- package/src/client/dist/pwa/assets/detached-fullscreen-Du3TcYdX.js +0 -1
- package/src/client/dist/pwa/assets/dom-BtYTvLeN.js +0 -2
- package/src/client/dist/pwa/assets/ecl-D05T4iGw.js +0 -1
- package/src/client/dist/pwa/assets/editor.worker-BLJF_oQx.js +0 -33
- package/src/client/dist/pwa/assets/es-3R4MJuTt.js +0 -17
- package/src/client/dist/pwa/assets/expand-template-Ci9UjnxZ.js +0 -1
- package/src/client/dist/pwa/assets/fr-DXwDVnJ4.js +0 -17
- package/src/client/dist/pwa/assets/i18n-CGLQAADf.js +0 -1
- package/src/client/dist/pwa/assets/index-C8zAZ-k-.css +0 -1
- package/src/client/dist/pwa/assets/index-CNcXBpzz.js +0 -20
- package/src/client/dist/pwa/assets/it-T9AjnG42.js +0 -17
- package/src/client/dist/pwa/assets/monaco-contributions-nBg6wf05.js +0 -53
- package/src/client/dist/pwa/assets/network-auth-C850jGfI.js +0 -1
- package/src/client/dist/pwa/assets/reactivity.esm-bundler-DY1JkAEA.js +0 -1
- package/src/client/dist/pwa/assets/render-chat-markdown-CafzCcmu.js +0 -69
- package/src/client/dist/pwa/assets/runtime-core.esm-bundler-Bqg71Vll.js +0 -1
- package/src/client/dist/pwa/assets/use-is-mobile-CDB_rzM9.js +0 -1
- package/src/client/dist/pwa/assets/use-slide-transition-B_Nu6u-t.js +0 -1
- package/src/client/dist/pwa/assets/use-tours-B0KtCS9w.js +0 -2
- package/src/client/dist/pwa/assets/use-tours-CTZuBZOi.css +0 -1
package/AGENTS.md
CHANGED
|
@@ -6,11 +6,13 @@ Guidance for AI coding agents (Claude Code, Cursor, etc.) working on this reposi
|
|
|
6
6
|
|
|
7
7
|
**Kōbō** (工房, Japanese for "workshop") orchestrates Claude Code and OpenAI Codex agents across isolated git worktrees. Each "workspace" is a self-contained mission with its own worktree, branch, agent sessions, optional dev server, optional Notion/Sentry context, and a dedicated MCP tools server. A Vue 3 UI lets the human track progress, read live agent output, review Git changes, and manage the lifecycle. A workspace can switch engines through a handoff to a fresh session while preserving its worktree and history.
|
|
8
8
|
|
|
9
|
-
Single-user dev tool, local by default. The server binds `127.0.0.1` unless the opt-in "network access" setting is enabled
|
|
9
|
+
Single-user dev tool, local by default. The server binds `127.0.0.1` unless the opt-in "network access" setting is enabled. Operator HTTP access uses the network token or a 12-hour HttpOnly browser session; browsers use 60-second single-use path-bound tickets for WebSocket upgrades, never the operator token in the URL or localStorage. Behind-a-reverse-proxy mode also gates loopback operator requests. Rotation, network disable and proxy-mode changes revoke sessions, tickets and active WebSockets. `/api/health` stays exempt. Host/Origin checks apply separately; public proxy origin must be declared explicitly. No multi-tenant concerns.
|
|
10
|
+
|
|
11
|
+
External `/api/mcp` and global stdio require dedicated hashed credentials with tool/workspace grants, expiry and revocation, even on loopback. Manage them through operator-only `/api/mcp-credentials`; global stdio uses `KOBO_MCP_TOKEN`. Managed workspace stdio uses per-launch `KOBO_MCP_SESSION_TOKEN` through OS-loopback-only `/api/internal-mcp`, never the operator token or direct SQLite writes. The backend enforces Plan/read-only permissions and revokes capabilities when stopping begins. Keep report/progress exceptions narrowly scoped. See [SECURITY.md](./SECURITY.md).
|
|
10
12
|
|
|
11
13
|
## Tech stack
|
|
12
14
|
|
|
13
|
-
**Backend**: Node.js ≥
|
|
15
|
+
**Backend**: Node.js ≥ 26.12.1, Hono (HTTP), `ws` (WebSocket), better-sqlite3 (WAL mode), nanoid, `@modelcontextprotocol/sdk`. TypeScript throughout, `tsx` for dev, `tsc` for production build.
|
|
14
16
|
|
|
15
17
|
**Frontend**: Vue 3, Quasar 2, Pinia, vue-router, marked + dompurify for markdown rendering. Vite via `@quasar/app-vite`, built and served as a Progressive Web App in production.
|
|
16
18
|
|
|
@@ -103,7 +105,8 @@ src/
|
|
|
103
105
|
│ ├── pages/ # WorkspacePage, CreatePage, SettingsPage
|
|
104
106
|
│ └── router/
|
|
105
107
|
├── mcp-server/ # standalone MCP server spawned per workspace
|
|
106
|
-
│ ├── kobo-tasks-server.ts #
|
|
108
|
+
│ ├── kobo-tasks-server.ts # stdio bridge; forwards discovery/calls to authenticated backend
|
|
109
|
+
│ ├── managed-mcp-dispatcher.ts # workspace tool definitions/dispatch, executed in backend
|
|
107
110
|
│ └── kobo-tasks-handlers.ts # pure handlers (list_tasks, mark_task_done)
|
|
108
111
|
├── shared/ # model catalogues, prompts, dialogue contracts, shared utilities
|
|
109
112
|
└── __tests__/ # backend Vitest suites; client tests live under client/src/__tests__/
|
|
@@ -292,7 +295,7 @@ also bypasses the auto-loop next-iteration UI path; normal backend immediate
|
|
|
292
295
|
message delivery pauses a ready loop. Do not flush existing queues on toggle,
|
|
293
296
|
remove compaction/permission/handoff guards, or queue rejected forced sends.
|
|
294
297
|
|
|
295
|
-
`POST /api/mcp` exposes stateless Streamable HTTP discovery/dialogue tools, behind
|
|
298
|
+
`POST /api/mcp` exposes stateless Streamable HTTP discovery/dialogue tools, behind Host/Origin, network enablement and dedicated MCP credential gates. The global stdio server forwards dialogue calls through this backend so agent runtime ownership remains centralized. `workspace-message-service.ts` shares delivery with WebSocket chat.
|
|
296
299
|
|
|
297
300
|
Optional `send_workspace_message.idempotency_key` uses `mcp_message_requests` (migration v43). Reserve before dispatch, preserve fingerprints and terminal outcomes, and never automatically resend an unfinished request after restart. The user event and accepted receipt commit in one SQLite transaction; broadcast follows commit. Dispatch may precede persistence, so interrupted requests are explicitly `delivery_unknown`, not an exactly-once execution promise. The backend alone calls `reconcileMessageRequests` on startup. History retention does not delete the ledger; workspace deletion cascades it.
|
|
298
301
|
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,21 @@ All notable changes to Kōbō are documented here. The format is based on
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/). Each release is an `## <version>`
|
|
5
5
|
section — the in-app "What's new" dialog reads this file.
|
|
6
6
|
|
|
7
|
+
## 2.1.29
|
|
8
|
+
|
|
9
|
+
- chore: upgrade node and dependencies and fix dev server readiness
|
|
10
|
+
|
|
11
|
+
## 2.1.28
|
|
12
|
+
|
|
13
|
+
- fix(ci): authenticate packaged mcp smoke tests
|
|
14
|
+
- fix(security): harden authentication and mcp access
|
|
15
|
+
- feat(models): Add Haiku 5.5
|
|
16
|
+
|
|
17
|
+
## 2.1.27
|
|
18
|
+
|
|
19
|
+
- fix(security): harden authentication and mcp access
|
|
20
|
+
- feat(models): Add Haiku 5.5
|
|
21
|
+
|
|
7
22
|
## 2.1.26
|
|
8
23
|
|
|
9
24
|
- feat: switch Claude and Codex accounts with ccswap
|
package/CONFIGURATION.md
CHANGED
|
@@ -887,11 +887,28 @@ destination worktree and sends file/image references to the agent and chat.
|
|
|
887
887
|
Keyed retries include attachment identity and never upload or send twice. See
|
|
888
888
|
[Sending files and images](src/mcp-server/README.md#sending-files-and-images).
|
|
889
889
|
|
|
890
|
-
|
|
890
|
+
Every external MCP client, including loopback and global stdio clients, must use
|
|
891
|
+
a dedicated MCP key. The operator token and browser session cookie are not accepted
|
|
892
|
+
by `/api/mcp`. Send the MCP key as `Authorization: Bearer <key>`. The endpoint retains the same Host/Origin, network-access and
|
|
893
|
+
reverse-proxy policy. No network setting changes automatically.
|
|
894
|
+
|
|
895
|
+
Keys are independent, stored only as hashes and have explicit tool and workspace
|
|
896
|
+
grants, optional expiration and individual revocation. The default tool grant is
|
|
897
|
+
read-only; writes and destructive tools require an explicit grant. Each key must
|
|
898
|
+
select workspace IDs or deliberately grant all workspaces. An MCP key cannot
|
|
899
|
+
authenticate to operator REST, terminal or credential-management endpoints.
|
|
900
|
+
|
|
901
|
+
An authenticated operator manages credentials through `/api/mcp-credentials`:
|
|
902
|
+
GET lists metadata and available tools; POST accepts `name`, optional `tools`,
|
|
903
|
+
`workspaceIds` or `allWorkspaces: true`, and optional ISO `expiresAt`; DELETE
|
|
904
|
+
`/api/mcp-credentials/<id>` revokes one key. Creation returns the raw `token` once.
|
|
905
|
+
Do not send that token to logs, commit it, or reuse it as the operator credential.
|
|
891
906
|
|
|
892
907
|
See [Connect an external LLM](src/mcp-server/README.md#connect-an-external-llm) for connection examples, tool arguments, cursor polling and authentication details.
|
|
893
908
|
|
|
894
|
-
The **External LLM access (MCP)** panel within global Network access settings
|
|
909
|
+
The **External LLM access (MCP)** panel within global Network access settings
|
|
910
|
+
provides HTTP/stdio configuration templates. Supply the dedicated MCP key for the
|
|
911
|
+
intended client. Client names are display labels, not permission identities.
|
|
895
912
|
|
|
896
913
|
External senders can supply `idempotency_key` once per intended message and reuse it on retries. The durable receipt survives backend restarts and event retention. An uncertain delivery is explicitly reported and never automatically sent again; see the MCP guide for response codes and limitations.
|
|
897
914
|
|
|
@@ -1058,8 +1075,9 @@ To disable network access, toggle it off and restart again.
|
|
|
1058
1075
|
|
|
1059
1076
|
### The network access token
|
|
1060
1077
|
|
|
1061
|
-
When network access is enabled,
|
|
1062
|
-
|
|
1078
|
+
When network access is enabled, remote API and WebSocket access requires
|
|
1079
|
+
operator authentication. The shared operator token opens a browser session;
|
|
1080
|
+
external MCP clients use separate scoped credentials.
|
|
1063
1081
|
|
|
1064
1082
|
- **Auto-generated**: Kōbō generates a random token the first time you enable
|
|
1065
1083
|
the feature. You never have to type one in.
|
|
@@ -1075,11 +1093,12 @@ non-loopback WebSocket connection must supply a shared token.
|
|
|
1075
1093
|
|
|
1076
1094
|
**Option A: QR code (recommended for phones)**
|
|
1077
1095
|
|
|
1078
|
-
The Settings panel shows a QR code
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1096
|
+
The Settings panel shows a QR code using a URL fragment (`#token=<token>`),
|
|
1097
|
+
which browsers do not send in HTTP requests. The client immediately removes the
|
|
1098
|
+
fragment and exchanges the token for a 12-hour HttpOnly, SameSite=Strict session
|
|
1099
|
+
cookie (Secure for a configured HTTPS proxy). The operator token is not retained in localStorage.
|
|
1100
|
+
Previously stored tokens are removed during migration. Use QR links only on
|
|
1101
|
+
trusted devices; do not publish or bookmark a credential-bearing link.
|
|
1083
1102
|
|
|
1084
1103
|
**Option B: manual URL**
|
|
1085
1104
|
|
|
@@ -1087,22 +1106,27 @@ session. The token is stored in the browser's `localStorage` under
|
|
|
1087
1106
|
`http://<lan-ip>:<port>/`).
|
|
1088
1107
|
2. Open it on the remote device.
|
|
1089
1108
|
3. A login dialog appears: paste the token from the Settings panel and confirm.
|
|
1090
|
-
4. The
|
|
1109
|
+
4. The HttpOnly session cookie authenticates subsequent visits until expiry or revocation.
|
|
1091
1110
|
|
|
1092
1111
|
**Host machine (localhost)**: connect to `http://localhost:<port>` as usual.
|
|
1093
1112
|
No token is needed unless **Behind a reverse proxy** is enabled.
|
|
1094
1113
|
|
|
1095
1114
|
### Token transport
|
|
1096
1115
|
|
|
1097
|
-
| Connection type |
|
|
1116
|
+
| Connection type | Authentication |
|
|
1098
1117
|
|---|---|
|
|
1099
|
-
|
|
|
1100
|
-
|
|
|
1101
|
-
|
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1118
|
+
| Browser API requests | HttpOnly session cookie after login |
|
|
1119
|
+
| Operator scripts / REST | `X-Kobo-Token: <operator-token>` header |
|
|
1120
|
+
| External MCP HTTP (`/api/mcp`) | Dedicated MCP key as `Authorization: Bearer <key>` |
|
|
1121
|
+
| Browser WebSocket connections | Short-lived, single-use ticket in the upgrade URL, bound to its WS path |
|
|
1122
|
+
|
|
1123
|
+
The browser handles session and ticket exchanges automatically. Tickets expire
|
|
1124
|
+
after 60 seconds and cannot be replayed, reused for a different terminal, or used
|
|
1125
|
+
after their session expires. The permanent operator token is no longer accepted
|
|
1126
|
+
in a WebSocket query string. Rotation, disabling network access or changing proxy
|
|
1127
|
+
mode invalidates browser sessions, pending tickets and existing main/terminal
|
|
1128
|
+
WebSocket connections. Agent processes are not stopped by credential revocation.
|
|
1129
|
+
Server restart also expires browser sessions.
|
|
1106
1130
|
|
|
1107
1131
|
The IP address used for the loopback exemption is taken **from the OS socket**,
|
|
1108
1132
|
never from forwarded headers (`X-Forwarded-For` etc.), so a remote client cannot
|
|
@@ -1154,19 +1178,15 @@ Practical consequences:
|
|
|
1154
1178
|
count as the real interface. In development the Quasar dev server is the one
|
|
1155
1179
|
exception, since it proxies to the backend and so never matches the `Host`;
|
|
1156
1180
|
the `dev` npm script declares it through `KOBO_DEV_CLIENT_ORIGIN`.
|
|
1157
|
-
- **Behind-a-reverse-proxy mode
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
mode also disables the loopback exemption, so every `/api/*` request has to
|
|
1162
|
-
carry the token — but the SPA itself is served outside `/api/*` and behind no
|
|
1163
|
-
token, so without a declared hostname a rebinding page can be served the real
|
|
1164
|
-
interface and ask the user to paste their token into it.
|
|
1181
|
+
- **Behind-a-reverse-proxy mode requires a declared public hostname.** Set
|
|
1182
|
+
`KOBO_NETWORK_ACCESS_PROXY_HOST`; missing or invalid configuration rejects
|
|
1183
|
+
public requests. Internal loopback clients remain reachable but still require
|
|
1184
|
+
authentication. The bundled proxy Compose files configure this explicitly.
|
|
1165
1185
|
|
|
1166
1186
|
#### `KOBO_NETWORK_ACCESS_PROXY_HOST`
|
|
1167
1187
|
|
|
1168
|
-
Set it to the
|
|
1169
|
-
|
|
1188
|
+
Set it to the public origin your proxy serves Kōbō under. This is required in
|
|
1189
|
+
behind-a-reverse-proxy mode:
|
|
1170
1190
|
|
|
1171
1191
|
```yaml
|
|
1172
1192
|
environment:
|
|
@@ -1175,9 +1195,33 @@ environment:
|
|
|
1175
1195
|
- KOBO_NETWORK_ACCESS_PROXY_HOST=kobo.example.com
|
|
1176
1196
|
```
|
|
1177
1197
|
|
|
1178
|
-
A
|
|
1179
|
-
|
|
1180
|
-
|
|
1198
|
+
A bare hostname means HTTPS. For a nonstandard port, set the complete origin,
|
|
1199
|
+
e.g. `https://kobo.example.com:8443`. Browser Origin checks compare the scheme,
|
|
1200
|
+
hostname and port exactly. Local HTTP proxy staging must explicitly declare
|
|
1201
|
+
`http://kobo.localhost`. Paths, credentials, query strings and fragments are
|
|
1202
|
+
invalid. Loopback healthchecks and authenticated internal calls remain reachable.
|
|
1203
|
+
Leaving this variable unset rejects public proxy traffic.
|
|
1204
|
+
|
|
1205
|
+
### Browser response protections
|
|
1206
|
+
|
|
1207
|
+
The server sends `Content-Security-Policy: frame-ancestors 'self'` and
|
|
1208
|
+
`X-Frame-Options: SAMEORIGIN`, preserving Kōbō's split panes while blocking
|
|
1209
|
+
embedding by another site. It also sends `X-Content-Type-Options: nosniff`,
|
|
1210
|
+
`Referrer-Policy: no-referrer` and `Cache-Control: no-store` for API responses.
|
|
1211
|
+
The public HTTPS Compose examples add one-year HSTS at Traefik, without applying
|
|
1212
|
+
it to subdomains or HTTP-only local staging. Kōbō does not trust forwarded headers
|
|
1213
|
+
to decide whether a connection is HTTPS. A broader script/style CSP is not enabled;
|
|
1214
|
+
it needs separate compatibility testing with Quasar and Monaco.
|
|
1215
|
+
|
|
1216
|
+
Application limits apply per OS peer address (forwarded addresses are not trusted):
|
|
1217
|
+
3,000 API requests per minute and 20 login attempts per minute. Requests exceeding
|
|
1218
|
+
these limits receive HTTP 429. MCP permits 32 concurrent requests, with at most
|
|
1219
|
+
four bodies larger than 1 MiB or of unknown/chunked length; ordinary attachment
|
|
1220
|
+
uploads also have four slots. Authentication runs before body buffering. Main
|
|
1221
|
+
WebSocket messages are capped at 1 MiB, terminal messages at 128 KiB; sockets
|
|
1222
|
+
have per-peer and global caps and inbound message-rate limits. Behind a proxy,
|
|
1223
|
+
clients share the proxy peer's bucket, so configure client-IP limits at the proxy
|
|
1224
|
+
for deployments with many simultaneous clients.
|
|
1181
1225
|
|
|
1182
1226
|
### Security caveats
|
|
1183
1227
|
|
|
@@ -1249,7 +1293,7 @@ and [project/skills operations guide](./docs/vps-projects-and-skills.md).
|
|
|
1249
1293
|
|
|
1250
1294
|
### The image
|
|
1251
1295
|
|
|
1252
|
-
Multi-stage `Dockerfile`, `node:
|
|
1296
|
+
Multi-stage `Dockerfile`, `node:26.12.1-slim` base:
|
|
1253
1297
|
|
|
1254
1298
|
- **Build stage**: installs root, client, and PWA deps, then runs `npm run build` (client via Quasar, server via `tsc`).
|
|
1255
1299
|
- **Runtime stage**: production deps only, plus OS tooling the agents and forge CLIs need — `git`, `openssh-client` + `openssh-server`, `ripgrep`, `fd-find`, `jq`, `curl`, Python + build tools, the Docker CLI, Compose and Buildx plugins (talk to a mounted host socket, see [Volumes](#volumes)), netcat (`nc`), `gh`, `glab`, `tmux`, `vim`/`nano`, and more for interactive shell use.
|
|
@@ -1300,7 +1344,7 @@ retrieved once — see [Token / login flow](#token--login-flow).
|
|
|
1300
1344
|
| `${HOME}/.claude.json:/root/.claude.json` | RW | Claude Code auth + MCP server registrations. **Must already exist as a file on the host** (run `claude /login` locally first if it doesn't) — Docker silently creates an empty *directory* instead of erroring on a missing bind-mount source, which breaks auth in a confusing way. |
|
|
1301
1345
|
| `${HOME}/.claude:/root/.claude` | RW | Claude Code's full state directory (skills/plugins cache, session transcripts, memory) — Claude Code writes into this tree during normal operation. |
|
|
1302
1346
|
| `${HOME}/.codex:/root/.codex` | RW | Codex's full state directory (`auth.json`, `config.toml`). Harmless to mount even if you only use Claude Code. |
|
|
1303
|
-
| `/var/run/docker.sock:/var/run/docker.sock` | RW,
|
|
1347
|
+
| `/var/run/docker.sock:/var/run/docker.sock` | RW, opt-in in both `example.yml` and `vps.yml` | Lets the dev-server panel start/stop/tail logs for your projects' own `docker compose` stacks. **DANGER**: grants the container root-equivalent control over the host — anyone who can run a command inside `kobo` can spawn a privileged container that mounts the host filesystem. Leave this mount commented out unless required. |
|
|
1304
1348
|
|
|
1305
1349
|
### Ports
|
|
1306
1350
|
|
|
@@ -1316,25 +1360,32 @@ reachable, matching the real production posture.
|
|
|
1316
1360
|
|
|
1317
1361
|
### Token / login flow
|
|
1318
1362
|
|
|
1319
|
-
All four files pre-enable network access via
|
|
1320
|
-
|
|
1363
|
+
All four files pre-enable network access via environment variables. Startup logs
|
|
1364
|
+
never contain the token. Retrieve it deliberately from a trusted local terminal:
|
|
1321
1365
|
|
|
1322
1366
|
```bash
|
|
1323
|
-
docker compose -f <compose-file>
|
|
1367
|
+
docker compose -f <compose-file> exec kobo node -e 'const fs = require("node:fs"); console.log(JSON.parse(fs.readFileSync(process.env.KOBO_HOME + "/settings.json", "utf8")).global.networkAccessToken)'
|
|
1324
1368
|
```
|
|
1325
1369
|
|
|
1326
|
-
Open
|
|
1327
|
-
|
|
1370
|
+
Open the plain application URL and paste the token into its login dialog. Do not
|
|
1371
|
+
put the token in a URL, command argument, log collector or shared transcript.
|
|
1372
|
+
For an npm installation, read `networkAccessToken` from your private
|
|
1373
|
+
`$KOBO_HOME/settings.json` (default `~/.config/kobo/settings.json`).
|
|
1374
|
+
Kōbō restricts its home to mode `0700` and settings, temporary settings and
|
|
1375
|
+
settings backups to `0600`, including existing files on startup or the next disk read.
|
|
1376
|
+
|
|
1377
|
+
Existing logs from older releases may still contain a valid token. After upgrading,
|
|
1378
|
+
rotate it from Settings and apply your log-retention policy to retained copies.
|
|
1379
|
+
Kōbō does not delete historical logs automatically.
|
|
1328
1380
|
|
|
1329
1381
|
### Quick local test — `docker-compose.local.yml`
|
|
1330
1382
|
|
|
1331
1383
|
```bash
|
|
1332
1384
|
docker build -t kobo:local . # once
|
|
1333
1385
|
docker compose -f docker-compose.local.yml up -d
|
|
1334
|
-
docker compose -f docker-compose.local.yml logs kobo | grep Token
|
|
1335
1386
|
```
|
|
1336
1387
|
|
|
1337
|
-
Open `http://localhost:3000
|
|
1388
|
+
Open `http://localhost:3000/`; retrieve the token using [Token / login flow](#token--login-flow) if prompted.
|
|
1338
1389
|
|
|
1339
1390
|
By default the file bind-mounts `./kobo-projects` (next to it) at `/projects` — put a real git repo
|
|
1340
1391
|
in there (or set `KOBO_PROJECTS_DIR` to point elsewhere) before creating a workspace. When you get
|
|
@@ -1353,10 +1404,9 @@ and lose all Kōbō state).
|
|
|
1353
1404
|
```bash
|
|
1354
1405
|
docker build -t kobo:local . # once, if not already built
|
|
1355
1406
|
docker compose -f docker-compose.local-traefik.yml up -d
|
|
1356
|
-
docker compose -f docker-compose.local-traefik.yml logs kobo | grep Token
|
|
1357
1407
|
```
|
|
1358
1408
|
|
|
1359
|
-
Open `http://kobo.localhost
|
|
1409
|
+
Open `http://kobo.localhost/` and sign in using [Token / login flow](#token--login-flow) — `.localhost` resolves to `127.0.0.1` on
|
|
1360
1410
|
most OSes without touching `/etc/hosts`. This exercises the exact routing/auth/mount setup used by
|
|
1361
1411
|
`docker-compose.example.yml`, minus a real domain and TLS certificate.
|
|
1362
1412
|
|
|
@@ -1386,17 +1436,16 @@ Before using it:
|
|
|
1386
1436
|
2. Replace `kobo.example.com` with your real domain, and `you@example.com` with a real email (Let's Encrypt account).
|
|
1387
1437
|
3. Populate a `.env` file next to the compose file with `GH_TOKEN` / `GITLAB_TOKEN` if you use the forge integration.
|
|
1388
1438
|
4. Point every bind mount (`~/.ssh`, `~/.gitconfig`, `~/.claude.json`, `~/.claude`, `~/.codex`) at real paths on the host — see [Volumes](#volumes) for what each one is for, in particular the "`~/.claude.json` must already exist as a file" gotcha.
|
|
1389
|
-
5.
|
|
1439
|
+
5. Leave the Docker socket unmounted unless your project workflows require it; opting in grants host-level control. See [Volumes](#volumes).
|
|
1390
1440
|
6. Network access + behind-a-reverse-proxy are already pre-enabled via the `KOBO_NETWORK_ACCESS_*` env vars in the file — no manual bootstrap step.
|
|
1391
1441
|
|
|
1392
|
-
|
|
1442
|
+
Start it, then retrieve the token using the login flow above:
|
|
1393
1443
|
|
|
1394
1444
|
```bash
|
|
1395
1445
|
docker compose -f docker-compose.example.yml up -d
|
|
1396
|
-
docker compose -f docker-compose.example.yml logs kobo | grep Token
|
|
1397
1446
|
```
|
|
1398
1447
|
|
|
1399
|
-
Open `https://kobo.example.com
|
|
1448
|
+
Open `https://kobo.example.com/` and sign in using [Token / login flow](#token--login-flow). SSH access: `ssh -p 2222 root@<host>` (key-based
|
|
1400
1449
|
only). See [Ports](#ports) and [Volumes](#volumes) above for the full rationale on the Docker socket
|
|
1401
1450
|
and SSH tradeoffs before deploying this to a real machine.
|
|
1402
1451
|
|
|
@@ -1455,9 +1504,8 @@ An old image alone is not a complete rollback after database migrations.
|
|
|
1455
1504
|
— check `docker inspect <container> --format '{{json .State.Health}}'`. This should not happen on
|
|
1456
1505
|
a current image (`/api/health` is exempt from the token gate, see [The image](#the-image)); if you
|
|
1457
1506
|
see a 401 in the health log on a custom-built image, you're missing that exemption.
|
|
1458
|
-
-
|
|
1459
|
-
|
|
1460
|
-
the `kobo` service.
|
|
1507
|
+
- **The token is absent from startup logs** — this is intentional. Use the local
|
|
1508
|
+
[token retrieval command](#token--login-flow), then the browser login dialog.
|
|
1461
1509
|
|
|
1462
1510
|
## Agent runtimes
|
|
1463
1511
|
|
|
@@ -1473,7 +1521,7 @@ claude /login
|
|
|
1473
1521
|
|
|
1474
1522
|
Kōbō talks to the embedded [`@anthropic-ai/claude-agent-sdk`](https://github.com/anthropics/claude-agent-sdk-typescript), which reuses the same login. The `claude` CLI is **not** required at runtime; you only need it for `/login`, `mcp add`, and other one-off setup commands. As a fallback you can export `ANTHROPIC_API_KEY` instead.
|
|
1475
1523
|
|
|
1476
|
-
The model selector is populated from [`src/shared/models.ts`](./src/shared/models.ts), also used by backend validation. This checkout includes Fable 5.1, Mythos 5, Opus 5,
|
|
1524
|
+
The model selector is populated from [`src/shared/models.ts`](./src/shared/models.ts), also used by backend validation. This checkout includes Fable 5.1, Mythos 5.1/5, Opus 5.5, Sonnet 5.5, Haiku 5.5 (`claude-haiku-5-5`) and older variants. Pick the default in **Settings → Agents**. Catalogue entries describe what Kōbō offers; provider access still depends on your account. `auto` leaves model selection to the runtime.
|
|
1477
1525
|
|
|
1478
1526
|
#### Immediate chat messages
|
|
1479
1527
|
|
|
@@ -1654,15 +1702,17 @@ Kōbō treats the dev server in two independent layers:
|
|
|
1654
1702
|
| Layer | Driven by | Works for any project? |
|
|
1655
1703
|
|---|---|---|
|
|
1656
1704
|
| **Start / Stop** | The shell commands you configure | ✅ Yes, any shell-startable process |
|
|
1657
|
-
| **Status badge, URL
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1705
|
+
| **Status badge, URL** | A tracked process's local readiness announcement, or the Docker convention below | Quasar (`App URL...`) and Vite/Next (`Local:`), or matching Docker containers |
|
|
1706
|
+
| **Container count, logs viewer** | The `.container/instances/*.env` convention + Docker | ❌ No, requires the convention below |
|
|
1707
|
+
|
|
1708
|
+
Configured processes can be started and stopped. A tracked direct process reports
|
|
1709
|
+
`starting` until it announces a local HTTP(S) URL in a recognized readiness line
|
|
1710
|
+
on stdout or stderr, then reports `running` with that URL and port. Colored output
|
|
1711
|
+
and lines split across chunks are supported. This observes the CLI announcement;
|
|
1712
|
+
it does not probe application health. Docker container status and logs require a
|
|
1713
|
+
matching instance file and running containers. Without a tracked process or an
|
|
1714
|
+
instance, runtime detection returns `unknown`; the HTTP route may show the saved
|
|
1715
|
+
status instead. Without a start command, the route returns `not_configured`.
|
|
1666
1716
|
|
|
1667
1717
|
### 1. Configure start / stop commands
|
|
1668
1718
|
|
|
@@ -1681,9 +1731,9 @@ How Kōbō runs them:
|
|
|
1681
1731
|
- `DEV_DOCKER_NO_FOLLOW=1`: a hint that a Docker setup script should exit after starting its containers instead of following logs. A tracked start process reports `starting` when an instance file exists but no matching container is running yet; once containers appear, Docker status takes precedence.
|
|
1682
1732
|
- `stopCommand` runs with `INSTANCE` and `PROJECT_NAME` in the environment. After it, Kōbō also unconditionally runs `docker compose -p <PROJECT_NAME> down` if a `PROJECT_NAME` was resolved, so a Docker project does not strictly need a `stopCommand` at all.
|
|
1683
1733
|
|
|
1684
|
-
### 2.
|
|
1734
|
+
### 2. Docker status — the `.container/instances` contract
|
|
1685
1735
|
|
|
1686
|
-
For
|
|
1736
|
+
For Docker detection, the URL, the container count, and the logs button to appear, your **start command must create an instance file**:
|
|
1687
1737
|
|
|
1688
1738
|
```
|
|
1689
1739
|
<project-root>/.container/instances/<any-name>.env
|
|
@@ -1705,13 +1755,12 @@ The simplest correct start script therefore: read `$INSTANCE`, start your contai
|
|
|
1705
1755
|
|
|
1706
1756
|
### 3. Running detection and logs
|
|
1707
1757
|
|
|
1708
|
-
- **Status**: `running` if at least one container has the exact Compose project label; `starting`
|
|
1758
|
+
- **Status**: a tracked process with a recognized local readiness URL reports `running`. Otherwise, `running` if at least one container has the exact Compose project label; `starting` while the start process remains tracked; `stopped` when an instance exists but no container or process remains; `unknown` if neither a tracked process nor an instance matched.
|
|
1709
1759
|
- **Logs**: the logs button runs `docker logs` on those same matched containers.
|
|
1710
1760
|
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
containers are running. Direct processes can still be started and stopped.
|
|
1761
|
+
The logs viewer and container count remain **Docker-only**. Writing an instance
|
|
1762
|
+
file alone is not enough to expose a URL: matching containers must be running,
|
|
1763
|
+
or a tracked direct process must have announced its local URL.
|
|
1715
1764
|
|
|
1716
1765
|
### Minimal setups
|
|
1717
1766
|
|
|
@@ -1719,11 +1768,15 @@ containers are running. Direct processes can still be started and stopped.
|
|
|
1719
1768
|
|
|
1720
1769
|
**Non-Docker project (e.g. Vite/Node)**: configure a foreground command such as
|
|
1721
1770
|
`npm run dev`. Kōbō tracks its process group for shutdown, including children that
|
|
1722
|
-
outlive the shell.
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1771
|
+
outlive the shell. Quasar's `App URL... http://localhost:9000/` and Vite/Next's
|
|
1772
|
+
`Local: http://localhost:5173/` announcements populate the status and URL without
|
|
1773
|
+
an instance file. Other output formats remain `starting`; there is no general
|
|
1774
|
+
process health monitoring or direct-process log viewer. Readiness URLs are kept
|
|
1775
|
+
only for the current launch and cleared when it stops.
|
|
1776
|
+
|
|
1777
|
+
**No instance file at all**: Start/Stop run your commands; a tracked process uses
|
|
1778
|
+
the direct-process detection above. Otherwise the panel uses the saved status
|
|
1779
|
+
when available, or `unknown`, with no URL or Docker logs.
|
|
1727
1780
|
|
|
1728
1781
|
### Kōbō shutdown
|
|
1729
1782
|
|
package/CONTRIBUTING.md
CHANGED
|
@@ -4,7 +4,7 @@ Thanks for considering a contribution. This guide covers the from-source setup,
|
|
|
4
4
|
|
|
5
5
|
## Prerequisites
|
|
6
6
|
|
|
7
|
-
Node.js ≥
|
|
7
|
+
Node.js ≥ 26.12.1. The repository's `.nvmrc` pins the tested version; run
|
|
8
8
|
`nvm use` when using nvm.
|
|
9
9
|
|
|
10
10
|
## Setup
|
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ Use [group messages](CONFIGURATION.md#group-workspace-messages) to send one inst
|
|
|
28
28
|
|
|
29
29
|
## Quick start
|
|
30
30
|
|
|
31
|
-
Requires Node.js ≥
|
|
31
|
+
Requires Node.js ≥ 26.12.1, Git, Bash and your own Claude Code **or** Codex authentication. No skill plugin or ticket integration is required. Kōbō is a local, single-user tool; each user installs their own instance.
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
34
|
npx @loicngr/kobo@latest
|
package/SECURITY.md
CHANGED
|
@@ -17,11 +17,37 @@ the account running Kōbō and the selected engine's permission mode. A Git work
|
|
|
17
17
|
isolates a checkout, not processes, credentials or the filesystem. Only open
|
|
18
18
|
projects and configure executable hooks/integrations you trust.
|
|
19
19
|
|
|
20
|
-
The default listener is loopback.
|
|
21
|
-
per-user authorization.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
The default listener is loopback. Network access uses an operator token; it is not
|
|
21
|
+
per-user authorization. Browsers exchange it for a 12-hour HttpOnly, SameSite=Strict
|
|
22
|
+
cookie (Secure behind HTTPS proxies), never persist it in localStorage, and obtain
|
|
23
|
+
60-second single-use tickets for each WebSocket path. Rotation, disabling network
|
|
24
|
+
access, or changing proxy mode revokes sessions, pending tickets and active sockets,
|
|
25
|
+
including terminals. Restarting Kōbō also expires sessions. A settings change may
|
|
26
|
+
establish a new session for the browser that performed it using the returned token.
|
|
27
|
+
|
|
28
|
+
Behind a reverse proxy, enable the corresponding setting and declare the exact
|
|
29
|
+
public origin with `KOBO_NETWORK_ACCESS_PROXY_HOST` (bare domains default to HTTPS).
|
|
30
|
+
Health checks are exempt. Host and Origin validation remain separate protections.
|
|
31
|
+
Use HTTPS or a trusted private network; do not offer this installation as a shared
|
|
32
|
+
public service. Configure HSTS at the HTTPS terminator. The supplied public Compose
|
|
33
|
+
examples include it. Socket and request size/rate/concurrency limits are bounded
|
|
34
|
+
in-process; proxy limits should complement them. Client IPs come from OS sockets,
|
|
35
|
+
so callers behind the same proxy share limits.
|
|
36
|
+
|
|
37
|
+
External MCP requires a separately issued Bearer credential, including on loopback.
|
|
38
|
+
Each key has explicit tool and workspace grants, optional expiry, and independent
|
|
39
|
+
revocation; only its hash is stored. The UI defaults to read-only tools, selected
|
|
40
|
+
workspaces and 30-day expiry. Operator cookies/tokens cannot authenticate `/api/mcp`,
|
|
41
|
+
and an MCP key cannot authenticate operator APIs or terminal upgrades. Global stdio
|
|
42
|
+
forwards to that endpoint using `KOBO_MCP_TOKEN`; it does not read the database offline.
|
|
43
|
+
|
|
44
|
+
Managed workspace stdio uses a per-launch `KOBO_MCP_SESSION_TOKEN` through the local
|
|
45
|
+
`/api/internal-mcp` dispatcher. The backend owns authorization and database writes;
|
|
46
|
+
Plan and read-only review launches cannot invoke mutating managed tools even if the
|
|
47
|
+
provider approves a tool. Launch capabilities are revoked when stopping begins.
|
|
48
|
+
Operational progress and narrowly scoped review/handoff reports retain their own
|
|
49
|
+
capabilities. This tool boundary does not sandbox arbitrary code executed by an
|
|
50
|
+
agent or other integrations running as the same OS account.
|
|
25
51
|
|
|
26
52
|
Git workflow preferences express which automatic actions are wanted. They are not
|
|
27
53
|
a sandbox for arbitrary shell commands or external MCP tools. Claude and Codex
|
|
@@ -33,7 +59,8 @@ network token.
|
|
|
33
59
|
|
|
34
60
|
KOBO_HOME stores conversations, workspaces, backups and settings. Direct integration
|
|
35
61
|
commands and credentials live in `integrations.json`, written atomically with mode
|
|
36
|
-
0600 on Unix.
|
|
62
|
+
0600 on Unix. Settings and their temporary files/backups are also private (0600),
|
|
63
|
+
and new Kōbō home directories use 0700. They are plaintext local secrets: protect the host account and backups.
|
|
37
64
|
They are excluded from settings exports and are never returned by the connection
|
|
38
65
|
status API. A replacement connection must be entered in full. MCP error text and
|
|
39
66
|
stderr are withheld because third-party processes may echo secrets.
|