@loicngr/kobo 2.1.16 → 2.1.19

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.
Files changed (131) hide show
  1. package/AGENTS.md +101 -0
  2. package/CHANGELOG.md +12 -0
  3. package/CONFIGURATION.md +108 -17
  4. package/README.md +6 -2
  5. package/dist/mcp-server/kobo-tasks-server.js +28 -6
  6. package/dist/mcp-server/progress-bar-client.js +20 -0
  7. package/dist/mcp-server/workspace-dialogue-client.js +27 -7
  8. package/dist/server/db/migrations.js +2 -0
  9. package/dist/server/db/progress-bar-schema.js +27 -0
  10. package/dist/server/db/schema.js +2 -0
  11. package/dist/server/index.js +6 -0
  12. package/dist/server/middleware/workspace-creation-maintenance.js +13 -0
  13. package/dist/server/routes/maintenance.js +32 -0
  14. package/dist/server/routes/mcp.js +19 -9
  15. package/dist/server/routes/progress-bars.js +56 -0
  16. package/dist/server/routes/pull-requests.js +2 -1
  17. package/dist/server/routes/workspaces.js +35 -64
  18. package/dist/server/services/agent/engines/claude-code/engine.js +59 -16
  19. package/dist/server/services/agent/engines/claude-code/options-builder.js +13 -34
  20. package/dist/server/services/agent/engines/claude-code/stop-hook.js +8 -27
  21. package/dist/server/services/agent/engines/codex/engine.js +8 -1
  22. package/dist/server/services/agent/engines/codex/options-builder.js +11 -16
  23. package/dist/server/services/agent/orchestrator.js +73 -11
  24. package/dist/server/services/auto-loop-final-review-service.js +1 -1
  25. package/dist/server/services/auto-loop-service.js +10 -10
  26. package/dist/server/services/cron-service.js +7 -0
  27. package/dist/server/services/progress-bar-mcp-service.js +44 -0
  28. package/dist/server/services/progress-bar-runtime.js +29 -0
  29. package/dist/server/services/progress-bar-service.js +232 -0
  30. package/dist/server/services/quota-backoff-service.js +7 -0
  31. package/dist/server/services/update-maintenance-service.js +44 -0
  32. package/dist/server/services/wakeup-service.js +21 -3
  33. package/dist/server/services/workspace-creation-mcp-service.js +16 -0
  34. package/dist/shared/auto-loop-prompts.js +12 -12
  35. package/dist/shared/launch-instructions.js +57 -0
  36. package/dist/shared/progress-bar-prompts.js +7 -0
  37. package/dist/shared/progress-bar-tools.js +73 -0
  38. package/dist/shared/progress-bars.js +3 -0
  39. package/docker-compose.vps.yml +60 -0
  40. package/docs/deployment-vps.md +506 -0
  41. package/docs/getting-started.md +9 -0
  42. package/package.json +8 -1
  43. package/scripts/kobo-gh +9 -0
  44. package/scripts/kobo-github-app-token +190 -0
  45. package/scripts/kobo-install +392 -0
  46. package/scripts/kobo-update +499 -0
  47. package/src/client/dist/pwa/assets/ActivityFeed-DiUxnmGJ.js +2 -0
  48. package/src/client/dist/pwa/assets/{AutoLoopFinalReviewSettings-Bbrq02Xt.js → AutoLoopFinalReviewSettings-f4VDR5dd.js} +1 -1
  49. package/src/client/dist/pwa/assets/{ChangelogPage-BJfkAVYp.js → ChangelogPage-dEWpjTlp.js} +1 -1
  50. package/src/client/dist/pwa/assets/ComparisonPanel-Bwbqgvr4.js +2 -0
  51. package/src/client/dist/pwa/assets/CreatePage-CCCCAhrx.js +2 -0
  52. package/src/client/dist/pwa/assets/{DashboardPage-DZYsAh5y.js → DashboardPage-3byhBITf.js} +1 -1
  53. package/src/client/dist/pwa/assets/DiffViewer-Bj_NTfCF.js +8 -0
  54. package/src/client/dist/pwa/assets/{DocumentsPanel-BfPlfiwU.js → DocumentsPanel-xyLDV3T1.js} +1 -1
  55. package/src/client/dist/pwa/assets/{DrawerToggleButton-DG1Qjqk1.js → DrawerToggleButton-pwBSstQP.js} +1 -1
  56. package/src/client/dist/pwa/assets/GitPanel-DvIdrkVw.js +3 -0
  57. package/src/client/dist/pwa/assets/{HealthPage-_VXG1Zeo.js → HealthPage-BSwhZQRo.js} +1 -1
  58. package/src/client/dist/pwa/assets/MainLayout-DZJ9BvZw.js +2 -0
  59. package/src/client/dist/pwa/assets/{MainLayout-DnmUxNk7.css → MainLayout-DoAEgANU.css} +1 -1
  60. package/src/client/dist/pwa/assets/{MemoryPanel-CVlvGZXZ.js → MemoryPanel-ChR032zP.js} +1 -1
  61. package/src/client/dist/pwa/assets/{MemoryProposalList-SJsnzUAM.js → MemoryProposalList-BRKSoS4K.js} +1 -1
  62. package/src/client/dist/pwa/assets/{QBtnDropdown-DBgGsN-D.js → QBtnDropdown-o3QH0Bb8.js} +1 -1
  63. package/src/client/dist/pwa/assets/{QExpansionItem-DKgaMJ_l.js → QExpansionItem-BhFHiyq9.js} +1 -1
  64. package/src/client/dist/pwa/assets/{QScrollArea-D3OCsq3g.js → QScrollArea-BsNY6slB.js} +1 -1
  65. package/src/client/dist/pwa/assets/QSelect-bEq3g_io.js +1 -0
  66. package/src/client/dist/pwa/assets/{QTooltip-X5ps8Opw.js → QTooltip-xYZ6KNu2.js} +1 -1
  67. package/src/client/dist/pwa/assets/{SchedulePanel-Ww_FVlW5.js → SchedulePanel-DIFv_FTY.js} +1 -1
  68. package/src/client/dist/pwa/assets/{SearchPage-B87WEHf3.js → SearchPage-BqTBIt5E.js} +1 -1
  69. package/src/client/dist/pwa/assets/SettingsPage-BLD0xWFB.js +9 -0
  70. package/src/client/dist/pwa/assets/{SplitWorkspacePage-B99AJUbG.js → SplitWorkspacePage-D6r2pl5g.js} +1 -1
  71. package/src/client/dist/pwa/assets/{TerminalPanel-DnA1MXwu.js → TerminalPanel-CladK9Vv.js} +9 -9
  72. package/src/client/dist/pwa/assets/{ToolCallItem-2vFggaur.js → ToolCallItem-CdzEME4w.js} +3 -3
  73. package/src/client/dist/pwa/assets/{TouchPan-BSU3z0aO.js → TouchPan-B4gQPwGN.js} +1 -1
  74. package/src/client/dist/pwa/assets/{TourReplayButton-DQwS2xdD.js → TourReplayButton-B0j6AZwU.js} +1 -1
  75. package/src/client/dist/pwa/assets/{WorkspaceAttentionLabels-CM1tGDje.js → WorkspaceAttentionLabels-CeVhoidC.js} +1 -1
  76. package/src/client/dist/pwa/assets/WorkspacePage-CK5XCuG_.js +4 -0
  77. package/src/client/dist/pwa/assets/{WorkspacePage-B248nKIU.css → WorkspacePage-w2bF8wTd.css} +1 -1
  78. package/src/client/dist/pwa/assets/{browser-DPsupI9Q.js → browser-B8tNScg1.js} +1 -1
  79. package/src/client/dist/pwa/assets/{build-path-tree-CbIdt-p9.js → build-path-tree-kmVAcvs_.js} +1 -1
  80. package/src/client/dist/pwa/assets/custom-sounds-CJwd-8TL.js +1 -0
  81. package/src/client/dist/pwa/assets/{de-D3Ycvf_F.js → de-BaO6kbdO.js} +2 -2
  82. package/src/client/dist/pwa/assets/{editor.api-DvgAtnOj.js → editor.api-CgbPVW9s.js} +1 -1
  83. package/src/client/dist/pwa/assets/{efforts-nmxfTVQD.js → efforts-y7Wf_Rgd.js} +2 -2
  84. package/src/client/dist/pwa/assets/{es-TgeS5898.js → es-DTvSsbD0.js} +2 -2
  85. package/src/client/dist/pwa/assets/{expand-template-Brn5O4a1.js → expand-template-BFbbjj7X.js} +1 -1
  86. package/src/client/dist/pwa/assets/{format-DfJ3Fv1i.js → format-BETfc4z9.js} +1 -1
  87. package/src/client/dist/pwa/assets/{formatters-B30bNFhq.js → formatters-C22K9vlC.js} +1 -1
  88. package/src/client/dist/pwa/assets/{fr-CJafryNb.js → fr-BH7V66Yz.js} +2 -2
  89. package/src/client/dist/pwa/assets/{freemarker2-DnZe74tc.js → freemarker2-DiRVvp9O.js} +1 -1
  90. package/src/client/dist/pwa/assets/{handlebars-CmuMfxzO.js → handlebars-BLYRroSQ.js} +1 -1
  91. package/src/client/dist/pwa/assets/{html-BD7OJFGX.js → html-DAW2vteY.js} +1 -1
  92. package/src/client/dist/pwa/assets/i18n-DnuTmw3O.js +1 -0
  93. package/src/client/dist/pwa/assets/index-CbyHfF8I.js +20 -0
  94. package/src/client/dist/pwa/assets/{it-C5mN8Y61.js → it-DZGbkkoy.js} +2 -2
  95. package/src/client/dist/pwa/assets/{javascript-Y-OrgcmW.js → javascript-Bb5J8n0k.js} +1 -1
  96. package/src/client/dist/pwa/assets/{liquid-BqOkKePH.js → liquid-Dqx3adnJ.js} +1 -1
  97. package/src/client/dist/pwa/assets/{mdx-D-58x2h0.js → mdx-D_7igLV3.js} +1 -1
  98. package/src/client/dist/pwa/assets/{monaco-contributions-BW4ZMKO6.js → monaco-contributions-C-0CbrAy.js} +1 -1
  99. package/src/client/dist/pwa/assets/{monaco.contribution-DJWqzNG-.js → monaco.contribution-c6JPBEZI.js} +2 -2
  100. package/src/client/dist/pwa/assets/network-auth-BE4qbvWm.js +1 -0
  101. package/src/client/dist/pwa/assets/notify-theme-BVFBBGrJ.js +1 -0
  102. package/src/client/dist/pwa/assets/{project-color-gB5yeZPN.js → project-color-CHOR2jB5.js} +1 -1
  103. package/src/client/dist/pwa/assets/{python-BkBj1wDC.js → python-Dqubw1F5.js} +1 -1
  104. package/src/client/dist/pwa/assets/{razor-DOOJ_0b8.js → razor-BQphc9Kt.js} +1 -1
  105. package/src/client/dist/pwa/assets/{typescript-Bheo43G5.js → typescript-Dep00l0X.js} +1 -1
  106. package/src/client/dist/pwa/assets/{use-search-index-status-CBpnyV-R.js → use-search-index-status-CQHHvHwM.js} +1 -1
  107. package/src/client/dist/pwa/assets/{use-tours-BHNasCvg.js → use-tours-IVbXTmz2.js} +2 -2
  108. package/src/client/dist/pwa/assets/{use-worktree-restore-CgABsWno.js → use-worktree-restore-B3s5xDGR.js} +1 -1
  109. package/src/client/dist/pwa/assets/{workspace-templates-BnFkigYg.js → workspace-templates-CyuTpztP.js} +1 -1
  110. package/src/client/dist/pwa/assets/{xml-vHt2BD26.js → xml-BMS2dvaF.js} +1 -1
  111. package/src/client/dist/pwa/assets/{yaml-BvhLPzP9.js → yaml-CYw92aic.js} +1 -1
  112. package/src/client/dist/pwa/index.html +1 -1
  113. package/src/client/dist/pwa/sw.js +1 -1
  114. package/src/mcp-server/README.md +88 -1
  115. package/src/mcp-server/kobo-tasks-server.ts +34 -6
  116. package/src/mcp-server/progress-bar-client.ts +27 -0
  117. package/src/mcp-server/workspace-dialogue-client.ts +26 -7
  118. package/src/client/dist/pwa/assets/ActivityFeed-tJmJhmtl.js +0 -2
  119. package/src/client/dist/pwa/assets/ComparisonPanel-BfP8APKY.js +0 -2
  120. package/src/client/dist/pwa/assets/CreatePage-BbtNfo0x.js +0 -2
  121. package/src/client/dist/pwa/assets/DiffViewer-4Q-GJgyA.js +0 -8
  122. package/src/client/dist/pwa/assets/GitPanel-ECnbb_rx.js +0 -3
  123. package/src/client/dist/pwa/assets/MainLayout-BH6grTuW.js +0 -2
  124. package/src/client/dist/pwa/assets/QSelect-Cb_s_nox.js +0 -1
  125. package/src/client/dist/pwa/assets/SettingsPage-BAZLGUyg.js +0 -9
  126. package/src/client/dist/pwa/assets/WorkspacePage-CQN6EKIn.js +0 -4
  127. package/src/client/dist/pwa/assets/custom-sounds-DR68eyF8.js +0 -1
  128. package/src/client/dist/pwa/assets/i18n-BY4JeBjk.js +0 -1
  129. package/src/client/dist/pwa/assets/index-C5fAw9ll.js +0 -20
  130. package/src/client/dist/pwa/assets/network-auth-BGPRhUa6.js +0 -1
  131. package/src/client/dist/pwa/assets/notify-theme-DZDzfxph.js +0 -1
@@ -0,0 +1,60 @@
1
+ # Fresh, independent Kōbō instance behind an EXISTING Traefik Docker provider.
2
+ # Setup, authentication and upgrades: docs/deployment-vps.md
3
+ # Copy to your deployment directory as compose.yaml and create its .env first.
4
+ name: kobo
5
+
6
+ services:
7
+ kobo:
8
+ # Build this initial image locally. kobo-update later pins a unique release tag.
9
+ image: kobo:local
10
+ init: true
11
+ restart: unless-stopped
12
+ # Use the host's SSH and `docker compose exec`; no container SSH daemon.
13
+ entrypoint: ["node"]
14
+ command: ["dist/server/index.js"]
15
+ environment:
16
+ NODE_ENV: production
17
+ SERVER_PORT: "3000"
18
+ KOBO_HOME: /root/.config/kobo
19
+ KOBO_NETWORK_ACCESS_ENABLED: "true"
20
+ KOBO_NETWORK_ACCESS_BEHIND_PROXY: "true"
21
+ KOBO_NETWORK_ACCESS_PROXY_HOST: ${KOBO_DOMAIN:?Set KOBO_DOMAIN to the public hostname}
22
+ volumes:
23
+ # Includes Kōbō, Claude/Codex state and Git configuration; no PC auth mounts.
24
+ - kobo-home:/root
25
+ # Same ABSOLUTE path in both namespaces for project Docker bind mounts.
26
+ # Create the host directory first; fail rather than silently making one.
27
+ - type: bind
28
+ source: ${KOBO_PROJECTS_DIR:?Set KOBO_PROJECTS_DIR to an existing absolute path}
29
+ target: ${KOBO_PROJECTS_DIR:?Set KOBO_PROJECTS_DIR to an existing absolute path}
30
+ bind:
31
+ create_host_path: false
32
+ # Optional: enables project Docker commands, with root-equivalent host access.
33
+ # - /var/run/docker.sock:/var/run/docker.sock
34
+ networks:
35
+ - proxy
36
+ labels:
37
+ traefik.enable: "true"
38
+ traefik.docker.network: ${TRAEFIK_NETWORK:-web}
39
+ traefik.http.routers.kobo.rule: Host(`${KOBO_DOMAIN:?Set KOBO_DOMAIN to the public hostname}`)
40
+ traefik.http.routers.kobo.entrypoints: ${TRAEFIK_ENTRYPOINT:-websecure}
41
+ traefik.http.routers.kobo.tls: "true"
42
+ traefik.http.routers.kobo.tls.certresolver: ${TRAEFIK_CERTRESOLVER:-letsencrypt}
43
+ traefik.http.services.kobo.loadbalancer.server.port: "3000"
44
+ # No published HTTP or SSH ports. Traefik handles HTTP and WebSockets.
45
+ stop_grace_period: 60s
46
+ healthcheck:
47
+ start_period: 60s
48
+ logging:
49
+ driver: json-file
50
+ options:
51
+ max-size: "20m"
52
+ max-file: "3"
53
+
54
+ networks:
55
+ proxy:
56
+ external: true
57
+ name: ${TRAEFIK_NETWORK:-web}
58
+
59
+ volumes:
60
+ kobo-home:
@@ -0,0 +1,506 @@
1
+ # Run Kōbō on your own VPS
2
+
3
+ Use this guide for a **fresh, independent, single-user instance** behind an existing
4
+ Traefik Docker provider. Your browser runs on your PC; Kōbō, its agents, Git
5
+ repositories and development processes run on the VPS. Closing the browser does
6
+ not stop the server. A shared access token does not provide separate user accounts.
7
+
8
+ Use [`docker-compose.vps.yml`](../docker-compose.vps.yml). It starts only Kōbō,
9
+ joins Traefik's existing network and persists the whole container home. It does
10
+ not import your PC's workspaces or credentials. For a stack that also installs
11
+ Traefik, see the [other Compose examples](../CONFIGURATION.md#choosing-a-compose-file).
12
+
13
+ ## Guided installation
14
+
15
+ For a new deployment, use [`scripts/kobo-install`](../scripts/kobo-install) from
16
+ an up-to-date repository checkout containing the installer, deployment template and
17
+ helper scripts. The installer needs Python 3.10+, Git, local Docker with Compose,
18
+ and an existing Traefik deployment on Linux amd64. GitHub App setup also requires
19
+ Python 3.10+ and OpenSSL inside the container; the installer checks its built image.
20
+ Create an empty deployment directory writable by your SSH user, separately from
21
+ the source checkout:
22
+
23
+ ```bash
24
+ sudo install -d -o "$(id -u)" -g "$(id -g)" /opt/kobo
25
+ python3 scripts/kobo-install --directory /opt/kobo
26
+ ```
27
+
28
+ The prompts collect the public domain and project directory, offer detected
29
+ Traefik settings, and let you opt into Docker socket access and GitHub App
30
+ credentials. Check the detected network, HTTPS entrypoint and certificate resolver
31
+ against your proxy configuration. Socket access remains an explicit choice because
32
+ it grants root-equivalent control over the host.
33
+
34
+ Choose an inspection or preparation mode when needed:
35
+
36
+ ```bash
37
+ python3 scripts/kobo-install --directory /opt/kobo --check
38
+ python3 scripts/kobo-install --directory /opt/kobo --prepare
39
+ ```
40
+
41
+ `--check` validates prerequisites and configuration without writing deployment
42
+ files, building an image or starting a container. `--prepare` writes the deployment
43
+ files and builds the image without starting Kōbō. A normal invocation completes
44
+ installation and starts the service. Both build modes require network access to
45
+ GitHub and image/package dependencies.
46
+
47
+ For unattended installation, supply the settings explicitly. Replace these
48
+ example IDs, domain, paths and proxy names with your own values:
49
+
50
+ ```bash
51
+ python3 scripts/kobo-install --directory /opt/kobo --yes \
52
+ --domain kobo.example.com \
53
+ --projects-directory /opt/kobo/projects \
54
+ --network web --entrypoint websecure --certresolver letsencrypt \
55
+ --version 2.1.16 \
56
+ --github-app-id 123456 --github-installation-id 789012 \
57
+ --github-private-key /home/YOUR-USER/.config/github-app/app.pem
58
+ ```
59
+
60
+ Omit the three `--github-*` arguments to configure forge authentication manually
61
+ later. Add `--docker-socket` only if agents need to manage project containers.
62
+ `--version` pins the release to build; the version above is illustrative. Without
63
+ it, the installer resolves the latest stable release. `--yes` skips interactive
64
+ prompts; it does not silently enable Docker socket access or overwrite a previous
65
+ installation.
66
+
67
+ This layout reserves the Compose project/router name `kobo` and volume
68
+ `kobo_kobo-home`; an existing container, router or volume using those names is
69
+ refused. Use the manual procedure if you need a second differently named instance.
70
+
71
+ For a preloaded TLS certificate, pass `--certresolver ''`; otherwise use the name
72
+ of the resolver configured in Traefik. Detection reads Traefik's Docker networks,
73
+ CLI arguments and environment, not mounted static configuration files. Confirm
74
+ the names manually when that configuration is file-based or multiple values are
75
+ detected. `--check` checks local configuration, not DNS, certificate issuance or
76
+ GitHub authentication; the normal installation checks authenticated API access
77
+ and public HTTPS after startup.
78
+
79
+ The installer places operator commands in `/opt/kobo/bin/kobo-install` and
80
+ `/opt/kobo/bin/kobo-update`. Rerun the installed installer against the same
81
+ directory to continue a prepared installation or inspect its state. It detects
82
+ changes to managed files and refuses to overwrite them. It also refuses to adopt
83
+ an older stack that was not created by this installer. Use the existing manual
84
+ procedure and updater for such deployments; do not delete their configuration to
85
+ make installation proceed.
86
+
87
+ An interrupted build can be retried with the same command; previous private build
88
+ logs remain under `install-builds/`. After a start was attempted, a retry only
89
+ finishes verification of the healthy container matching the prepared image and
90
+ Compose configuration. It never automatically recreates an uncertain container.
91
+ For example, fix DNS/certificate provisioning and rerun to finish an HTTPS check.
92
+ If the container is missing, unhealthy or changed, inspect `docker compose ps`
93
+ and its private logs first; follow the manual procedure to repair it. Interrupted
94
+ initial file writes require manual inspection of `.kobo-install.json` and the
95
+ files it lists. Do not remove persistent volumes or reset this manifest to bypass
96
+ these checks.
97
+
98
+ After installation, continue with [opening Kōbō](#2-start-and-open-kōbō) and
99
+ [authenticating agent engines](#3-authenticate-and-choose-a-project). The installer
100
+ does not log you into Claude or Codex. Obtain the Kōbō browser token through the
101
+ existing startup-log command below. For installer-managed deployments, invoke the
102
+ updater as `/opt/kobo/bin/kobo-update --directory /opt/kobo`; the `./kobo-update`
103
+ examples later in this guide describe the manual installation layout.
104
+
105
+ The following numbered steps provide the **manual alternative**. Do not recreate
106
+ the source tree, Compose file or `.env` after a successful guided installation.
107
+
108
+ ## 1. Prepare the host and image
109
+
110
+ Requirements: a Linux Docker host, Docker Compose v2 or later, Git, SSH access,
111
+ and an existing Traefik HTTPS entrypoint, certificate resolver and Docker network.
112
+ Point your chosen domain's DNS at that server. The updater also requires Python
113
+ 3.10 or later. This recipe uses the repository image, currently built for amd64;
114
+ its `glab` installation is architecture-specific.
115
+
116
+ Create a deployment directory owned by your SSH user. `/opt/kobo` is an example;
117
+ use another absolute path if appropriate:
118
+
119
+ ```bash
120
+ sudo install -d -o "$(id -u)" -g "$(id -g)" /opt/kobo /opt/kobo/projects
121
+ cd /opt/kobo
122
+ ```
123
+
124
+ Choose a published release from [GitHub releases](https://github.com/loicngr/kobo/releases).
125
+ The version below is an example, not a moving latest-version recommendation:
126
+
127
+ ```bash
128
+ KOBO_VERSION=2.1.16
129
+ git clone --depth 1 --branch "v${KOBO_VERSION}" https://github.com/loicngr/kobo.git source
130
+ docker build -t kobo:local source
131
+ ```
132
+
133
+ Save [`docker-compose.vps.yml`](../docker-compose.vps.yml) as `/opt/kobo/compose.yaml`
134
+ and [`scripts/kobo-update`](../scripts/kobo-update) as `/opt/kobo/kobo-update`.
135
+ These files may be newer than the example release above: obtain them from the
136
+ checkout containing this guide, not an older tag that predates them.
137
+
138
+ ```bash
139
+ chmod 755 /opt/kobo/kobo-update
140
+ ```
141
+
142
+ Create `/opt/kobo/.env` with your deployment values:
143
+
144
+ ```dotenv
145
+ KOBO_DOMAIN=kobo.example.com
146
+ KOBO_PROJECTS_DIR=/opt/kobo/projects
147
+ TRAEFIK_NETWORK=web
148
+ TRAEFIK_ENTRYPOINT=websecure
149
+ TRAEFIK_CERTRESOLVER=letsencrypt
150
+ ```
151
+
152
+ The network, entrypoint and resolver names must match **your existing Traefik**;
153
+ `web`, `websecure` and `letsencrypt` are examples. If Traefik uses a preloaded
154
+ certificate rather than an ACME resolver, remove the `tls.certresolver` label.
155
+ Keep `tls: "true"`. Do not start a second proxy on the same ports. The explicit
156
+ network label selects the network Traefik uses to reach Kōbō. See
157
+ [Traefik's Docker routing reference](https://doc.traefik.io/traefik/reference/routing-configuration/other-providers/docker/).
158
+
159
+ ## 2. Start and open Kōbō
160
+
161
+ From `/opt/kobo`:
162
+
163
+ ```bash
164
+ docker network inspect web # use your TRAEFIK_NETWORK value
165
+ docker compose config --quiet
166
+ docker compose up -d --wait --wait-timeout 180 kobo
167
+ docker compose logs kobo | grep Token
168
+ ```
169
+
170
+ Open `https://kobo.example.com/?token=<printed-token>` on your PC. The browser
171
+ remembers the token; treat both that URL and startup logs as credentials.
172
+ `KOBO_NETWORK_ACCESS_PROXY_HOST` is populated from `KOBO_DOMAIN` and must match
173
+ the public hostname. Both network access and behind-proxy mode are enabled.
174
+
175
+ This example publishes no HTTP or SSH ports. Use SSH to the VPS followed by
176
+ `docker compose exec kobo bash` for a container shell. The Compose entrypoint
177
+ starts Node directly, so it does not start the image's optional SSH daemon.
178
+
179
+ Check routing before starting a mission:
180
+
181
+ ```bash
182
+ curl --fail https://kobo.example.com/api/health
183
+ curl -s -o /dev/null -w '%{http_code}\n' https://kobo.example.com/api/workspaces
184
+ ```
185
+
186
+ Expect health JSON with `status: "ok"` and the installed version, then `401`
187
+ without a token. `/api/health` is intentionally public. Ordinary authenticated
188
+ REST requests use `X-Kobo-Token`; the external MCP endpoint also supports Bearer
189
+ authentication. No additional Traefik route is needed for WebSocket upgrades.
190
+
191
+ ## 3. Authenticate and choose a project
192
+
193
+ Authenticate **inside the container**, using the engine you intend to run:
194
+
195
+ ```bash
196
+ docker compose exec kobo claude auth login
197
+ docker compose exec kobo codex login --device-auth
198
+ ```
199
+
200
+ Follow the browser URL/code printed by your installed CLI. Provider availability
201
+ and login requirements can vary; `claude auth login --help` and `codex login --help`
202
+ show the supported options. You can also configure your own provider API key.
203
+ No paid agent turn is needed for these setup commands.
204
+
205
+ For a personal GitHub account, complete the CLI's browser login flow from your PC,
206
+ then connect Git HTTPS credentials to it:
207
+
208
+ ```bash
209
+ docker compose exec kobo gh auth login --hostname github.com --git-protocol https --web
210
+ docker compose exec kobo gh auth setup-git --hostname github.com
211
+ docker compose exec kobo git config --global user.name "Your Name"
212
+ docker compose exec kobo git config --global user.email "you@example.com"
213
+ ```
214
+
215
+ Git commit identity and forge authentication are separate settings. For a GitHub
216
+ App bot, use the [renewable-token setup below](#github-app-bot-authentication)
217
+ instead of an interactive account login.
218
+
219
+ Clone your repository in the mounted project directory (replace the repository):
220
+
221
+ ```bash
222
+ docker compose exec kobo git clone https://github.com/YOUR-ORG/YOUR-REPO.git /opt/kobo/projects/my-project
223
+ ```
224
+
225
+ In the first-run form, **Local project directory** means
226
+ `/opt/kobo/projects/my-project` inside the VPS container. It is neither a GitHub URL
227
+ nor a folder on the PC running the browser. Then follow [your first mission](./getting-started.md#create-a-mission).
228
+
229
+ The named `kobo-home` volume covers `/root`: it preserves Kōbō's database/settings,
230
+ Claude/Codex state and Git/forge configuration across container replacement.
231
+ Do not run `docker compose down -v`. Authentication performed only on the host is
232
+ not automatically available inside a container. See [Docker volume persistence](https://docs.docker.com/reference/compose-file/volumes/).
233
+
234
+ ## Optional project Docker environments
235
+
236
+ The image includes the Docker CLI and Compose plugin. Verify with
237
+ `docker compose exec kobo docker compose version`; an older release image may
238
+ need the plugin installed in a derived image. The updater below adds it when missing.
239
+
240
+ To let agents manage project containers, explicitly enable the commented
241
+ `/var/run/docker.sock` mount in `compose.yaml` and recreate the service when idle.
242
+ This grants **root-equivalent control of the Docker host**, not an isolated
243
+ Docker daemon. A worktree does not provide a security boundary.
244
+
245
+ The host daemon resolves bind-mount paths on the **host**. The example therefore
246
+ mounts `/opt/kobo/projects` at the same absolute path inside Kōbō. Before creating
247
+ workspaces, set **Settings → Worktrees → worktree path** to a persistent path
248
+ under that mount, for example `/opt/kobo/projects/.worktrees`. A worktree stored
249
+ only inside `/root` cannot be used by the host daemon under that container path.
250
+ Keep the same path arrangement for any additional bind-mounted project data.
251
+
252
+ An `npm` development process does not require the Docker socket. Development
253
+ server URLs are separate from Kōbō's dashboard URL; configure their own reachable
254
+ ports or proxy routes. See the [dev-server contract](../CONFIGURATION.md#dev-server).
255
+
256
+ ## GitHub App bot authentication
257
+
258
+ A GitHub App installation token expires after one hour. Putting one token in
259
+ `.env` is insufficient for a long-running server. Supply a helper that returns
260
+ a current installation token, with renewal before expiry. GitHub documents both
261
+ [token generation](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-an-installation-access-token-for-a-github-app)
262
+ and [installation authentication for HTTPS Git](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/authenticating-as-a-github-app-installation).
263
+
264
+ Kōbō ships the renewal helper [`scripts/kobo-github-app-token`](../scripts/kobo-github-app-token)
265
+ and wrapper [`scripts/kobo-gh`](../scripts/kobo-gh), but no App credentials. The
266
+ installer can configure these for a new stack. To configure them manually on an
267
+ existing stack, follow the procedure below. No web-settings change is required.
268
+ This helper supports GitHub.com, not GitHub Enterprise Server.
269
+
270
+ Create your GitHub App, install it only on the repositories Kōbō should access,
271
+ and obtain its App ID (or client ID), installation ID and unencrypted RSA private
272
+ key. Grant repository **Contents: read and write** for Git pushes and **Pull
273
+ requests: read and write** for PR operations. Add other permissions only for the
274
+ operations you intend to use, such as workflow changes or CI inspection; the
275
+ helper cannot expand the App's granted permissions. See
276
+ [GitHub App permission selection](https://docs.github.com/en/apps/creating-github-apps/setting-up-a-github-app/choosing-permissions-for-a-github-app).
277
+ The installation ID identifies the installation, not the App or bot user.
278
+
279
+ From the source checkout, install private host files outside the repository:
280
+
281
+ ```bash
282
+ install -d -m 700 /opt/kobo/auth
283
+ install -m 755 scripts/kobo-gh /opt/kobo/auth/gh
284
+ install -m 755 scripts/kobo-github-app-token /opt/kobo/auth/kobo-github-app-token
285
+ install -m 600 /path/to/YOUR-APP-PRIVATE-KEY.pem /opt/kobo/auth/app.pem
286
+ ```
287
+
288
+ Create `/opt/kobo/auth/github-app.json` with the following structure, replacing
289
+ the IDs. The key path is the **container path**, not its path on the host:
290
+
291
+ ```json
292
+ {
293
+ "app_id": "123456",
294
+ "installation_id": "789012",
295
+ "private_key": "/run/secrets/github-app.pem"
296
+ }
297
+ ```
298
+
299
+ ```bash
300
+ chmod 600 /opt/kobo/auth/github-app.json
301
+ ```
302
+
303
+ Add these read-only mounts under `services.kobo.volumes` in `compose.yaml`.
304
+ Create all source files first; these mounts complement the existing `/root`
305
+ volume and project bind mount:
306
+
307
+ ```yaml
308
+ - type: bind
309
+ source: /opt/kobo/auth/gh
310
+ target: /usr/local/bin/gh
311
+ read_only: true
312
+ bind:
313
+ create_host_path: false
314
+ - type: bind
315
+ source: /opt/kobo/auth/kobo-github-app-token
316
+ target: /usr/local/bin/kobo-github-app-token
317
+ read_only: true
318
+ bind:
319
+ create_host_path: false
320
+ - type: bind
321
+ source: /opt/kobo/auth/github-app.json
322
+ target: /etc/kobo/github-app.json
323
+ read_only: true
324
+ bind:
325
+ create_host_path: false
326
+ - type: bind
327
+ source: /opt/kobo/auth/app.pem
328
+ target: /run/secrets/github-app.pem
329
+ read_only: true
330
+ bind:
331
+ create_host_path: false
332
+ ```
333
+
334
+ The container requires Python 3.10+ and OpenSSL for this helper. Check older
335
+ images before applying the mounts; install missing dependencies in a derived
336
+ image so they survive recreation. Keep the private key outside the image and
337
+ Git repository, owner-readable only. Its host path, environment and cache are
338
+ not automatically inherited inside Docker.
339
+
340
+ The wrapper is mounted in `/usr/local/bin`, which precedes `/usr/bin` even in the
341
+ image's login shells. This covers Kōbō and agent subprocesses, whereas a shell
342
+ alias would not. It preserves all `gh` arguments and uses explicit nonempty
343
+ `GH_TOKEN` or `GITHUB_TOKEN` variables before requesting an App token. Remove
344
+ stale exported tokens when you want automatic renewal to apply.
345
+
346
+ Recreate the idle service to apply the mounts, then configure Git inside it:
347
+
348
+ ```bash
349
+ docker compose config --quiet
350
+ docker compose up -d --wait --wait-timeout 180 kobo
351
+ docker compose exec kobo kobo-github-app-token --check
352
+ docker compose exec kobo git config --global --replace-all credential.https://github.com.helper ''
353
+ docker compose exec kobo git config --global --add credential.https://github.com.helper '!/usr/local/bin/gh auth git-credential'
354
+ docker compose exec kobo bash -lc 'command -v gh'
355
+ docker compose exec kobo gh repo view YOUR-ORG/YOUR-REPO --json nameWithOwner
356
+ docker compose exec kobo git -C /opt/kobo/projects/my-project ls-remote origin HEAD
357
+ ```
358
+
359
+ The empty helper entry resets inherited helpers **only for this HTTPS host**.
360
+ Use clean remotes such as `https://github.com/YOUR-ORG/YOUR-REPO.git`; remove any
361
+ old token embedded in a remote URL so it cannot override the helper. Normal `gh`
362
+ and Git HTTPS clone/fetch/pull/push now share the renewable credentials, within
363
+ the App's repository access and permissions. Local rebase/merge/commit operations
364
+ need no token. SSH remotes retain SSH authentication. Calling `/usr/bin/gh`
365
+ directly bypasses the wrapper.
366
+
367
+ The helper reads `/etc/kobo/github-app.json` by default. `--config PATH` selects
368
+ another JSON file; `--cache-dir PATH` selects another cache directory. In the
369
+ container it caches tokens under `/root/.cache/kobo/github-app`, retained by the
370
+ home volume. The directory is private (`0700`) and its files are private (`0600`).
371
+ It renews within two minutes of the API's actual expiry, serializes concurrent
372
+ renewals with a bounded lock, and invalidates cached tokens when the configuration
373
+ or key changes. Failed renewal never falls back to an expired token. HTTPS calls
374
+ use the fixed GitHub API endpoint and do not follow redirects.
375
+
376
+ Use `docker compose exec kobo kobo-github-app-token --check` to validate signing,
377
+ GitHub authentication and the cache without exposing a token. It prints a JSON
378
+ status and expiration time. On failure, check file permissions, the key and IDs,
379
+ the App installation's repository access, server clock and outbound HTTPS. Do not
380
+ run the helper without `--check` in a shared terminal or log: its normal stdout is
381
+ the credential consumed by the wrapper.
382
+
383
+ The token authenticates remote operations; it does not choose the author of local
384
+ commits. Configure commit identity separately, for example using your App's bot
385
+ login and its actual GitHub bot-user email:
386
+
387
+ ```bash
388
+ docker compose exec kobo git config --global user.name 'YOUR-APP[bot]'
389
+ docker compose exec kobo git config --global user.email 'BOT-USER-ID+YOUR-APP[bot]@users.noreply.github.com'
390
+ ```
391
+
392
+ `BOT-USER-ID` is the bot account's user ID, not the App ID or installation ID.
393
+ The installer does not invent or overwrite a Git author identity.
394
+
395
+ For host-side Git, install/configure a host-side wrapper and credential helper too;
396
+ container settings do not change the host. Do not print token-helper output or
397
+ paste credentials into logs. This wrapper pattern is optional deployment plumbing,
398
+ not an extra authentication setting in Kōbō's UI.
399
+
400
+ ## Update with kobo-update
401
+
402
+ From the deployment directory:
403
+
404
+ ```bash
405
+ cd /opt/kobo
406
+ ./kobo-update --check # inspect prerequisites and latest stable release
407
+ ./kobo-update # build, back up and deploy the latest stable release
408
+ ```
409
+
410
+ To select a version or build without interruption:
411
+
412
+ ```bash
413
+ ./kobo-update 2.1.16 --prepare # example version; build and smoke-test only
414
+ ./kobo-update 2.1.16 # deploy that version, or do nothing if already installed
415
+ ```
416
+
417
+ From another directory, pass `--directory /opt/kobo`. From your PC, for example:
418
+ `ssh -t YOUR-VPS '/opt/kobo/kobo-update --directory /opt/kobo'`.
419
+ The source copy can also be invoked directly with
420
+ `python3 scripts/kobo-update --directory /opt/kobo --check`.
421
+
422
+ The updater is for this **standalone Linux Docker layout**, not every Compose
423
+ stack: one service named `kobo`, a `compose.yaml`, `KOBO_HOME=/root/.config/kobo`,
424
+ a named volume mounted at `/root`, and an HTTPS proxy hostname in the service
425
+ environment. It reads the Compose project name, hostname and volume rather than
426
+ assuming a particular server. It uses the local Docker daemon; do not point it
427
+ at a remote Docker context. It requires network access to npm, GitHub and image
428
+ build dependencies. It does not update Traefik or install a scheduled auto-updater.
429
+
430
+ Both operator scripts explicitly read the deployment directory's `.env` for
431
+ Compose. Exported `KOBO_DOMAIN`, `KOBO_PROJECTS_DIR`, `TRAEFIK_NETWORK`,
432
+ `TRAEFIK_ENTRYPOINT`, `TRAEFIK_CERTRESOLVER` and `COMPOSE_*` variables in the caller's
433
+ shell cannot override these commands. This applies to validation, start, stop and
434
+ recovery. Docker context selection and forge authentication remain available to
435
+ child processes; other commands such as image builds retain their environment.
436
+
437
+ The installed runtime must support the atomic update-maintenance endpoint
438
+ (`GET /api/maintenance/update`, protocol 1). Older releases, including the 2.1.16
439
+ example above, do not: automatic deployment and `--check` refuse without stopping
440
+ the service. `--prepare` remains available to build a candidate image. For the
441
+ first upgrade from such a release, explicitly stop the old service, back up its
442
+ home volume, and deploy the prepared image manually; the updater never falls
443
+ back to an unsafe check-then-stop sequence. Do not bypass this check in the script.
444
+
445
+ It checks active agents before the build. Immediately before stopping, the backend
446
+ atomically verifies inactivity and reserves admission: manual and automatic agent
447
+ starts cannot slip between the final check and shutdown. Workspace creations and
448
+ PR checkouts in progress also block reservation; new ones are refused while it
449
+ is held, before creating records, worktrees or running setup scripts. A creation
450
+ keeps its admission slot through asynchronous preparation and any rollback,
451
+ including the MCP PR-import sequence. Cron, wakeup and quota
452
+ deliveries wait without consuming their persisted instructions or deadlines.
453
+ Valid pending wakeups are marked as deferred before the reservation succeeds,
454
+ including deadlines that will fall during downtime; this prevents the normal
455
+ five-minute stale-wakeup cleanup from deleting them after a long backup. Their
456
+ original deadline and prompt stay unchanged. Already stale, never-attempted
457
+ wakeups are not revived.
458
+ It retrieves npm's `latest` version (or the explicit
459
+ stable version), verifies the Git tag's commit and package version, builds a uniquely
460
+ tagged image, ensures Compose is installed and checks native modules. The old
461
+ service stays available during the build. Plan for roughly 5–15 minutes without
462
+ build cache; backup duration depends on the volume size.
463
+
464
+ Once idle, it stops Kōbō, archives the complete `/root` volume, tests SQLite
465
+ migrations/integrity on a copy, pins the new image directly in `compose.yaml`, and
466
+ starts the service. It checks container health, the authenticated internal API,
467
+ the version served through HTTPS, and public API rejection without a token. It
468
+ preserves other Compose settings and mounts, refuses downgrades and concurrent
469
+ updates, and detects Compose/environment edits during the build. The script
470
+ itself stays at the version you installed; copy a newer reviewed script from the
471
+ repository when you want to update the updater.
472
+
473
+ ## Backups and failed updates
474
+
475
+ Each update records its private log, `state.json`, previous Compose file,
476
+ `home.tar.gz` and recovery instructions in `<deployment>/updates/<timestamp>-<id>/`.
477
+ The archive contains credentials as well as application data; keep it private.
478
+ A prepared-only build does not create a home backup. No old images, backups or
479
+ volumes are automatically removed; monitor disk space and retain off-host copies.
480
+
481
+ An error before shutdown releases the reservation, including a lost acquisition
482
+ response. If shutdown was attempted, the updater confirms the old process has
483
+ stopped before restarting it. An interrupted updater can leave admission reserved;
484
+ the reservation deliberately has no expiry that could reopen the race. Follow
485
+ `RECOVERY.md` and the durable phase: before a new-version launch, stop the old
486
+ container and confirm its exit before restarting it. Restart clears the in-memory
487
+ reservation. Never release it while a Docker stop could still be in progress.
488
+
489
+ Repositories/worktrees stored outside `/root`, bind-mounted App keys/scripts and
490
+ project database volumes are **not included** in `home.tar.gz`. Back them up
491
+ separately along with `.env` and other deployment files. Never copy a live SQLite
492
+ file as your only database backup; the updater stops Kōbō before archiving it.
493
+
494
+ A build failure leaves the current service running. A backup or migration-test
495
+ failure restarts the previous version before new code touches production data.
496
+ After a new-version launch, an error leaves data intact for diagnosis: an older
497
+ image must not be blindly started against a migrated database, and a snapshot
498
+ restore could discard messages or work resumed since launch. Read the generated
499
+ `RECOVERY.md`; restore to a **new volume**, retaining the current one, if a full
500
+ rollback is necessary. An interrupted update blocks subsequent updates until its
501
+ recorded state has been reviewed. Inspect logs locally; they may contain secrets.
502
+
503
+ For troubleshooting, start with `docker compose ps`, the private update log and
504
+ `docker compose logs --tail 100 kobo`. A Traefik 404/502 calls for checking the
505
+ shared network, hostname, resolver and container health before restoring data.
506
+ The application update banner only reports releases; it does not run this script.
@@ -10,6 +10,8 @@ Kōbō is a local, single-user application that runs Claude Code or OpenAI Codex
10
10
 
11
11
  No skill plugin, forge CLI, Docker, Notion, Sentry or voice software is needed for a basic mission. A repository without a remote works; choose forge `none` to disable PR/MR features.
12
12
 
13
+ For a remote installation, follow the [VPS and Docker guide](./deployment-vps.md) first: `kobo-install` guides a fresh installation behind existing Traefik and can configure a GitHub App bot. The same guide documents manual setup. The project picker browses the server/container filesystem: select a repository cloned there, not a folder on the PC running your browser. Authenticate the agent and forge tools inside the container too.
14
+
13
15
  ## Start
14
16
 
15
17
  ```bash
@@ -36,6 +38,13 @@ New installations use manual commit, push and PR/MR publication preferences, dis
36
38
 
37
39
  You can skip setup and reopen it from **Help → First-run setup**. Setup checks do not start a mission automatically.
38
40
 
41
+ ## Using a phone or tablet
42
+
43
+ Open a side panel from the chat header. Drag its inner edge with a finger to
44
+ adjust its width; drag the divider in the right panel to resize its two sections.
45
+ Settings, Help and Create wrap onto additional lines in a narrow workspace panel.
46
+ Tap the visible area outside a panel to close it.
47
+
39
48
  ## Optional features
40
49
 
41
50
  Configure integrations only when you need them, in their Settings tabs. Notion and Sentry support direct command, JSON arguments and JSON environment configuration without a Claude installation; credentials are stored locally outside settings exports. Connection tests run only when explicitly requested. Forge actions use your authenticated forge CLI or configured Bitbucket credentials. See [Configuration](../CONFIGURATION.md) and [Security](../SECURITY.md).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loicngr/kobo",
3
- "version": "2.1.16",
3
+ "version": "2.1.19",
4
4
  "description": "Kōbō — local multi-workspace orchestrator for Claude Code and OpenAI Codex, with isolated Git worktrees, live review and optional automation.",
5
5
  "type": "module",
6
6
  "license": "GPL-3.0-or-later",
@@ -19,6 +19,12 @@
19
19
  "SECURITY.md",
20
20
  "THIRD_PARTY_NOTICES.md",
21
21
  "docs/getting-started.md",
22
+ "docs/deployment-vps.md",
23
+ "docker-compose.vps.yml",
24
+ "scripts/kobo-update",
25
+ "scripts/kobo-install",
26
+ "scripts/kobo-github-app-token",
27
+ "scripts/kobo-gh",
22
28
  "docs/troubleshooting.md",
23
29
  "CONTRIBUTING.md",
24
30
  "CODE_OF_CONDUCT.md",
@@ -70,6 +76,7 @@
70
76
  "test:mcp:live": "vitest run --config vitest.live.config.ts",
71
77
  "test:watch": "vitest --config vitest.config.ts --root .",
72
78
  "test:client": "cd src/client && npm test",
79
+ "test:deployment": "python3 -B -m unittest discover -s scripts/tests -p 'test_*.py'",
73
80
  "test:all": "npm test && npm run test:client",
74
81
  "typecheck:tests": "tsc -p tsconfig.test.json",
75
82
  "lint": "biome check .",
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env bash
2
+ # Explicit caller credentials take precedence over the configured GitHub App.
3
+ set -euo pipefail
4
+ if [[ -z "${GH_TOKEN:-}" && -z "${GITHUB_TOKEN:-}" ]]; then
5
+ GH_TOKEN="$(/usr/local/bin/kobo-github-app-token)"
6
+ [[ -n "$GH_TOKEN" ]] || exit 1
7
+ export GH_TOKEN
8
+ fi
9
+ exec /usr/bin/gh "$@"