@pixelbyte-software/pixcode 1.34.0 → 1.35.1

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 (247) hide show
  1. package/LICENSE +718 -718
  2. package/README.de.md +248 -248
  3. package/README.ja.md +240 -240
  4. package/README.ko.md +240 -240
  5. package/README.md +303 -303
  6. package/README.ru.md +248 -248
  7. package/README.tr.md +250 -250
  8. package/README.zh-CN.md +240 -240
  9. package/dist/api-docs.html +548 -395
  10. package/dist/assets/index-B8w57E1r.css +32 -0
  11. package/dist/assets/index-CBdsvGSR.js +854 -0
  12. package/dist/clear-cache.html +85 -85
  13. package/dist/convert-icons.md +52 -52
  14. package/dist/favicon.svg +8 -8
  15. package/dist/generate-icons.js +48 -48
  16. package/dist/icons/codex-white.svg +3 -3
  17. package/dist/icons/codex.svg +3 -3
  18. package/dist/icons/cursor-white.svg +11 -11
  19. package/dist/icons/icon-128x128.svg +9 -9
  20. package/dist/icons/icon-144x144.svg +9 -9
  21. package/dist/icons/icon-152x152.svg +9 -9
  22. package/dist/icons/icon-192x192.svg +9 -9
  23. package/dist/icons/icon-384x384.svg +9 -9
  24. package/dist/icons/icon-512x512.svg +9 -9
  25. package/dist/icons/icon-72x72.svg +9 -9
  26. package/dist/icons/icon-96x96.svg +9 -9
  27. package/dist/icons/icon-template.svg +9 -9
  28. package/dist/icons/qwen-logo.svg +14 -14
  29. package/dist/index.html +59 -59
  30. package/dist/logo.svg +12 -12
  31. package/dist/manifest.json +60 -60
  32. package/dist/openapi.yaml +1693 -1311
  33. package/dist/sw.js +124 -124
  34. package/dist-server/server/claude-sdk.js +38 -7
  35. package/dist-server/server/claude-sdk.js.map +1 -1
  36. package/dist-server/server/cli.js +107 -112
  37. package/dist-server/server/cli.js.map +1 -1
  38. package/dist-server/server/daemon/manager.js +33 -33
  39. package/dist-server/server/daemon-manager.js +159 -112
  40. package/dist-server/server/daemon-manager.js.map +1 -1
  41. package/dist-server/server/database/json-store.js +8 -5
  42. package/dist-server/server/database/json-store.js.map +1 -1
  43. package/dist-server/server/index.js +31 -10
  44. package/dist-server/server/index.js.map +1 -1
  45. package/dist-server/server/modules/orchestration/a2a/adapter-registry.js +45 -19
  46. package/dist-server/server/modules/orchestration/a2a/adapter-registry.js.map +1 -1
  47. package/dist-server/server/modules/orchestration/a2a/adapters/abstract-a2a.adapter.js.map +1 -1
  48. package/dist-server/server/modules/orchestration/a2a/adapters/claude-code.adapter.js +1 -0
  49. package/dist-server/server/modules/orchestration/a2a/adapters/claude-code.adapter.js.map +1 -1
  50. package/dist-server/server/modules/orchestration/a2a/adapters/codex.adapter.js +202 -0
  51. package/dist-server/server/modules/orchestration/a2a/adapters/codex.adapter.js.map +1 -0
  52. package/dist-server/server/modules/orchestration/a2a/adapters/cursor.adapter.js +205 -0
  53. package/dist-server/server/modules/orchestration/a2a/adapters/cursor.adapter.js.map +1 -0
  54. package/dist-server/server/modules/orchestration/a2a/adapters/gemini.adapter.js +205 -0
  55. package/dist-server/server/modules/orchestration/a2a/adapters/gemini.adapter.js.map +1 -0
  56. package/dist-server/server/modules/orchestration/a2a/adapters/opencode.adapter.js +205 -0
  57. package/dist-server/server/modules/orchestration/a2a/adapters/opencode.adapter.js.map +1 -0
  58. package/dist-server/server/modules/orchestration/a2a/adapters/qwen.adapter.js +205 -0
  59. package/dist-server/server/modules/orchestration/a2a/adapters/qwen.adapter.js.map +1 -0
  60. package/dist-server/server/modules/orchestration/a2a/routes.js +298 -34
  61. package/dist-server/server/modules/orchestration/a2a/routes.js.map +1 -1
  62. package/dist-server/server/modules/orchestration/a2a/task-store.js +144 -0
  63. package/dist-server/server/modules/orchestration/a2a/task-store.js.map +1 -0
  64. package/dist-server/server/modules/orchestration/a2a/validator.js +16 -0
  65. package/dist-server/server/modules/orchestration/a2a/validator.js.map +1 -1
  66. package/dist-server/server/modules/orchestration/index.js +14 -0
  67. package/dist-server/server/modules/orchestration/index.js.map +1 -1
  68. package/dist-server/server/modules/orchestration/preview/port-watcher.js +90 -0
  69. package/dist-server/server/modules/orchestration/preview/port-watcher.js.map +1 -0
  70. package/dist-server/server/modules/orchestration/preview/preview-proxy.js +58 -0
  71. package/dist-server/server/modules/orchestration/preview/preview-proxy.js.map +1 -0
  72. package/dist-server/server/modules/orchestration/preview/types.js +2 -0
  73. package/dist-server/server/modules/orchestration/preview/types.js.map +1 -0
  74. package/dist-server/server/modules/orchestration/tasks/orchestration-task-store.js +37 -0
  75. package/dist-server/server/modules/orchestration/tasks/orchestration-task-store.js.map +1 -0
  76. package/dist-server/server/modules/orchestration/tasks/orchestration-task.routes.js +68 -0
  77. package/dist-server/server/modules/orchestration/tasks/orchestration-task.routes.js.map +1 -0
  78. package/dist-server/server/modules/orchestration/tasks/orchestration-task.service.js +128 -0
  79. package/dist-server/server/modules/orchestration/tasks/orchestration-task.service.js.map +1 -0
  80. package/dist-server/server/modules/orchestration/tasks/orchestration-task.types.js +2 -0
  81. package/dist-server/server/modules/orchestration/tasks/orchestration-task.types.js.map +1 -0
  82. package/dist-server/server/modules/orchestration/workflows/built-in-workflows.js +126 -0
  83. package/dist-server/server/modules/orchestration/workflows/built-in-workflows.js.map +1 -0
  84. package/dist-server/server/modules/orchestration/workflows/workflow-runner.js +1047 -0
  85. package/dist-server/server/modules/orchestration/workflows/workflow-runner.js.map +1 -0
  86. package/dist-server/server/modules/orchestration/workflows/workflow-store.js +76 -0
  87. package/dist-server/server/modules/orchestration/workflows/workflow-store.js.map +1 -0
  88. package/dist-server/server/modules/orchestration/workflows/workflow.routes.js +151 -0
  89. package/dist-server/server/modules/orchestration/workflows/workflow.routes.js.map +1 -0
  90. package/dist-server/server/modules/orchestration/workflows/workflow.types.js +2 -0
  91. package/dist-server/server/modules/orchestration/workflows/workflow.types.js.map +1 -0
  92. package/dist-server/server/modules/orchestration/workflows/workspace-target.js +98 -0
  93. package/dist-server/server/modules/orchestration/workflows/workspace-target.js.map +1 -0
  94. package/dist-server/server/modules/orchestration/workspace/docker-workspace.js +122 -0
  95. package/dist-server/server/modules/orchestration/workspace/docker-workspace.js.map +1 -0
  96. package/dist-server/server/modules/orchestration/workspace/path-safety.js +48 -0
  97. package/dist-server/server/modules/orchestration/workspace/path-safety.js.map +1 -0
  98. package/dist-server/server/modules/orchestration/workspace/types.js +11 -0
  99. package/dist-server/server/modules/orchestration/workspace/types.js.map +1 -0
  100. package/dist-server/server/modules/orchestration/workspace/workspace-manager.js +80 -0
  101. package/dist-server/server/modules/orchestration/workspace/workspace-manager.js.map +1 -0
  102. package/dist-server/server/modules/orchestration/workspace/worktree-workspace.js +96 -0
  103. package/dist-server/server/modules/orchestration/workspace/worktree-workspace.js.map +1 -0
  104. package/dist-server/server/modules/providers/index.js +3 -0
  105. package/dist-server/server/modules/providers/index.js.map +1 -0
  106. package/dist-server/server/openai-codex.js +35 -4
  107. package/dist-server/server/openai-codex.js.map +1 -1
  108. package/dist-server/server/routes/commands.js +25 -25
  109. package/dist-server/server/routes/git.js +17 -17
  110. package/dist-server/server/routes/taskmaster.js +525 -508
  111. package/dist-server/server/routes/taskmaster.js.map +1 -1
  112. package/package.json +180 -178
  113. package/scripts/fix-node-pty.js +67 -67
  114. package/scripts/smoke/a2a-roundtrip.mjs +86 -17
  115. package/scripts/smoke/orchestration-api.mjs +172 -0
  116. package/scripts/smoke/orchestration-live-run.mjs +176 -0
  117. package/server/claude-sdk.js +898 -857
  118. package/server/cli.js +935 -940
  119. package/server/constants/config.js +4 -4
  120. package/server/cursor-cli.js +342 -342
  121. package/server/daemon/manager.js +564 -564
  122. package/server/daemon-manager.js +959 -920
  123. package/server/database/db.js +794 -794
  124. package/server/database/json-store.js +197 -194
  125. package/server/gemini-cli.js +535 -535
  126. package/server/gemini-response-handler.js +79 -79
  127. package/server/index.js +3135 -3104
  128. package/server/load-env.js +34 -34
  129. package/server/middleware/auth.js +173 -173
  130. package/server/modules/orchestration/a2a/adapter-registry.ts +72 -22
  131. package/server/modules/orchestration/a2a/adapters/abstract-a2a.adapter.ts +9 -3
  132. package/server/modules/orchestration/a2a/adapters/claude-code.adapter.ts +1 -0
  133. package/server/modules/orchestration/a2a/adapters/codex.adapter.ts +244 -0
  134. package/server/modules/orchestration/a2a/adapters/cursor.adapter.ts +249 -0
  135. package/server/modules/orchestration/a2a/adapters/gemini.adapter.ts +248 -0
  136. package/server/modules/orchestration/a2a/adapters/opencode.adapter.ts +248 -0
  137. package/server/modules/orchestration/a2a/adapters/qwen.adapter.ts +248 -0
  138. package/server/modules/orchestration/a2a/routes.ts +349 -36
  139. package/server/modules/orchestration/a2a/task-store.ts +178 -0
  140. package/server/modules/orchestration/a2a/types.ts +14 -0
  141. package/server/modules/orchestration/a2a/validator.ts +25 -2
  142. package/server/modules/orchestration/index.ts +40 -0
  143. package/server/modules/orchestration/preview/port-watcher.ts +112 -0
  144. package/server/modules/orchestration/preview/preview-proxy.ts +60 -0
  145. package/server/modules/orchestration/preview/types.ts +19 -0
  146. package/server/modules/orchestration/tasks/orchestration-task-store.ts +45 -0
  147. package/server/modules/orchestration/tasks/orchestration-task.routes.ts +73 -0
  148. package/server/modules/orchestration/tasks/orchestration-task.service.ts +145 -0
  149. package/server/modules/orchestration/tasks/orchestration-task.types.ts +29 -0
  150. package/server/modules/orchestration/workflows/built-in-workflows.ts +127 -0
  151. package/server/modules/orchestration/workflows/workflow-runner.ts +1206 -0
  152. package/server/modules/orchestration/workflows/workflow-store.ts +97 -0
  153. package/server/modules/orchestration/workflows/workflow.routes.ts +169 -0
  154. package/server/modules/orchestration/workflows/workflow.types.ts +70 -0
  155. package/server/modules/orchestration/workflows/workspace-target.ts +120 -0
  156. package/server/modules/orchestration/workspace/docker-workspace.ts +135 -0
  157. package/server/modules/orchestration/workspace/path-safety.ts +55 -0
  158. package/server/modules/orchestration/workspace/types.ts +52 -0
  159. package/server/modules/orchestration/workspace/workspace-manager.ts +97 -0
  160. package/server/modules/orchestration/workspace/worktree-workspace.ts +125 -0
  161. package/server/modules/providers/index.ts +2 -0
  162. package/server/modules/providers/list/claude/claude-auth.provider.ts +145 -145
  163. package/server/modules/providers/list/claude/claude-mcp.provider.ts +135 -135
  164. package/server/modules/providers/list/claude/claude-sessions.provider.ts +306 -306
  165. package/server/modules/providers/list/claude/claude.provider.ts +15 -15
  166. package/server/modules/providers/list/codex/codex-auth.provider.ts +115 -115
  167. package/server/modules/providers/list/codex/codex-mcp.provider.ts +135 -135
  168. package/server/modules/providers/list/codex/codex-sessions.provider.ts +319 -319
  169. package/server/modules/providers/list/codex/codex.provider.ts +15 -15
  170. package/server/modules/providers/list/cursor/cursor-auth.provider.ts +143 -143
  171. package/server/modules/providers/list/cursor/cursor-mcp.provider.ts +108 -108
  172. package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +421 -421
  173. package/server/modules/providers/list/cursor/cursor.provider.ts +15 -15
  174. package/server/modules/providers/list/gemini/gemini-auth.provider.ts +163 -163
  175. package/server/modules/providers/list/gemini/gemini-mcp.provider.ts +110 -110
  176. package/server/modules/providers/list/gemini/gemini-sessions.provider.ts +227 -227
  177. package/server/modules/providers/list/gemini/gemini.provider.ts +15 -15
  178. package/server/modules/providers/list/opencode/opencode-auth.provider.ts +130 -130
  179. package/server/modules/providers/list/opencode/opencode-mcp.provider.ts +126 -126
  180. package/server/modules/providers/list/opencode/opencode-sessions.provider.ts +232 -232
  181. package/server/modules/providers/list/opencode/opencode.provider.ts +29 -29
  182. package/server/modules/providers/list/qwen/qwen-auth.provider.ts +145 -145
  183. package/server/modules/providers/list/qwen/qwen-mcp.provider.ts +114 -114
  184. package/server/modules/providers/list/qwen/qwen-sessions.provider.ts +265 -265
  185. package/server/modules/providers/list/qwen/qwen.provider.ts +21 -21
  186. package/server/modules/providers/provider.registry.ts +40 -40
  187. package/server/modules/providers/provider.routes.ts +819 -819
  188. package/server/modules/providers/services/mcp.service.ts +86 -86
  189. package/server/modules/providers/services/provider-auth.service.ts +26 -26
  190. package/server/modules/providers/services/sessions.service.ts +45 -45
  191. package/server/modules/providers/shared/base/abstract.provider.ts +20 -20
  192. package/server/modules/providers/shared/mcp/mcp.provider.ts +151 -151
  193. package/server/modules/providers/shared/provider-configs.ts +142 -142
  194. package/server/modules/providers/tests/mcp.test.ts +293 -293
  195. package/server/openai-codex.js +462 -426
  196. package/server/opencode-cli.js +459 -459
  197. package/server/opencode-response-handler.js +107 -107
  198. package/server/projects.js +3105 -3105
  199. package/server/qwen-code-cli.js +395 -395
  200. package/server/qwen-response-handler.js +73 -73
  201. package/server/routes/agent.js +1365 -1365
  202. package/server/routes/auth.js +138 -138
  203. package/server/routes/codex.js +19 -19
  204. package/server/routes/commands.js +554 -554
  205. package/server/routes/cursor.js +52 -52
  206. package/server/routes/gemini.js +24 -24
  207. package/server/routes/git.js +1488 -1488
  208. package/server/routes/mcp-utils.js +31 -31
  209. package/server/routes/messages.js +61 -61
  210. package/server/routes/network.js +120 -120
  211. package/server/routes/plugins.js +318 -318
  212. package/server/routes/projects.js +915 -915
  213. package/server/routes/qwen.js +27 -27
  214. package/server/routes/settings.js +286 -286
  215. package/server/routes/taskmaster.js +1496 -1471
  216. package/server/routes/telegram.js +125 -125
  217. package/server/routes/user.js +123 -123
  218. package/server/services/external-access.js +171 -171
  219. package/server/services/install-jobs.js +571 -571
  220. package/server/services/notification-orchestrator.js +242 -242
  221. package/server/services/provider-credentials.js +189 -189
  222. package/server/services/provider-models.js +381 -381
  223. package/server/services/telegram/bot.js +279 -279
  224. package/server/services/telegram/telegram-http-client.js +130 -130
  225. package/server/services/telegram/translations.js +170 -170
  226. package/server/services/vapid-keys.js +36 -36
  227. package/server/sessionManager.js +225 -225
  228. package/server/shared/interfaces.ts +54 -54
  229. package/server/shared/types.ts +172 -172
  230. package/server/shared/utils.ts +193 -193
  231. package/server/tsconfig.json +36 -36
  232. package/server/utils/colors.js +21 -21
  233. package/server/utils/commandParser.js +303 -303
  234. package/server/utils/frontmatter.js +18 -18
  235. package/server/utils/gitConfig.js +34 -34
  236. package/server/utils/mcp-detector.js +147 -147
  237. package/server/utils/plugin-loader.js +457 -457
  238. package/server/utils/plugin-process-manager.js +184 -184
  239. package/server/utils/port-access.js +209 -209
  240. package/server/utils/runtime-paths.js +37 -37
  241. package/server/utils/taskmaster-websocket.js +128 -128
  242. package/server/utils/url-detection.js +71 -71
  243. package/server/vite-daemon.js +78 -78
  244. package/shared/modelConstants.js +162 -162
  245. package/shared/networkHosts.js +22 -22
  246. package/dist/assets/index-B1ghfb4w.css +0 -32
  247. package/dist/assets/index-BvClqlMf.js +0 -852
package/dist/openapi.yaml CHANGED
@@ -1,1311 +1,1693 @@
1
- openapi: 3.1.0
2
- info:
3
- title: Pixcode REST API
4
- version: 1.33.10
5
- description: |
6
- REST API for Pixcode — the multi-CLI web UI for Claude Code, Cursor CLI,
7
- Codex, Gemini CLI, Qwen Code, and OpenCode.
8
-
9
- ## Authentication
10
-
11
- Most endpoints require authentication. Two schemes are accepted:
12
-
13
- - **JWT cookie** (`token` HTTP-only cookie) — set automatically when the
14
- browser logs in via `POST /api/auth/login`.
15
- - **API key** (`Authorization: Bearer ck_...`) — generated under
16
- Settings → API. API keys never expire and survive server restarts.
17
-
18
- Endpoints flagged `apiKey` accept both.
19
-
20
- ## Streaming endpoints
21
-
22
- Three classes of endpoint stream beyond plain JSON:
23
-
24
- - **WebSocket** (`/ws`, `/shell`) — chat session bidirectional traffic. Not
25
- documented here; see `docs/websocket-protocol.md` if it exists, or read
26
- `server/index.js` `handleChatConnection`.
27
- - **SSE** (Server-Sent Events) — long-running jobs. Each `data:` frame
28
- contains a JSON event; the stream ends with `event: done` or `event: error`.
29
- - **NDJSON** — provider chat output (one JSON event per line) when the
30
- backend forwards from a CLI's `--format json` mode.
31
-
32
- ## Errors
33
-
34
- Errors share a consistent envelope:
35
-
36
- ```json
37
- { "success": false, "error": { "code": "ROUTE_NOT_FOUND", "message": "..." } }
38
- ```
39
-
40
- contact:
41
- name: Pixcode on GitHub
42
- url: https://github.com/alicomert/pixcode
43
- license:
44
- name: AGPL-3.0-or-later
45
- url: https://www.gnu.org/licenses/agpl-3.0.txt
46
-
47
- servers:
48
- - url: http://localhost:3001
49
- description: Local development server
50
- - url: '{protocol}://{host}'
51
- description: Self-hosted Pixcode instance
52
- variables:
53
- protocol:
54
- enum: [http, https]
55
- default: http
56
- host:
57
- default: localhost:3001
58
-
59
- tags:
60
- - name: System
61
- description: Health, version, and self-update.
62
- - name: Authentication
63
- description: Login, register, JWT lifecycle, API keys.
64
- - name: Projects
65
- description: Project CRUD and session enumeration.
66
- - name: Files
67
- description: Project filesystem read/write and directory traversal.
68
- - name: Sessions
69
- description: Conversation sessions across providers.
70
- - name: Git
71
- description: Git status, diffs, branches, commits, push/pull.
72
- - name: Providers
73
- description: Multi-CLI provider auth, install, sessions, configuration.
74
- - name: Network
75
- description: LAN discovery, UPnP, public tunnel.
76
- - name: Settings
77
- description: User-scoped preferences and notification channels.
78
- - name: Search
79
- description: Full-text search across conversations.
80
- - name: MCP
81
- description: Model Context Protocol servers and tooling.
82
-
83
- components:
84
- securitySchemes:
85
- bearerAuth:
86
- type: http
87
- scheme: bearer
88
- bearerFormat: JWT
89
- description: |
90
- `Authorization: Bearer <token>` — token may be a JWT (issued by
91
- `/api/auth/login`) or an API key (prefix `ck_`, generated under
92
- Settings API). The middleware sniffs the prefix to decide.
93
- apiKeyAuth:
94
- type: apiKey
95
- in: header
96
- name: X-API-Key
97
- description: |
98
- Alternative for tools that can't set `Authorization`. Accepts the same
99
- `ck_...` keys as `bearerAuth`. Either header works on every secured
100
- endpoint pick whichever your client supports.
101
- cookieAuth:
102
- type: apiKey
103
- in: cookie
104
- name: token
105
- description: HTTP-only `token` cookie set by `/api/auth/login`.
106
-
107
- schemas:
108
- Error:
109
- type: object
110
- required: [success, error]
111
- properties:
112
- success: { type: boolean, enum: [false] }
113
- error:
114
- type: object
115
- required: [code, message]
116
- properties:
117
- code: { type: string, example: ROUTE_NOT_FOUND }
118
- message: { type: string }
119
-
120
- Health:
121
- type: object
122
- required: [status, timestamp]
123
- properties:
124
- status: { type: string, enum: [ok] }
125
- timestamp: { type: string, format: date-time }
126
- version:
127
- type: string
128
- description: Server version (matches semver `MAJOR.MINOR.PATCH`).
129
- example: 1.33.9
130
- installMode:
131
- type: string
132
- enum: [git, npm-global, runtime-dir, docker]
133
-
134
- User:
135
- type: object
136
- properties:
137
- id: { type: integer }
138
- username: { type: string }
139
- email: { type: string, format: email, nullable: true }
140
- created_at: { type: string, format: date-time }
141
-
142
- AuthStatus:
143
- type: object
144
- properties:
145
- success: { type: boolean }
146
- isAuthenticated: { type: boolean }
147
- needsSetup: { type: boolean, description: 'true if no users exist yet — UI shows registration screen.' }
148
- user: { $ref: '#/components/schemas/User' }
149
-
150
- LoginRequest:
151
- type: object
152
- required: [username, password]
153
- properties:
154
- username: { type: string }
155
- password: { type: string, format: password }
156
-
157
- LoginResponse:
158
- type: object
159
- properties:
160
- success: { type: boolean }
161
- token: { type: string, description: JWT (also set as `token` cookie). }
162
- user: { $ref: '#/components/schemas/User' }
163
-
164
- ApiKey:
165
- type: object
166
- properties:
167
- id: { type: integer }
168
- key_name: { type: string }
169
- api_key: { type: string, description: 'Format: `ck_<32-hex>`. Returned in full on creation only.' }
170
- created_at: { type: string, format: date-time }
171
- last_used: { type: string, format: date-time, nullable: true }
172
- is_active: { type: boolean }
173
-
174
- Project:
175
- type: object
176
- properties:
177
- name: { type: string }
178
- displayName: { type: string }
179
- path: { type: string }
180
- fullPath: { type: string }
181
- sessions:
182
- type: array
183
- items: { $ref: '#/components/schemas/SessionMeta' }
184
-
185
- SessionMeta:
186
- type: object
187
- properties:
188
- id: { type: string }
189
- title: { type: string, nullable: true }
190
- provider:
191
- type: string
192
- enum: [claude, cursor, codex, gemini, qwen, opencode]
193
- lastActivity: { type: string, format: date-time }
194
-
195
- GitStatus:
196
- type: object
197
- properties:
198
- branch: { type: string }
199
- ahead: { type: integer }
200
- behind: { type: integer }
201
- modified: { type: array, items: { type: string } }
202
- added: { type: array, items: { type: string } }
203
- deleted: { type: array, items: { type: string } }
204
- untracked: { type: array, items: { type: string } }
205
-
206
- ProviderInfo:
207
- type: object
208
- properties:
209
- id:
210
- type: string
211
- enum: [claude, cursor, codex, gemini, qwen, opencode]
212
- installed: { type: boolean }
213
- authenticated: { type: boolean }
214
- version: { type: string, nullable: true }
215
- binaryPath: { type: string, nullable: true }
216
-
217
- InstallJob:
218
- type: object
219
- properties:
220
- jobId: { type: string }
221
- provider: { type: string }
222
- status: { type: string, enum: [pending, running, succeeded, failed, cancelled] }
223
-
224
- security:
225
- - bearerAuth: []
226
- - apiKeyAuth: []
227
- - cookieAuth: []
228
-
229
- paths:
230
- /health:
231
- get:
232
- tags: [System]
233
- summary: Liveness + version probe
234
- description: |
235
- Public, unauthenticated. Returns server version and install mode so the
236
- UI can detect updates and stale daemons. Used by:
237
-
238
- - The version-upgrade modal — polls during/after `/api/system/update`
239
- to detect when the new version is up.
240
- - `useVersionCheck` falls back to the bundle's baked
241
- `__PIXCODE_UI_VERSION__` if `version` is missing or non-semver.
242
- security: []
243
- responses:
244
- '200':
245
- description: Server is up.
246
- content:
247
- application/json:
248
- schema: { $ref: '#/components/schemas/Health' }
249
-
250
- /api/system/update:
251
- post:
252
- tags: [System]
253
- summary: Self-update (SSE)
254
- description: |
255
- Streams the update process via SSE. Behavior depends on
256
- `installMode`:
257
-
258
- - **runtime-dir** (desktop wrapper): downloads the latest npm tarball,
259
- atomically swaps files, emits `done { selfRestarting: true }`, then
260
- `process.exit(42)` so the wrapper respawns. **Don't `POST /restart`
261
- when `selfRestarting` is true.**
262
- - **git/npm-global**: runs `git pull && npm install` or
263
- `npm install -g`. The supervising daemon may restart the server
264
- mid-stream — clients should treat a bare close + `/health` version
265
- bump as success.
266
- responses:
267
- '200':
268
- description: 'SSE stream of `event: log`, `event: progress`, `event: done`, `event: error`.'
269
- content:
270
- text/event-stream:
271
- schema: { type: string }
272
-
273
- /api/system/restart:
274
- post:
275
- tags: [System]
276
- summary: Restart the server process
277
- description: |
278
- Triggers a graceful exit; the supervising daemon (systemd/pm2/electron
279
- wrapper) is expected to respawn. Don't call after a `selfRestarting`
280
- update event the wrapper has already been signalled.
281
- responses:
282
- '200':
283
- description: Restart scheduled.
284
-
285
- /api/auth/status:
286
- get:
287
- tags: [Authentication]
288
- summary: Probe authentication state
289
- description: Returns whether the current request carries a valid token, and whether the system has any users at all (`needsSetup`).
290
- security: []
291
- responses:
292
- '200':
293
- description: Auth status.
294
- content:
295
- application/json:
296
- schema: { $ref: '#/components/schemas/AuthStatus' }
297
-
298
- /api/auth/register:
299
- post:
300
- tags: [Authentication]
301
- summary: Register the first user
302
- description: Only allowed while `needsSetup` is true. Subsequent calls return 403.
303
- security: []
304
- requestBody:
305
- required: true
306
- content:
307
- application/json:
308
- schema: { $ref: '#/components/schemas/LoginRequest' }
309
- responses:
310
- '200':
311
- description: Registered + auto-logged-in.
312
- content:
313
- application/json:
314
- schema: { $ref: '#/components/schemas/LoginResponse' }
315
- '403':
316
- description: Setup already complete.
317
- content:
318
- application/json:
319
- schema: { $ref: '#/components/schemas/Error' }
320
-
321
- /api/auth/login:
322
- post:
323
- tags: [Authentication]
324
- summary: Log in
325
- security: []
326
- requestBody:
327
- required: true
328
- content:
329
- application/json:
330
- schema: { $ref: '#/components/schemas/LoginRequest' }
331
- responses:
332
- '200':
333
- description: Login OK; sets `token` cookie + returns JWT in body.
334
- content:
335
- application/json:
336
- schema: { $ref: '#/components/schemas/LoginResponse' }
337
- '401':
338
- description: Invalid credentials.
339
-
340
- /api/auth/user:
341
- get:
342
- tags: [Authentication]
343
- summary: Current user
344
- responses:
345
- '200':
346
- description: Authenticated user details.
347
- content:
348
- application/json:
349
- schema:
350
- type: object
351
- properties:
352
- user: { $ref: '#/components/schemas/User' }
353
-
354
- /api/auth/logout:
355
- post:
356
- tags: [Authentication]
357
- summary: Log out
358
- description: Clears the `token` cookie. JWT remains valid until expiry — server-side blacklist isn't implemented.
359
- responses:
360
- '200': { description: OK }
361
-
362
- /api/settings/api-keys:
363
- get:
364
- tags: [Authentication]
365
- summary: List user API keys
366
- responses:
367
- '200':
368
- description: List of keys (the `api_key` field is masked except on creation).
369
- content:
370
- application/json:
371
- schema:
372
- type: array
373
- items: { $ref: '#/components/schemas/ApiKey' }
374
- post:
375
- tags: [Authentication]
376
- summary: Create an API key
377
- requestBody:
378
- required: true
379
- content:
380
- application/json:
381
- schema:
382
- type: object
383
- required: [name]
384
- properties:
385
- name: { type: string, description: 'Human-readable label.' }
386
- responses:
387
- '201':
388
- description: Key created. The full `api_key` value is returned **once** — store it.
389
- content:
390
- application/json:
391
- schema: { $ref: '#/components/schemas/ApiKey' }
392
-
393
- /api/settings/api-keys/{keyId}:
394
- delete:
395
- tags: [Authentication]
396
- summary: Delete an API key
397
- parameters:
398
- - name: keyId
399
- in: path
400
- required: true
401
- schema: { type: integer }
402
- responses:
403
- '200': { description: Deleted. }
404
-
405
- /api/settings/api-keys/{keyId}/toggle:
406
- patch:
407
- tags: [Authentication]
408
- summary: Activate / deactivate an API key
409
- parameters:
410
- - name: keyId
411
- in: path
412
- required: true
413
- schema: { type: integer }
414
- requestBody:
415
- required: true
416
- content:
417
- application/json:
418
- schema:
419
- type: object
420
- properties:
421
- is_active: { type: boolean }
422
- responses:
423
- '200': { description: Updated. }
424
-
425
- /api/projects:
426
- get:
427
- tags: [Projects]
428
- summary: List all projects
429
- description: Walks `~/.claude/projects/*` plus any registered workspaces and returns a unified list. Sessions are flattened by provider.
430
- responses:
431
- '200':
432
- description: Project list.
433
- content:
434
- application/json:
435
- schema:
436
- type: array
437
- items: { $ref: '#/components/schemas/Project' }
438
-
439
- /api/projects/quick-start:
440
- post:
441
- tags: [Projects]
442
- summary: Open or create a project from an absolute path
443
- requestBody:
444
- required: true
445
- content:
446
- application/json:
447
- schema:
448
- type: object
449
- required: [path]
450
- properties:
451
- path: { type: string, description: 'Absolute filesystem path.' }
452
- responses:
453
- '200':
454
- description: Project record (created if it didn't exist).
455
- content:
456
- application/json:
457
- schema: { $ref: '#/components/schemas/Project' }
458
-
459
- /api/projects/{projectName}/rename:
460
- put:
461
- tags: [Projects]
462
- summary: Rename project display
463
- parameters:
464
- - { name: projectName, in: path, required: true, schema: { type: string } }
465
- requestBody:
466
- required: true
467
- content:
468
- application/json:
469
- schema:
470
- type: object
471
- properties:
472
- displayName: { type: string }
473
- responses:
474
- '200': { description: Renamed. }
475
-
476
- /api/projects/{projectName}:
477
- delete:
478
- tags: [Projects]
479
- summary: Delete (deregister) a project
480
- parameters:
481
- - { name: projectName, in: path, required: true, schema: { type: string } }
482
- responses:
483
- '200': { description: Deleted. }
484
-
485
- /api/projects/{projectName}/sessions:
486
- get:
487
- tags: [Sessions]
488
- summary: List sessions for a project
489
- parameters:
490
- - { name: projectName, in: path, required: true, schema: { type: string } }
491
- responses:
492
- '200':
493
- description: Sessions sorted by lastActivity desc.
494
- content:
495
- application/json:
496
- schema:
497
- type: array
498
- items: { $ref: '#/components/schemas/SessionMeta' }
499
-
500
- /api/projects/{projectName}/sessions/{sessionId}:
501
- delete:
502
- tags: [Sessions]
503
- summary: Delete a session
504
- parameters:
505
- - { name: projectName, in: path, required: true, schema: { type: string } }
506
- - { name: sessionId, in: path, required: true, schema: { type: string } }
507
- responses:
508
- '200': { description: Deleted. }
509
-
510
- /api/sessions/{sessionId}/rename:
511
- put:
512
- tags: [Sessions]
513
- summary: Rename a session
514
- parameters:
515
- - { name: sessionId, in: path, required: true, schema: { type: string } }
516
- requestBody:
517
- required: true
518
- content:
519
- application/json:
520
- schema:
521
- type: object
522
- properties:
523
- title: { type: string }
524
- responses:
525
- '200': { description: Renamed. }
526
-
527
- /api/sessions/{sessionId}/messages:
528
- get:
529
- tags: [Sessions]
530
- summary: Get session message history
531
- description: |
532
- Note: this is mounted at `/api/sessions`, NOT under `/api/projects` — the
533
- `projectName` is supplied as a query parameter rather than a path
534
- segment. The mount lives in `server/routes/messages.js`.
535
- parameters:
536
- - { name: sessionId, in: path, required: true, schema: { type: string } }
537
- - { name: projectName, in: query, required: true, schema: { type: string }, description: Pixcode project the session belongs to. }
538
- - { name: limit, in: query, required: false, schema: { type: integer, default: 100 } }
539
- - { name: offset, in: query, required: false, schema: { type: integer, default: 0 } }
540
- responses:
541
- '200':
542
- description: Normalized message stream.
543
- content:
544
- application/json:
545
- schema:
546
- type: object
547
- properties:
548
- messages: { type: array, items: { type: object, additionalProperties: true } }
549
- total: { type: integer }
550
- hasMore: { type: boolean }
551
-
552
- /api/search/conversations:
553
- get:
554
- tags: [Search]
555
- summary: Full-text search across all sessions
556
- parameters:
557
- - { name: q, in: query, required: true, schema: { type: string }, description: Search query. }
558
- - { name: provider, in: query, required: false, schema: { type: string, enum: [claude, cursor, codex, gemini, qwen, opencode] } }
559
- - { name: limit, in: query, required: false, schema: { type: integer, default: 50 } }
560
- responses:
561
- '200':
562
- description: Ranked matches.
563
- content:
564
- application/json:
565
- schema:
566
- type: object
567
- properties:
568
- results: { type: array, items: { type: object, additionalProperties: true } }
569
- total: { type: integer }
570
-
571
- /api/projects/{projectName}/files:
572
- get:
573
- tags: [Files]
574
- summary: List files in a project subtree
575
- parameters:
576
- - { name: projectName, in: path, required: true, schema: { type: string } }
577
- - { name: path, in: query, required: false, schema: { type: string }, description: Subdirectory relative to project root. }
578
- responses:
579
- '200':
580
- description: Directory listing.
581
- content:
582
- application/json:
583
- schema:
584
- type: array
585
- items:
586
- type: object
587
- properties:
588
- name: { type: string }
589
- path: { type: string }
590
- type: { type: string, enum: [file, directory] }
591
- size: { type: integer, nullable: true }
592
- delete:
593
- tags: [Files]
594
- summary: Delete a file or folder (path in body)
595
- description: |
596
- Same path as the listing endpoint above — discriminated by HTTP method.
597
- The target's project-relative path goes in the body, NOT the query
598
- string (so directory deletes can't be partially URL-encoded into a
599
- broken state).
600
- parameters:
601
- - { name: projectName, in: path, required: true, schema: { type: string } }
602
- requestBody:
603
- required: true
604
- content:
605
- application/json:
606
- schema:
607
- type: object
608
- required: [path]
609
- properties:
610
- path: { type: string, description: 'Project-relative path of the file or directory to delete.' }
611
- type: { type: string, enum: [file, directory], description: 'Optional hint; server detects automatically if omitted.' }
612
- responses:
613
- '200': { description: Deleted. }
614
-
615
- /api/projects/{projectName}/file:
616
- get:
617
- tags: [Files]
618
- summary: Read a single file
619
- parameters:
620
- - { name: projectName, in: path, required: true, schema: { type: string } }
621
- - { name: path, in: query, required: true, schema: { type: string } }
622
- responses:
623
- '200':
624
- description: File contents (utf-8 text or base64 binary).
625
- content:
626
- application/json:
627
- schema:
628
- type: object
629
- properties:
630
- content: { type: string }
631
- encoding: { type: string, enum: [utf-8, base64] }
632
- put:
633
- tags: [Files]
634
- summary: Overwrite a file
635
- parameters:
636
- - { name: projectName, in: path, required: true, schema: { type: string } }
637
- requestBody:
638
- required: true
639
- content:
640
- application/json:
641
- schema:
642
- type: object
643
- required: [path, content]
644
- properties:
645
- path: { type: string }
646
- content: { type: string }
647
- responses:
648
- '200': { description: Saved. }
649
-
650
- /api/projects/{projectName}/files/create:
651
- post:
652
- tags: [Files]
653
- summary: Create a new file or folder
654
- parameters:
655
- - { name: projectName, in: path, required: true, schema: { type: string } }
656
- requestBody:
657
- required: true
658
- content:
659
- application/json:
660
- schema:
661
- type: object
662
- required: [path, type]
663
- properties:
664
- path: { type: string }
665
- type: { type: string, enum: [file, directory] }
666
- content: { type: string, description: 'Initial content for files; ignored for directories.' }
667
- responses:
668
- '201': { description: Created. }
669
-
670
- /api/projects/{projectName}/files/rename:
671
- put:
672
- tags: [Files]
673
- summary: Rename / move a file
674
- parameters:
675
- - { name: projectName, in: path, required: true, schema: { type: string } }
676
- requestBody:
677
- required: true
678
- content:
679
- application/json:
680
- schema:
681
- type: object
682
- required: [oldPath, newPath]
683
- properties:
684
- oldPath: { type: string }
685
- newPath: { type: string }
686
- responses:
687
- '200': { description: Renamed. }
688
-
689
-
690
- /api/browse-filesystem:
691
- get:
692
- tags: [Files]
693
- summary: Native filesystem browser (outside project tree)
694
- description: Used by Quick Start to let the user pick a folder anywhere on the host. Honours `~` expansion.
695
- parameters:
696
- - { name: path, in: query, required: false, schema: { type: string, default: '~' } }
697
- responses:
698
- '200':
699
- description: Directory listing.
700
- content:
701
- application/json:
702
- schema:
703
- type: object
704
- properties:
705
- path: { type: string }
706
- parent: { type: string, nullable: true }
707
- entries:
708
- type: array
709
- items:
710
- type: object
711
- properties:
712
- name: { type: string }
713
- type: { type: string, enum: [file, directory] }
714
-
715
- /api/git/status:
716
- get:
717
- tags: [Git]
718
- summary: Working tree status
719
- parameters:
720
- - { name: project, in: query, required: true, schema: { type: string } }
721
- responses:
722
- '200':
723
- description: Git status snapshot.
724
- content:
725
- application/json:
726
- schema: { $ref: '#/components/schemas/GitStatus' }
727
-
728
- /api/git/diff:
729
- get:
730
- tags: [Git]
731
- summary: Unified diff for one file or the whole tree
732
- parameters:
733
- - { name: project, in: query, required: true, schema: { type: string } }
734
- - { name: file, in: query, required: false, schema: { type: string } }
735
- - { name: staged, in: query, required: false, schema: { type: boolean, default: false } }
736
- responses:
737
- '200':
738
- description: Diff text.
739
- content:
740
- application/json:
741
- schema:
742
- type: object
743
- properties:
744
- diff: { type: string }
745
-
746
- /api/git/branches:
747
- get:
748
- tags: [Git]
749
- summary: List local + remote branches
750
- parameters:
751
- - { name: project, in: query, required: true, schema: { type: string } }
752
- responses:
753
- '200':
754
- description: Branch list.
755
- content:
756
- application/json:
757
- schema:
758
- type: object
759
- properties:
760
- current: { type: string }
761
- local: { type: array, items: { type: string } }
762
- remote: { type: array, items: { type: string } }
763
-
764
- /api/git/commit:
765
- post:
766
- tags: [Git]
767
- summary: Create a commit
768
- requestBody:
769
- required: true
770
- content:
771
- application/json:
772
- schema:
773
- type: object
774
- required: [project, message]
775
- properties:
776
- project: { type: string }
777
- message: { type: string }
778
- files: { type: array, items: { type: string }, description: 'When omitted, all staged changes are committed.' }
779
- responses:
780
- '200': { description: Commit created. }
781
-
782
- /api/git/push:
783
- post:
784
- tags: [Git]
785
- summary: Push to remote
786
- requestBody:
787
- required: true
788
- content:
789
- application/json:
790
- schema:
791
- type: object
792
- required: [project]
793
- properties:
794
- project: { type: string }
795
- remote: { type: string, default: origin }
796
- branch: { type: string }
797
- force: { type: boolean, default: false }
798
- responses:
799
- '200': { description: Pushed. }
800
-
801
- /api/git/pull:
802
- post:
803
- tags: [Git]
804
- summary: Pull from remote
805
- requestBody:
806
- required: true
807
- content:
808
- application/json:
809
- schema:
810
- type: object
811
- required: [project]
812
- properties:
813
- project: { type: string }
814
- responses:
815
- '200': { description: Pulled. }
816
-
817
- /api/git/checkout:
818
- post:
819
- tags: [Git]
820
- summary: Switch branch
821
- requestBody:
822
- required: true
823
- content:
824
- application/json:
825
- schema:
826
- type: object
827
- required: [project, branch]
828
- properties:
829
- project: { type: string }
830
- branch: { type: string }
831
- responses:
832
- '200': { description: Switched. }
833
-
834
- /api/providers/credentials:
835
- get:
836
- tags: [Providers]
837
- summary: List stored credentials across providers
838
- description: Returns a sanitised inventory of API keys / OAuth tokens Pixcode is currently holding for each provider. Real secret values are NOT returned — only presence + masked tail.
839
- responses:
840
- '200':
841
- description: Credentials inventory.
842
- content:
843
- application/json:
844
- schema:
845
- type: object
846
- additionalProperties:
847
- type: object
848
- properties:
849
- hasCredential: { type: boolean }
850
- masked: { type: string, nullable: true, example: '...beef' }
851
-
852
- /api/providers/{provider}/auth/status:
853
- get:
854
- tags: [Providers]
855
- summary: Auth status for a single provider
856
- description: |
857
- Returns whether the provider's CLI is installed, whether it has a
858
- valid auth credential (api key / OAuth token), and the resolved
859
- binary path the spawn layer will use.
860
- parameters:
861
- - { name: provider, in: path, required: true, schema: { type: string, enum: [claude, cursor, codex, gemini, qwen, opencode] } }
862
- responses:
863
- '200':
864
- description: Auth status snapshot.
865
- content:
866
- application/json:
867
- schema: { $ref: '#/components/schemas/ProviderInfo' }
868
-
869
- /api/providers/{provider}/auth/api-key:
870
- post:
871
- tags: [Providers]
872
- summary: Save / replace an API-key credential for a provider
873
- parameters:
874
- - { name: provider, in: path, required: true, schema: { type: string } }
875
- requestBody:
876
- required: true
877
- content:
878
- application/json:
879
- schema:
880
- type: object
881
- required: [apiKey]
882
- properties:
883
- apiKey: { type: string }
884
- baseUrl: { type: string, description: Optional override (e.g. self-hosted Anthropic compat endpoint). }
885
- responses:
886
- '200': { description: Credential saved. }
887
-
888
- /api/providers/{provider}/oauth-paste:
889
- post:
890
- tags: [Providers]
891
- summary: Paste an OAuth callback URL to complete login
892
- description: |
893
- For providers (Claude, Cursor) whose login flow opens a browser tab and
894
- bounces back to a URL the user copies into Pixcode. The handler parses
895
- the token and stores it as the active credential.
896
- parameters:
897
- - { name: provider, in: path, required: true, schema: { type: string } }
898
- requestBody:
899
- required: true
900
- content:
901
- application/json:
902
- schema:
903
- type: object
904
- required: [url]
905
- properties:
906
- url: { type: string, format: uri }
907
- responses:
908
- '200': { description: Token extracted and stored. }
909
- '400': { description: URL did not contain a recognisable token. }
910
-
911
- /api/providers/{provider}/models:
912
- get:
913
- tags: [Providers]
914
- summary: List models the provider's CLI exposes
915
- description: |
916
- Pixcode caches the model list per provider on first call (or when the
917
- cache is busted via `DELETE …/models/cache`). Each entry is the
918
- `provider/model` form OpenCode expects.
919
- parameters:
920
- - { name: provider, in: path, required: true, schema: { type: string } }
921
- responses:
922
- '200':
923
- description: Model catalog.
924
- content:
925
- application/json:
926
- schema:
927
- type: array
928
- items:
929
- type: object
930
- properties:
931
- id: { type: string, example: 'opencode/gpt-5.2' }
932
- name: { type: string }
933
- contextWindow: { type: integer, nullable: true }
934
-
935
- /api/providers/{provider}/models/cache:
936
- delete:
937
- tags: [Providers]
938
- summary: Bust the cached model list for one provider
939
- parameters:
940
- - { name: provider, in: path, required: true, schema: { type: string } }
941
- responses:
942
- '200': { description: Cache cleared; next GET re-fetches. }
943
-
944
- /api/providers/{provider}/install:
945
- post:
946
- tags: [Providers]
947
- summary: Install / update a provider CLI in the Pixcode sandbox
948
- description: |
949
- Installs the provider's npm package into `~/.pixcode/cli-bin/` (no
950
- `-g`, no sudo/UAC). Returns a `jobId` immediately; subscribe to
951
- `/install/{jobId}/stream` for live logs.
952
- parameters:
953
- - { name: provider, in: path, required: true, schema: { type: string } }
954
- responses:
955
- '202':
956
- description: Job accepted.
957
- content:
958
- application/json:
959
- schema: { $ref: '#/components/schemas/InstallJob' }
960
-
961
- /api/providers/{provider}/install/{jobId}/stream:
962
- get:
963
- tags: [Providers]
964
- summary: Stream install job output (SSE)
965
- description: Replays buffered output, then streams live until the job ends. Send `Last-Event-ID` to resume after disconnect.
966
- parameters:
967
- - { name: provider, in: path, required: true, schema: { type: string } }
968
- - { name: jobId, in: path, required: true, schema: { type: string } }
969
- responses:
970
- '200':
971
- description: 'SSE event stream — `event: log`, `event: status`, `event: done`, `event: error`.'
972
- content:
973
- text/event-stream:
974
- schema: { type: string }
975
-
976
- /api/providers/{provider}/install/{jobId}:
977
- delete:
978
- tags: [Providers]
979
- summary: Cancel an in-flight install
980
- parameters:
981
- - { name: provider, in: path, required: true, schema: { type: string } }
982
- - { name: jobId, in: path, required: true, schema: { type: string } }
983
- responses:
984
- '200': { description: Cancelled. }
985
-
986
- /api/providers/{provider}/mcp/servers:
987
- get:
988
- tags: [MCP]
989
- summary: List MCP servers configured for one provider
990
- parameters:
991
- - { name: provider, in: path, required: true, schema: { type: string } }
992
- responses:
993
- '200':
994
- description: MCP server list (matches the provider's native config schema).
995
- content:
996
- application/json:
997
- schema:
998
- type: array
999
- items: { type: object, additionalProperties: true }
1000
- post:
1001
- tags: [MCP]
1002
- summary: Add or replace an MCP server entry
1003
- parameters:
1004
- - { name: provider, in: path, required: true, schema: { type: string } }
1005
- requestBody:
1006
- required: true
1007
- content:
1008
- application/json:
1009
- schema:
1010
- type: object
1011
- required: [name, command]
1012
- properties:
1013
- name: { type: string }
1014
- command: { type: string }
1015
- args: { type: array, items: { type: string } }
1016
- env: { type: object, additionalProperties: { type: string } }
1017
- scope: { type: string, enum: [local, user], default: user }
1018
- responses:
1019
- '200': { description: Server saved. }
1020
-
1021
- /api/providers/{provider}/mcp/servers/{name}:
1022
- delete:
1023
- tags: [MCP]
1024
- summary: Remove an MCP server entry
1025
- parameters:
1026
- - { name: provider, in: path, required: true, schema: { type: string } }
1027
- - { name: name, in: path, required: true, schema: { type: string } }
1028
- responses:
1029
- '200': { description: Removed. }
1030
-
1031
- /api/providers/mcp/servers/global:
1032
- post:
1033
- tags: [MCP]
1034
- summary: Add an MCP server to every provider that supports MCP
1035
- description: Convenience endpoint that fans out the same server config to all MCP-capable providers (Claude, Cursor, Codex, OpenCode). Per-provider edits override.
1036
- requestBody:
1037
- required: true
1038
- content:
1039
- application/json:
1040
- schema:
1041
- type: object
1042
- required: [name, command]
1043
- properties:
1044
- name: { type: string }
1045
- command: { type: string }
1046
- args: { type: array, items: { type: string } }
1047
- env: { type: object, additionalProperties: { type: string } }
1048
- responses:
1049
- '200': { description: Server fanned out. }
1050
-
1051
- /api/providers/{provider}/config-files:
1052
- get:
1053
- tags: [Providers]
1054
- summary: List config files Pixcode knows about for a provider
1055
- description: |
1056
- Returns the catalog of editable config files for a provider typically
1057
- `settings.json`, `auth.json`, `opencode.json`, etc. Each entry has an
1058
- opaque `fileId` used by `GET/PUT …/{fileId}`.
1059
- parameters:
1060
- - { name: provider, in: path, required: true, schema: { type: string } }
1061
- responses:
1062
- '200':
1063
- description: Config file catalog.
1064
- content:
1065
- application/json:
1066
- schema:
1067
- type: array
1068
- items:
1069
- type: object
1070
- properties:
1071
- fileId: { type: string }
1072
- path: { type: string }
1073
- label: { type: string }
1074
- exists: { type: boolean }
1075
- size: { type: integer, nullable: true }
1076
-
1077
- /api/providers/{provider}/config-files/{fileId}:
1078
- get:
1079
- tags: [Providers]
1080
- summary: Read a provider config file's contents
1081
- parameters:
1082
- - { name: provider, in: path, required: true, schema: { type: string } }
1083
- - { name: fileId, in: path, required: true, schema: { type: string } }
1084
- responses:
1085
- '200':
1086
- description: File contents.
1087
- content:
1088
- application/json:
1089
- schema:
1090
- type: object
1091
- properties:
1092
- content: { type: string }
1093
- path: { type: string }
1094
- encoding: { type: string, enum: [utf-8] }
1095
- put:
1096
- tags: [Providers]
1097
- summary: Overwrite a provider config file
1098
- parameters:
1099
- - { name: provider, in: path, required: true, schema: { type: string } }
1100
- - { name: fileId, in: path, required: true, schema: { type: string } }
1101
- requestBody:
1102
- required: true
1103
- content:
1104
- application/json:
1105
- schema:
1106
- type: object
1107
- required: [content]
1108
- properties:
1109
- content: { type: string }
1110
- responses:
1111
- '200': { description: Saved. }
1112
- '400': { description: Content failed validation (e.g. malformed JSON). }
1113
-
1114
- /api/network/endpoints:
1115
- get:
1116
- tags: [Network]
1117
- summary: LAN endpoints for mobile QR pairing
1118
- description: Returns every reachable IPv4 the host has bound, formatted as `http://<ip>:<port>`.
1119
- responses:
1120
- '200':
1121
- description: LAN endpoint list.
1122
- content:
1123
- application/json:
1124
- schema:
1125
- type: object
1126
- properties:
1127
- endpoints: { type: array, items: { type: string } }
1128
- port: { type: integer }
1129
-
1130
- /api/network/external:
1131
- get:
1132
- tags: [Network]
1133
- summary: Current external-access state (UPnP + tunnel)
1134
- responses:
1135
- '200':
1136
- description: Snapshot.
1137
- content:
1138
- application/json:
1139
- schema:
1140
- type: object
1141
- properties:
1142
- upnp:
1143
- type: object
1144
- properties:
1145
- active: { type: boolean }
1146
- externalIp: { type: string, nullable: true }
1147
- mappedPort: { type: integer, nullable: true }
1148
- tunnel:
1149
- type: object
1150
- properties:
1151
- active: { type: boolean }
1152
- provider: { type: string, enum: [cloudflared, ngrok], nullable: true }
1153
- url: { type: string, nullable: true }
1154
-
1155
- /api/network/upnp:
1156
- post:
1157
- tags: [Network]
1158
- summary: Open the LAN port on the router
1159
- responses:
1160
- '200': { description: Mapping created (or already present). }
1161
- delete:
1162
- tags: [Network]
1163
- summary: Remove the UPnP mapping
1164
- responses:
1165
- '200': { description: Removed. }
1166
-
1167
- /api/network/tunnel:
1168
- post:
1169
- tags: [Network]
1170
- summary: Start a public tunnel (cloudflared / ngrok auto-detect)
1171
- responses:
1172
- '200':
1173
- description: Tunnel started; URL returned.
1174
- content:
1175
- application/json:
1176
- schema:
1177
- type: object
1178
- properties:
1179
- url: { type: string, format: uri }
1180
- provider: { type: string }
1181
- delete:
1182
- tags: [Network]
1183
- summary: Stop the tunnel
1184
- responses:
1185
- '200': { description: Stopped. }
1186
-
1187
- /api/settings/notification-preferences:
1188
- get:
1189
- tags: [Settings]
1190
- summary: Get notification preferences
1191
- responses:
1192
- '200':
1193
- description: Per-channel + per-event toggles.
1194
- content:
1195
- application/json:
1196
- schema:
1197
- type: object
1198
- properties:
1199
- preferences:
1200
- type: object
1201
- properties:
1202
- channels:
1203
- type: object
1204
- properties:
1205
- inApp: { type: boolean }
1206
- webPush: { type: boolean }
1207
- events:
1208
- type: object
1209
- properties:
1210
- actionRequired: { type: boolean }
1211
- stop: { type: boolean }
1212
- error: { type: boolean }
1213
- put:
1214
- tags: [Settings]
1215
- summary: Update notification preferences
1216
- requestBody:
1217
- required: true
1218
- content:
1219
- application/json:
1220
- schema: { type: object }
1221
- responses:
1222
- '200': { description: Saved. }
1223
-
1224
- /api/agent:
1225
- post:
1226
- tags: [Providers]
1227
- summary: External REST entry point (API-key authenticated)
1228
- description: |
1229
- One-shot non-interactive run for automation/CI. Spawns the chosen
1230
- provider, optionally cloning a GitHub repo first, optionally cutting
1231
- a branch + opening a PR. **API key required** — accepts the same `ck_`
1232
- keys as the rest of the API on `Authorization: Bearer`, `X-API-Key`,
1233
- or `?apiKey=`.
1234
-
1235
- Default response is an SSE stream of provider-native events; pass
1236
- `stream: false` to buffer and return JSON.
1237
- security:
1238
- - bearerAuth: []
1239
- - apiKeyAuth: []
1240
- requestBody:
1241
- required: true
1242
- content:
1243
- application/json:
1244
- schema:
1245
- type: object
1246
- required: [message]
1247
- properties:
1248
- message:
1249
- type: string
1250
- description: Prompt text to send to the agent.
1251
- provider:
1252
- type: string
1253
- enum: [claude, cursor, codex, gemini, qwen, opencode]
1254
- default: claude
1255
- model:
1256
- type: string
1257
- description: Provider-specific model id (e.g. `opencode/gpt-5.2`).
1258
- projectPath:
1259
- type: string
1260
- description: Absolute path on the host. Required if `githubUrl` is omitted.
1261
- githubUrl:
1262
- type: string
1263
- format: uri
1264
- description: Clone this repo before running. Mutually inclusive with `projectPath` (used as the clone target if both are given).
1265
- githubToken:
1266
- type: string
1267
- description: Optional override for the per-user GitHub PAT stored under Settings → Git.
1268
- branchName:
1269
- type: string
1270
- description: 'Cutting `branchName` implies `createBranch: true`.'
1271
- createBranch:
1272
- type: boolean
1273
- default: false
1274
- createPR:
1275
- type: boolean
1276
- default: false
1277
- sessionId:
1278
- type: string
1279
- description: Resume an existing session instead of starting a new one.
1280
- stream:
1281
- type: boolean
1282
- default: true
1283
- description: 'Set false to buffer to a single JSON response.'
1284
- cleanup:
1285
- type: boolean
1286
- default: true
1287
- description: When `githubUrl` was used, delete the temp clone after the run.
1288
- responses:
1289
- '200':
1290
- description: |
1291
- When `stream:true` SSE stream of provider events. When `stream:false` — final JSON payload with `text` + `sessionId` + `usage`.
1292
- content:
1293
- application/json:
1294
- schema:
1295
- type: object
1296
- properties:
1297
- text: { type: string }
1298
- sessionId: { type: string }
1299
- usage:
1300
- type: object
1301
- properties:
1302
- input: { type: integer }
1303
- output: { type: integer }
1304
- total: { type: integer }
1305
- cost: { type: number }
1306
- text/event-stream:
1307
- schema: { type: string }
1308
- '400':
1309
- description: 'Missing required fields, unknown provider, or invalid GitHub URL.'
1310
- '401':
1311
- description: Missing or invalid API key.
1
+ openapi: 3.1.0
2
+ info:
3
+ title: Pixcode REST API
4
+ version: 1.34.0
5
+ description: |
6
+ REST API for Pixcode — the multi-CLI web UI for Claude Code, Cursor CLI,
7
+ Codex, Gemini CLI, Qwen Code, and OpenCode.
8
+
9
+ ## Authentication
10
+
11
+ Most endpoints require authentication. Two schemes are accepted:
12
+
13
+ - **JWT cookie** (`token` HTTP-only cookie) — set automatically when the
14
+ browser logs in via `POST /api/auth/login`.
15
+ - **API key** (`Authorization: Bearer ck_...`) — generated under
16
+ Settings → API. API keys never expire and survive server restarts.
17
+
18
+ Endpoints flagged `apiKey` accept both.
19
+
20
+ ## Streaming endpoints
21
+
22
+ Three classes of endpoint stream beyond plain JSON:
23
+
24
+ - **WebSocket** (`/ws`, `/shell`) — chat session bidirectional traffic. Not
25
+ documented here; see `docs/websocket-protocol.md` if it exists, or read
26
+ `server/index.js` `handleChatConnection`.
27
+ - **SSE** (Server-Sent Events) — long-running jobs. Each `data:` frame
28
+ contains a JSON event; the stream ends with `event: done` or `event: error`.
29
+ - **NDJSON** — provider chat output (one JSON event per line) when the
30
+ backend forwards from a CLI's `--format json` mode.
31
+
32
+ ## Errors
33
+
34
+ Errors share a consistent envelope:
35
+
36
+ ```json
37
+ { "success": false, "error": { "code": "ROUTE_NOT_FOUND", "message": "..." } }
38
+ ```
39
+
40
+ contact:
41
+ name: Pixcode on GitHub
42
+ url: https://github.com/alicomert/pixcode
43
+ license:
44
+ name: AGPL-3.0-or-later
45
+ url: https://www.gnu.org/licenses/agpl-3.0.txt
46
+
47
+ servers:
48
+ - url: http://localhost:3001
49
+ description: Local development server
50
+ - url: '{protocol}://{host}'
51
+ description: Self-hosted Pixcode instance
52
+ variables:
53
+ protocol:
54
+ enum: [http, https]
55
+ default: http
56
+ host:
57
+ default: localhost:3001
58
+
59
+ tags:
60
+ - name: System
61
+ description: Health, version, and self-update.
62
+ - name: Authentication
63
+ description: Login, register, JWT lifecycle, API keys.
64
+ - name: Projects
65
+ description: Project CRUD and session enumeration.
66
+ - name: Files
67
+ description: Project filesystem read/write and directory traversal.
68
+ - name: Sessions
69
+ description: Conversation sessions across providers.
70
+ - name: Git
71
+ description: Git status, diffs, branches, commits, push/pull.
72
+ - name: Providers
73
+ description: Multi-CLI provider auth, install, sessions, configuration.
74
+ - name: Orchestration
75
+ description: A2A-backed multi-agent workflow planning, preview, execution, streaming, and cancellation.
76
+ - name: Network
77
+ description: LAN discovery, UPnP, public tunnel.
78
+ - name: Settings
79
+ description: User-scoped preferences and notification channels.
80
+ - name: Search
81
+ description: Full-text search across conversations.
82
+ - name: MCP
83
+ description: Model Context Protocol servers and tooling.
84
+
85
+ components:
86
+ securitySchemes:
87
+ bearerAuth:
88
+ type: http
89
+ scheme: bearer
90
+ bearerFormat: JWT
91
+ description: |
92
+ `Authorization: Bearer <token>` token may be a JWT (issued by
93
+ `/api/auth/login`) or an API key (prefix `ck_`, generated under
94
+ Settings → API). The middleware sniffs the prefix to decide.
95
+ apiKeyAuth:
96
+ type: apiKey
97
+ in: header
98
+ name: X-API-Key
99
+ description: |
100
+ Alternative for tools that can't set `Authorization`. Accepts the same
101
+ `ck_...` keys as `bearerAuth`. Either header works on every secured
102
+ endpoint — pick whichever your client supports.
103
+ cookieAuth:
104
+ type: apiKey
105
+ in: cookie
106
+ name: token
107
+ description: HTTP-only `token` cookie set by `/api/auth/login`.
108
+
109
+ schemas:
110
+ Error:
111
+ type: object
112
+ required: [success, error]
113
+ properties:
114
+ success: { type: boolean, enum: [false] }
115
+ error:
116
+ type: object
117
+ required: [code, message]
118
+ properties:
119
+ code: { type: string, example: ROUTE_NOT_FOUND }
120
+ message: { type: string }
121
+
122
+ Health:
123
+ type: object
124
+ required: [status, timestamp]
125
+ properties:
126
+ status: { type: string, enum: [ok] }
127
+ timestamp: { type: string, format: date-time }
128
+ version:
129
+ type: string
130
+ description: Server version (matches semver `MAJOR.MINOR.PATCH`).
131
+ example: 1.33.9
132
+ installMode:
133
+ type: string
134
+ enum: [git, npm-global, runtime-dir, docker]
135
+
136
+ User:
137
+ type: object
138
+ properties:
139
+ id: { type: integer }
140
+ username: { type: string }
141
+ email: { type: string, format: email, nullable: true }
142
+ created_at: { type: string, format: date-time }
143
+
144
+ AuthStatus:
145
+ type: object
146
+ properties:
147
+ success: { type: boolean }
148
+ isAuthenticated: { type: boolean }
149
+ needsSetup: { type: boolean, description: 'true if no users exist yet — UI shows registration screen.' }
150
+ user: { $ref: '#/components/schemas/User' }
151
+
152
+ LoginRequest:
153
+ type: object
154
+ required: [username, password]
155
+ properties:
156
+ username: { type: string }
157
+ password: { type: string, format: password }
158
+
159
+ LoginResponse:
160
+ type: object
161
+ properties:
162
+ success: { type: boolean }
163
+ token: { type: string, description: JWT (also set as `token` cookie). }
164
+ user: { $ref: '#/components/schemas/User' }
165
+
166
+ ApiKey:
167
+ type: object
168
+ properties:
169
+ id: { type: integer }
170
+ key_name: { type: string }
171
+ api_key: { type: string, description: 'Format: `ck_<32-hex>`. Returned in full on creation only.' }
172
+ created_at: { type: string, format: date-time }
173
+ last_used: { type: string, format: date-time, nullable: true }
174
+ is_active: { type: boolean }
175
+
176
+ Project:
177
+ type: object
178
+ properties:
179
+ name: { type: string }
180
+ displayName: { type: string }
181
+ path: { type: string }
182
+ fullPath: { type: string }
183
+ sessions:
184
+ type: array
185
+ items: { $ref: '#/components/schemas/SessionMeta' }
186
+
187
+ SessionMeta:
188
+ type: object
189
+ properties:
190
+ id: { type: string }
191
+ title: { type: string, nullable: true }
192
+ provider:
193
+ type: string
194
+ enum: [claude, cursor, codex, gemini, qwen, opencode]
195
+ lastActivity: { type: string, format: date-time }
196
+
197
+ GitStatus:
198
+ type: object
199
+ properties:
200
+ branch: { type: string }
201
+ ahead: { type: integer }
202
+ behind: { type: integer }
203
+ modified: { type: array, items: { type: string } }
204
+ added: { type: array, items: { type: string } }
205
+ deleted: { type: array, items: { type: string } }
206
+ untracked: { type: array, items: { type: string } }
207
+
208
+ ProviderInfo:
209
+ type: object
210
+ properties:
211
+ id:
212
+ type: string
213
+ enum: [claude, cursor, codex, gemini, qwen, opencode]
214
+ installed: { type: boolean }
215
+ authenticated: { type: boolean }
216
+ version: { type: string, nullable: true }
217
+ binaryPath: { type: string, nullable: true }
218
+
219
+ InstallJob:
220
+ type: object
221
+ properties:
222
+ jobId: { type: string }
223
+ provider: { type: string }
224
+ status: { type: string, enum: [pending, running, succeeded, failed, cancelled] }
225
+
226
+ OrchestrationAgent:
227
+ type: object
228
+ required: [adapterId]
229
+ properties:
230
+ instanceId:
231
+ type: string
232
+ description: Stable client-side instance id. If omitted, Pixcode derives one from adapter id + order.
233
+ example: codex-backend-1
234
+ adapterId:
235
+ type: string
236
+ enum: [claude-code, codex, cursor, gemini, qwen, opencode]
237
+ description: CLI adapter to execute this agent.
238
+ label:
239
+ type: string
240
+ description: Human-readable label shown in workflow history.
241
+ example: Backend Agent
242
+ role:
243
+ type: string
244
+ description: |
245
+ Optional language-independent orchestration hint. Known values are
246
+ routed directly (`backend`, `frontend`, `review`, `proposal`,
247
+ `critique`, etc.); custom stage names are accepted.
248
+ instruction:
249
+ type: string
250
+ description: |
251
+ Optional per-agent assignment supplied by the API caller. Pixcode
252
+ does not require a fixed language or fixed text here.
253
+ model:
254
+ type: string
255
+ description: Optional provider-specific model id. Omit this field to let the underlying CLI use its own configured/default model.
256
+ permissionMode:
257
+ type: string
258
+ description: Provider-specific permission/sandbox mode.
259
+ enabled:
260
+ type: boolean
261
+ default: true
262
+ toolsSettings:
263
+ type: object
264
+ additionalProperties: true
265
+
266
+ WorkflowNodeRun:
267
+ type: object
268
+ properties:
269
+ nodeId: { type: string }
270
+ adapterId: { type: string }
271
+ agentInstanceId: { type: string }
272
+ agentLabel: { type: string }
273
+ assignment: { type: string }
274
+ model: { type: string }
275
+ permissionMode: { type: string }
276
+ timeoutMs: { type: integer }
277
+ status:
278
+ type: string
279
+ enum: [queued, running, completed, failed, canceled, skipped]
280
+ a2aTaskId: { type: string }
281
+ startedAt: { type: integer, format: int64 }
282
+ finishedAt: { type: integer, format: int64 }
283
+ error: { type: string }
284
+ outputText: { type: string }
285
+ messages:
286
+ type: array
287
+ items:
288
+ type: object
289
+ properties:
290
+ role: { type: string, enum: [user, agent] }
291
+ text: { type: string }
292
+ createdAt: { type: integer, format: int64 }
293
+ artifacts:
294
+ type: array
295
+ items:
296
+ type: object
297
+ properties:
298
+ type: { type: string, enum: [file-diff, command-output, preview-url, data] }
299
+ text: { type: string }
300
+ data: { type: object, additionalProperties: true }
301
+ metadata: { type: object, additionalProperties: true }
302
+
303
+ WorkspaceTarget:
304
+ type: object
305
+ properties:
306
+ kind:
307
+ type: string
308
+ enum: [selected_project, pixcode_app, custom]
309
+ description: Which workspace should become the child agent cwd.
310
+ label:
311
+ type: string
312
+ description: Human-readable target label shown in run metadata.
313
+ projectPath:
314
+ type: string
315
+ description: Required for `custom`; optional for `pixcode_app`, where the server resolves the app root.
316
+
317
+ WorkflowRun:
318
+ type: object
319
+ properties:
320
+ id: { type: string, example: wrun_1234abcd }
321
+ workflowId: { type: string, example: agent_team }
322
+ contextId:
323
+ type: string
324
+ description: Shared A2A context id used by every child task in this run.
325
+ example: ctx_1234abcd
326
+ status:
327
+ type: string
328
+ enum: [queued, running, completed, failed, canceled]
329
+ input: { type: string }
330
+ startedAt: { type: integer, format: int64 }
331
+ finishedAt: { type: integer, format: int64 }
332
+ metadata: { type: object, additionalProperties: true }
333
+ nodeRuns:
334
+ type: array
335
+ items: { $ref: '#/components/schemas/WorkflowNodeRun' }
336
+
337
+ WorkflowRunCreateRequest:
338
+ type: object
339
+ properties:
340
+ input:
341
+ type: string
342
+ description: User goal sent to the workflow.
343
+ metadata:
344
+ type: object
345
+ properties:
346
+ projectId: { type: string }
347
+ selectedProjectPath:
348
+ type: string
349
+ description: Absolute path of the UI-selected project used for history grouping and fallback.
350
+ projectPath:
351
+ type: string
352
+ description: Resolved absolute host path where CLI agents should run.
353
+ workspaceTarget:
354
+ $ref: '#/components/schemas/WorkspaceTarget'
355
+ agents:
356
+ type: array
357
+ items: { $ref: '#/components/schemas/OrchestrationAgent' }
358
+ settings:
359
+ type: object
360
+ properties:
361
+ maxParallelAgents:
362
+ type: integer
363
+ minimum: 1
364
+ maximum: 12
365
+ default: 3
366
+ isolation:
367
+ type: string
368
+ enum: [host, worktree, docker]
369
+ keepWorkspace:
370
+ type: boolean
371
+ default: true
372
+
373
+ WorkflowPreviewResponse:
374
+ type: object
375
+ properties:
376
+ workflow:
377
+ type: object
378
+ additionalProperties: true
379
+ nodeCount: { type: integer }
380
+ nodes:
381
+ type: array
382
+ items:
383
+ type: object
384
+ properties:
385
+ id: { type: string }
386
+ adapterId: { type: string }
387
+ agentInstanceId: { type: string }
388
+ agentLabel: { type: string }
389
+ inputs:
390
+ type: array
391
+ items: { type: string }
392
+ onFail: { type: string, enum: [abort, continue, retry] }
393
+ output: { type: string, enum: [message, artifact, both] }
394
+ timeoutMs: { type: integer }
395
+
396
+ security:
397
+ - bearerAuth: []
398
+ - apiKeyAuth: []
399
+ - cookieAuth: []
400
+
401
+ paths:
402
+ /health:
403
+ get:
404
+ tags: [System]
405
+ summary: Liveness + version probe
406
+ description: |
407
+ Public, unauthenticated. Returns server version and install mode so the
408
+ UI can detect updates and stale daemons. Used by:
409
+
410
+ - The version-upgrade modal — polls during/after `/api/system/update`
411
+ to detect when the new version is up.
412
+ - `useVersionCheck` — falls back to the bundle's baked
413
+ `__PIXCODE_UI_VERSION__` if `version` is missing or non-semver.
414
+ security: []
415
+ responses:
416
+ '200':
417
+ description: Server is up.
418
+ content:
419
+ application/json:
420
+ schema: { $ref: '#/components/schemas/Health' }
421
+
422
+ /api/system/update:
423
+ post:
424
+ tags: [System]
425
+ summary: Self-update (SSE)
426
+ description: |
427
+ Streams the update process via SSE. Behavior depends on
428
+ `installMode`:
429
+
430
+ - **runtime-dir** (desktop wrapper): downloads the latest npm tarball,
431
+ atomically swaps files, emits `done { selfRestarting: true }`, then
432
+ `process.exit(42)` so the wrapper respawns. **Don't `POST /restart`
433
+ when `selfRestarting` is true.**
434
+ - **git/npm-global**: runs `git pull && npm install` or
435
+ `npm install -g`. The supervising daemon may restart the server
436
+ mid-stream — clients should treat a bare close + `/health` version
437
+ bump as success.
438
+ responses:
439
+ '200':
440
+ description: 'SSE stream of `event: log`, `event: progress`, `event: done`, `event: error`.'
441
+ content:
442
+ text/event-stream:
443
+ schema: { type: string }
444
+
445
+ /api/system/restart:
446
+ post:
447
+ tags: [System]
448
+ summary: Restart the server process
449
+ description: |
450
+ Triggers a graceful exit; the supervising daemon (systemd/pm2/electron
451
+ wrapper) is expected to respawn. Don't call after a `selfRestarting`
452
+ update event — the wrapper has already been signalled.
453
+ responses:
454
+ '200':
455
+ description: Restart scheduled.
456
+
457
+ /api/auth/status:
458
+ get:
459
+ tags: [Authentication]
460
+ summary: Probe authentication state
461
+ description: Returns whether the current request carries a valid token, and whether the system has any users at all (`needsSetup`).
462
+ security: []
463
+ responses:
464
+ '200':
465
+ description: Auth status.
466
+ content:
467
+ application/json:
468
+ schema: { $ref: '#/components/schemas/AuthStatus' }
469
+
470
+ /api/auth/register:
471
+ post:
472
+ tags: [Authentication]
473
+ summary: Register the first user
474
+ description: Only allowed while `needsSetup` is true. Subsequent calls return 403.
475
+ security: []
476
+ requestBody:
477
+ required: true
478
+ content:
479
+ application/json:
480
+ schema: { $ref: '#/components/schemas/LoginRequest' }
481
+ responses:
482
+ '200':
483
+ description: Registered + auto-logged-in.
484
+ content:
485
+ application/json:
486
+ schema: { $ref: '#/components/schemas/LoginResponse' }
487
+ '403':
488
+ description: Setup already complete.
489
+ content:
490
+ application/json:
491
+ schema: { $ref: '#/components/schemas/Error' }
492
+
493
+ /api/auth/login:
494
+ post:
495
+ tags: [Authentication]
496
+ summary: Log in
497
+ security: []
498
+ requestBody:
499
+ required: true
500
+ content:
501
+ application/json:
502
+ schema: { $ref: '#/components/schemas/LoginRequest' }
503
+ responses:
504
+ '200':
505
+ description: Login OK; sets `token` cookie + returns JWT in body.
506
+ content:
507
+ application/json:
508
+ schema: { $ref: '#/components/schemas/LoginResponse' }
509
+ '401':
510
+ description: Invalid credentials.
511
+
512
+ /api/auth/user:
513
+ get:
514
+ tags: [Authentication]
515
+ summary: Current user
516
+ responses:
517
+ '200':
518
+ description: Authenticated user details.
519
+ content:
520
+ application/json:
521
+ schema:
522
+ type: object
523
+ properties:
524
+ user: { $ref: '#/components/schemas/User' }
525
+
526
+ /api/auth/logout:
527
+ post:
528
+ tags: [Authentication]
529
+ summary: Log out
530
+ description: Clears the `token` cookie. JWT remains valid until expiry — server-side blacklist isn't implemented.
531
+ responses:
532
+ '200': { description: OK }
533
+
534
+ /api/settings/api-keys:
535
+ get:
536
+ tags: [Authentication]
537
+ summary: List user API keys
538
+ responses:
539
+ '200':
540
+ description: List of keys (the `api_key` field is masked except on creation).
541
+ content:
542
+ application/json:
543
+ schema:
544
+ type: array
545
+ items: { $ref: '#/components/schemas/ApiKey' }
546
+ post:
547
+ tags: [Authentication]
548
+ summary: Create an API key
549
+ requestBody:
550
+ required: true
551
+ content:
552
+ application/json:
553
+ schema:
554
+ type: object
555
+ required: [name]
556
+ properties:
557
+ name: { type: string, description: 'Human-readable label.' }
558
+ responses:
559
+ '201':
560
+ description: Key created. The full `api_key` value is returned **once** — store it.
561
+ content:
562
+ application/json:
563
+ schema: { $ref: '#/components/schemas/ApiKey' }
564
+
565
+ /api/settings/api-keys/{keyId}:
566
+ delete:
567
+ tags: [Authentication]
568
+ summary: Delete an API key
569
+ parameters:
570
+ - name: keyId
571
+ in: path
572
+ required: true
573
+ schema: { type: integer }
574
+ responses:
575
+ '200': { description: Deleted. }
576
+
577
+ /api/settings/api-keys/{keyId}/toggle:
578
+ patch:
579
+ tags: [Authentication]
580
+ summary: Activate / deactivate an API key
581
+ parameters:
582
+ - name: keyId
583
+ in: path
584
+ required: true
585
+ schema: { type: integer }
586
+ requestBody:
587
+ required: true
588
+ content:
589
+ application/json:
590
+ schema:
591
+ type: object
592
+ properties:
593
+ is_active: { type: boolean }
594
+ responses:
595
+ '200': { description: Updated. }
596
+
597
+ /api/projects:
598
+ get:
599
+ tags: [Projects]
600
+ summary: List all projects
601
+ description: Walks `~/.claude/projects/*` plus any registered workspaces and returns a unified list. Sessions are flattened by provider.
602
+ responses:
603
+ '200':
604
+ description: Project list.
605
+ content:
606
+ application/json:
607
+ schema:
608
+ type: array
609
+ items: { $ref: '#/components/schemas/Project' }
610
+
611
+ /api/projects/quick-start:
612
+ post:
613
+ tags: [Projects]
614
+ summary: Open or create a project from an absolute path
615
+ requestBody:
616
+ required: true
617
+ content:
618
+ application/json:
619
+ schema:
620
+ type: object
621
+ required: [path]
622
+ properties:
623
+ path: { type: string, description: 'Absolute filesystem path.' }
624
+ responses:
625
+ '200':
626
+ description: Project record (created if it didn't exist).
627
+ content:
628
+ application/json:
629
+ schema: { $ref: '#/components/schemas/Project' }
630
+
631
+ /api/projects/{projectName}/rename:
632
+ put:
633
+ tags: [Projects]
634
+ summary: Rename project display
635
+ parameters:
636
+ - { name: projectName, in: path, required: true, schema: { type: string } }
637
+ requestBody:
638
+ required: true
639
+ content:
640
+ application/json:
641
+ schema:
642
+ type: object
643
+ properties:
644
+ displayName: { type: string }
645
+ responses:
646
+ '200': { description: Renamed. }
647
+
648
+ /api/projects/{projectName}:
649
+ delete:
650
+ tags: [Projects]
651
+ summary: Delete (deregister) a project
652
+ parameters:
653
+ - { name: projectName, in: path, required: true, schema: { type: string } }
654
+ responses:
655
+ '200': { description: Deleted. }
656
+
657
+ /api/projects/{projectName}/sessions:
658
+ get:
659
+ tags: [Sessions]
660
+ summary: List sessions for a project
661
+ parameters:
662
+ - { name: projectName, in: path, required: true, schema: { type: string } }
663
+ responses:
664
+ '200':
665
+ description: Sessions sorted by lastActivity desc.
666
+ content:
667
+ application/json:
668
+ schema:
669
+ type: array
670
+ items: { $ref: '#/components/schemas/SessionMeta' }
671
+
672
+ /api/projects/{projectName}/sessions/{sessionId}:
673
+ delete:
674
+ tags: [Sessions]
675
+ summary: Delete a session
676
+ parameters:
677
+ - { name: projectName, in: path, required: true, schema: { type: string } }
678
+ - { name: sessionId, in: path, required: true, schema: { type: string } }
679
+ responses:
680
+ '200': { description: Deleted. }
681
+
682
+ /api/sessions/{sessionId}/rename:
683
+ put:
684
+ tags: [Sessions]
685
+ summary: Rename a session
686
+ parameters:
687
+ - { name: sessionId, in: path, required: true, schema: { type: string } }
688
+ requestBody:
689
+ required: true
690
+ content:
691
+ application/json:
692
+ schema:
693
+ type: object
694
+ properties:
695
+ title: { type: string }
696
+ responses:
697
+ '200': { description: Renamed. }
698
+
699
+ /api/sessions/{sessionId}/messages:
700
+ get:
701
+ tags: [Sessions]
702
+ summary: Get session message history
703
+ description: |
704
+ Note: this is mounted at `/api/sessions`, NOT under `/api/projects` — the
705
+ `projectName` is supplied as a query parameter rather than a path
706
+ segment. The mount lives in `server/routes/messages.js`.
707
+ parameters:
708
+ - { name: sessionId, in: path, required: true, schema: { type: string } }
709
+ - { name: projectName, in: query, required: true, schema: { type: string }, description: Pixcode project the session belongs to. }
710
+ - { name: limit, in: query, required: false, schema: { type: integer, default: 100 } }
711
+ - { name: offset, in: query, required: false, schema: { type: integer, default: 0 } }
712
+ responses:
713
+ '200':
714
+ description: Normalized message stream.
715
+ content:
716
+ application/json:
717
+ schema:
718
+ type: object
719
+ properties:
720
+ messages: { type: array, items: { type: object, additionalProperties: true } }
721
+ total: { type: integer }
722
+ hasMore: { type: boolean }
723
+
724
+ /api/search/conversations:
725
+ get:
726
+ tags: [Search]
727
+ summary: Full-text search across all sessions
728
+ parameters:
729
+ - { name: q, in: query, required: true, schema: { type: string }, description: Search query. }
730
+ - { name: provider, in: query, required: false, schema: { type: string, enum: [claude, cursor, codex, gemini, qwen, opencode] } }
731
+ - { name: limit, in: query, required: false, schema: { type: integer, default: 50 } }
732
+ responses:
733
+ '200':
734
+ description: Ranked matches.
735
+ content:
736
+ application/json:
737
+ schema:
738
+ type: object
739
+ properties:
740
+ results: { type: array, items: { type: object, additionalProperties: true } }
741
+ total: { type: integer }
742
+
743
+ /api/projects/{projectName}/files:
744
+ get:
745
+ tags: [Files]
746
+ summary: List files in a project subtree
747
+ parameters:
748
+ - { name: projectName, in: path, required: true, schema: { type: string } }
749
+ - { name: path, in: query, required: false, schema: { type: string }, description: Subdirectory relative to project root. }
750
+ responses:
751
+ '200':
752
+ description: Directory listing.
753
+ content:
754
+ application/json:
755
+ schema:
756
+ type: array
757
+ items:
758
+ type: object
759
+ properties:
760
+ name: { type: string }
761
+ path: { type: string }
762
+ type: { type: string, enum: [file, directory] }
763
+ size: { type: integer, nullable: true }
764
+ delete:
765
+ tags: [Files]
766
+ summary: Delete a file or folder (path in body)
767
+ description: |
768
+ Same path as the listing endpoint above — discriminated by HTTP method.
769
+ The target's project-relative path goes in the body, NOT the query
770
+ string (so directory deletes can't be partially URL-encoded into a
771
+ broken state).
772
+ parameters:
773
+ - { name: projectName, in: path, required: true, schema: { type: string } }
774
+ requestBody:
775
+ required: true
776
+ content:
777
+ application/json:
778
+ schema:
779
+ type: object
780
+ required: [path]
781
+ properties:
782
+ path: { type: string, description: 'Project-relative path of the file or directory to delete.' }
783
+ type: { type: string, enum: [file, directory], description: 'Optional hint; server detects automatically if omitted.' }
784
+ responses:
785
+ '200': { description: Deleted. }
786
+
787
+ /api/projects/{projectName}/file:
788
+ get:
789
+ tags: [Files]
790
+ summary: Read a single file
791
+ parameters:
792
+ - { name: projectName, in: path, required: true, schema: { type: string } }
793
+ - { name: path, in: query, required: true, schema: { type: string } }
794
+ responses:
795
+ '200':
796
+ description: File contents (utf-8 text or base64 binary).
797
+ content:
798
+ application/json:
799
+ schema:
800
+ type: object
801
+ properties:
802
+ content: { type: string }
803
+ encoding: { type: string, enum: [utf-8, base64] }
804
+ put:
805
+ tags: [Files]
806
+ summary: Overwrite a file
807
+ parameters:
808
+ - { name: projectName, in: path, required: true, schema: { type: string } }
809
+ requestBody:
810
+ required: true
811
+ content:
812
+ application/json:
813
+ schema:
814
+ type: object
815
+ required: [path, content]
816
+ properties:
817
+ path: { type: string }
818
+ content: { type: string }
819
+ responses:
820
+ '200': { description: Saved. }
821
+
822
+ /api/projects/{projectName}/files/create:
823
+ post:
824
+ tags: [Files]
825
+ summary: Create a new file or folder
826
+ parameters:
827
+ - { name: projectName, in: path, required: true, schema: { type: string } }
828
+ requestBody:
829
+ required: true
830
+ content:
831
+ application/json:
832
+ schema:
833
+ type: object
834
+ required: [path, type]
835
+ properties:
836
+ path: { type: string }
837
+ type: { type: string, enum: [file, directory] }
838
+ content: { type: string, description: 'Initial content for files; ignored for directories.' }
839
+ responses:
840
+ '201': { description: Created. }
841
+
842
+ /api/projects/{projectName}/files/rename:
843
+ put:
844
+ tags: [Files]
845
+ summary: Rename / move a file
846
+ parameters:
847
+ - { name: projectName, in: path, required: true, schema: { type: string } }
848
+ requestBody:
849
+ required: true
850
+ content:
851
+ application/json:
852
+ schema:
853
+ type: object
854
+ required: [oldPath, newPath]
855
+ properties:
856
+ oldPath: { type: string }
857
+ newPath: { type: string }
858
+ responses:
859
+ '200': { description: Renamed. }
860
+
861
+
862
+ /api/browse-filesystem:
863
+ get:
864
+ tags: [Files]
865
+ summary: Native filesystem browser (outside project tree)
866
+ description: Used by Quick Start to let the user pick a folder anywhere on the host. Honours `~` expansion.
867
+ parameters:
868
+ - { name: path, in: query, required: false, schema: { type: string, default: '~' } }
869
+ responses:
870
+ '200':
871
+ description: Directory listing.
872
+ content:
873
+ application/json:
874
+ schema:
875
+ type: object
876
+ properties:
877
+ path: { type: string }
878
+ parent: { type: string, nullable: true }
879
+ entries:
880
+ type: array
881
+ items:
882
+ type: object
883
+ properties:
884
+ name: { type: string }
885
+ type: { type: string, enum: [file, directory] }
886
+
887
+ /api/git/status:
888
+ get:
889
+ tags: [Git]
890
+ summary: Working tree status
891
+ parameters:
892
+ - { name: project, in: query, required: true, schema: { type: string } }
893
+ responses:
894
+ '200':
895
+ description: Git status snapshot.
896
+ content:
897
+ application/json:
898
+ schema: { $ref: '#/components/schemas/GitStatus' }
899
+
900
+ /api/git/diff:
901
+ get:
902
+ tags: [Git]
903
+ summary: Unified diff for one file or the whole tree
904
+ parameters:
905
+ - { name: project, in: query, required: true, schema: { type: string } }
906
+ - { name: file, in: query, required: false, schema: { type: string } }
907
+ - { name: staged, in: query, required: false, schema: { type: boolean, default: false } }
908
+ responses:
909
+ '200':
910
+ description: Diff text.
911
+ content:
912
+ application/json:
913
+ schema:
914
+ type: object
915
+ properties:
916
+ diff: { type: string }
917
+
918
+ /api/git/branches:
919
+ get:
920
+ tags: [Git]
921
+ summary: List local + remote branches
922
+ parameters:
923
+ - { name: project, in: query, required: true, schema: { type: string } }
924
+ responses:
925
+ '200':
926
+ description: Branch list.
927
+ content:
928
+ application/json:
929
+ schema:
930
+ type: object
931
+ properties:
932
+ current: { type: string }
933
+ local: { type: array, items: { type: string } }
934
+ remote: { type: array, items: { type: string } }
935
+
936
+ /api/git/commit:
937
+ post:
938
+ tags: [Git]
939
+ summary: Create a commit
940
+ requestBody:
941
+ required: true
942
+ content:
943
+ application/json:
944
+ schema:
945
+ type: object
946
+ required: [project, message]
947
+ properties:
948
+ project: { type: string }
949
+ message: { type: string }
950
+ files: { type: array, items: { type: string }, description: 'When omitted, all staged changes are committed.' }
951
+ responses:
952
+ '200': { description: Commit created. }
953
+
954
+ /api/git/push:
955
+ post:
956
+ tags: [Git]
957
+ summary: Push to remote
958
+ requestBody:
959
+ required: true
960
+ content:
961
+ application/json:
962
+ schema:
963
+ type: object
964
+ required: [project]
965
+ properties:
966
+ project: { type: string }
967
+ remote: { type: string, default: origin }
968
+ branch: { type: string }
969
+ force: { type: boolean, default: false }
970
+ responses:
971
+ '200': { description: Pushed. }
972
+
973
+ /api/git/pull:
974
+ post:
975
+ tags: [Git]
976
+ summary: Pull from remote
977
+ requestBody:
978
+ required: true
979
+ content:
980
+ application/json:
981
+ schema:
982
+ type: object
983
+ required: [project]
984
+ properties:
985
+ project: { type: string }
986
+ responses:
987
+ '200': { description: Pulled. }
988
+
989
+ /api/git/checkout:
990
+ post:
991
+ tags: [Git]
992
+ summary: Switch branch
993
+ requestBody:
994
+ required: true
995
+ content:
996
+ application/json:
997
+ schema:
998
+ type: object
999
+ required: [project, branch]
1000
+ properties:
1001
+ project: { type: string }
1002
+ branch: { type: string }
1003
+ responses:
1004
+ '200': { description: Switched. }
1005
+
1006
+ /api/providers/credentials:
1007
+ get:
1008
+ tags: [Providers]
1009
+ summary: List stored credentials across providers
1010
+ description: Returns a sanitised inventory of API keys / OAuth tokens Pixcode is currently holding for each provider. Real secret values are NOT returned — only presence + masked tail.
1011
+ responses:
1012
+ '200':
1013
+ description: Credentials inventory.
1014
+ content:
1015
+ application/json:
1016
+ schema:
1017
+ type: object
1018
+ additionalProperties:
1019
+ type: object
1020
+ properties:
1021
+ hasCredential: { type: boolean }
1022
+ masked: { type: string, nullable: true, example: '...beef' }
1023
+
1024
+ /api/providers/{provider}/auth/status:
1025
+ get:
1026
+ tags: [Providers]
1027
+ summary: Auth status for a single provider
1028
+ description: |
1029
+ Returns whether the provider's CLI is installed, whether it has a
1030
+ valid auth credential (api key / OAuth token), and the resolved
1031
+ binary path the spawn layer will use.
1032
+ parameters:
1033
+ - { name: provider, in: path, required: true, schema: { type: string, enum: [claude, cursor, codex, gemini, qwen, opencode] } }
1034
+ responses:
1035
+ '200':
1036
+ description: Auth status snapshot.
1037
+ content:
1038
+ application/json:
1039
+ schema: { $ref: '#/components/schemas/ProviderInfo' }
1040
+
1041
+ /api/providers/{provider}/auth/api-key:
1042
+ post:
1043
+ tags: [Providers]
1044
+ summary: Save / replace an API-key credential for a provider
1045
+ parameters:
1046
+ - { name: provider, in: path, required: true, schema: { type: string } }
1047
+ requestBody:
1048
+ required: true
1049
+ content:
1050
+ application/json:
1051
+ schema:
1052
+ type: object
1053
+ required: [apiKey]
1054
+ properties:
1055
+ apiKey: { type: string }
1056
+ baseUrl: { type: string, description: Optional override (e.g. self-hosted Anthropic compat endpoint). }
1057
+ responses:
1058
+ '200': { description: Credential saved. }
1059
+
1060
+ /api/providers/{provider}/oauth-paste:
1061
+ post:
1062
+ tags: [Providers]
1063
+ summary: Paste an OAuth callback URL to complete login
1064
+ description: |
1065
+ For providers (Claude, Cursor) whose login flow opens a browser tab and
1066
+ bounces back to a URL the user copies into Pixcode. The handler parses
1067
+ the token and stores it as the active credential.
1068
+ parameters:
1069
+ - { name: provider, in: path, required: true, schema: { type: string } }
1070
+ requestBody:
1071
+ required: true
1072
+ content:
1073
+ application/json:
1074
+ schema:
1075
+ type: object
1076
+ required: [url]
1077
+ properties:
1078
+ url: { type: string, format: uri }
1079
+ responses:
1080
+ '200': { description: Token extracted and stored. }
1081
+ '400': { description: URL did not contain a recognisable token. }
1082
+
1083
+ /api/providers/{provider}/models:
1084
+ get:
1085
+ tags: [Providers]
1086
+ summary: List models the provider's CLI exposes
1087
+ description: |
1088
+ Pixcode caches the model list per provider on first call (or when the
1089
+ cache is busted via `DELETE …/models/cache`). Each entry is the
1090
+ `provider/model` form OpenCode expects.
1091
+ parameters:
1092
+ - { name: provider, in: path, required: true, schema: { type: string } }
1093
+ responses:
1094
+ '200':
1095
+ description: Model catalog.
1096
+ content:
1097
+ application/json:
1098
+ schema:
1099
+ type: array
1100
+ items:
1101
+ type: object
1102
+ properties:
1103
+ id: { type: string, example: 'opencode/gpt-5.2' }
1104
+ name: { type: string }
1105
+ contextWindow: { type: integer, nullable: true }
1106
+
1107
+ /api/providers/{provider}/models/cache:
1108
+ delete:
1109
+ tags: [Providers]
1110
+ summary: Bust the cached model list for one provider
1111
+ parameters:
1112
+ - { name: provider, in: path, required: true, schema: { type: string } }
1113
+ responses:
1114
+ '200': { description: Cache cleared; next GET re-fetches. }
1115
+
1116
+ /api/providers/{provider}/install:
1117
+ post:
1118
+ tags: [Providers]
1119
+ summary: Install / update a provider CLI in the Pixcode sandbox
1120
+ description: |
1121
+ Installs the provider's npm package into `~/.pixcode/cli-bin/` (no
1122
+ `-g`, no sudo/UAC). Returns a `jobId` immediately; subscribe to
1123
+ `/install/{jobId}/stream` for live logs.
1124
+ parameters:
1125
+ - { name: provider, in: path, required: true, schema: { type: string } }
1126
+ responses:
1127
+ '202':
1128
+ description: Job accepted.
1129
+ content:
1130
+ application/json:
1131
+ schema: { $ref: '#/components/schemas/InstallJob' }
1132
+
1133
+ /api/providers/{provider}/install/{jobId}/stream:
1134
+ get:
1135
+ tags: [Providers]
1136
+ summary: Stream install job output (SSE)
1137
+ description: Replays buffered output, then streams live until the job ends. Send `Last-Event-ID` to resume after disconnect.
1138
+ parameters:
1139
+ - { name: provider, in: path, required: true, schema: { type: string } }
1140
+ - { name: jobId, in: path, required: true, schema: { type: string } }
1141
+ responses:
1142
+ '200':
1143
+ description: 'SSE event stream — `event: log`, `event: status`, `event: done`, `event: error`.'
1144
+ content:
1145
+ text/event-stream:
1146
+ schema: { type: string }
1147
+
1148
+ /api/providers/{provider}/install/{jobId}:
1149
+ delete:
1150
+ tags: [Providers]
1151
+ summary: Cancel an in-flight install
1152
+ parameters:
1153
+ - { name: provider, in: path, required: true, schema: { type: string } }
1154
+ - { name: jobId, in: path, required: true, schema: { type: string } }
1155
+ responses:
1156
+ '200': { description: Cancelled. }
1157
+
1158
+ /api/providers/{provider}/mcp/servers:
1159
+ get:
1160
+ tags: [MCP]
1161
+ summary: List MCP servers configured for one provider
1162
+ parameters:
1163
+ - { name: provider, in: path, required: true, schema: { type: string } }
1164
+ responses:
1165
+ '200':
1166
+ description: MCP server list (matches the provider's native config schema).
1167
+ content:
1168
+ application/json:
1169
+ schema:
1170
+ type: array
1171
+ items: { type: object, additionalProperties: true }
1172
+ post:
1173
+ tags: [MCP]
1174
+ summary: Add or replace an MCP server entry
1175
+ parameters:
1176
+ - { name: provider, in: path, required: true, schema: { type: string } }
1177
+ requestBody:
1178
+ required: true
1179
+ content:
1180
+ application/json:
1181
+ schema:
1182
+ type: object
1183
+ required: [name, command]
1184
+ properties:
1185
+ name: { type: string }
1186
+ command: { type: string }
1187
+ args: { type: array, items: { type: string } }
1188
+ env: { type: object, additionalProperties: { type: string } }
1189
+ scope: { type: string, enum: [local, user], default: user }
1190
+ responses:
1191
+ '200': { description: Server saved. }
1192
+
1193
+ /api/providers/{provider}/mcp/servers/{name}:
1194
+ delete:
1195
+ tags: [MCP]
1196
+ summary: Remove an MCP server entry
1197
+ parameters:
1198
+ - { name: provider, in: path, required: true, schema: { type: string } }
1199
+ - { name: name, in: path, required: true, schema: { type: string } }
1200
+ responses:
1201
+ '200': { description: Removed. }
1202
+
1203
+ /api/providers/mcp/servers/global:
1204
+ post:
1205
+ tags: [MCP]
1206
+ summary: Add an MCP server to every provider that supports MCP
1207
+ description: Convenience endpoint that fans out the same server config to all MCP-capable providers (Claude, Cursor, Codex, OpenCode). Per-provider edits override.
1208
+ requestBody:
1209
+ required: true
1210
+ content:
1211
+ application/json:
1212
+ schema:
1213
+ type: object
1214
+ required: [name, command]
1215
+ properties:
1216
+ name: { type: string }
1217
+ command: { type: string }
1218
+ args: { type: array, items: { type: string } }
1219
+ env: { type: object, additionalProperties: { type: string } }
1220
+ responses:
1221
+ '200': { description: Server fanned out. }
1222
+
1223
+ /api/providers/{provider}/config-files:
1224
+ get:
1225
+ tags: [Providers]
1226
+ summary: List config files Pixcode knows about for a provider
1227
+ description: |
1228
+ Returns the catalog of editable config files for a provider — typically
1229
+ `settings.json`, `auth.json`, `opencode.json`, etc. Each entry has an
1230
+ opaque `fileId` used by `GET/PUT …/{fileId}`.
1231
+ parameters:
1232
+ - { name: provider, in: path, required: true, schema: { type: string } }
1233
+ responses:
1234
+ '200':
1235
+ description: Config file catalog.
1236
+ content:
1237
+ application/json:
1238
+ schema:
1239
+ type: array
1240
+ items:
1241
+ type: object
1242
+ properties:
1243
+ fileId: { type: string }
1244
+ path: { type: string }
1245
+ label: { type: string }
1246
+ exists: { type: boolean }
1247
+ size: { type: integer, nullable: true }
1248
+
1249
+ /api/providers/{provider}/config-files/{fileId}:
1250
+ get:
1251
+ tags: [Providers]
1252
+ summary: Read a provider config file's contents
1253
+ parameters:
1254
+ - { name: provider, in: path, required: true, schema: { type: string } }
1255
+ - { name: fileId, in: path, required: true, schema: { type: string } }
1256
+ responses:
1257
+ '200':
1258
+ description: File contents.
1259
+ content:
1260
+ application/json:
1261
+ schema:
1262
+ type: object
1263
+ properties:
1264
+ content: { type: string }
1265
+ path: { type: string }
1266
+ encoding: { type: string, enum: [utf-8] }
1267
+ put:
1268
+ tags: [Providers]
1269
+ summary: Overwrite a provider config file
1270
+ parameters:
1271
+ - { name: provider, in: path, required: true, schema: { type: string } }
1272
+ - { name: fileId, in: path, required: true, schema: { type: string } }
1273
+ requestBody:
1274
+ required: true
1275
+ content:
1276
+ application/json:
1277
+ schema:
1278
+ type: object
1279
+ required: [content]
1280
+ properties:
1281
+ content: { type: string }
1282
+ responses:
1283
+ '200': { description: Saved. }
1284
+ '400': { description: Content failed validation (e.g. malformed JSON). }
1285
+
1286
+ /api/orchestration/workflows:
1287
+ get:
1288
+ tags: [Orchestration]
1289
+ summary: List built-in workflow modes
1290
+ description: |
1291
+ Returns the available "Çalışma modu / Work mode" definitions. The
1292
+ `agent_team` workflow is dynamic: it expands from the API caller's
1293
+ `metadata.agents` list at preview/run time.
1294
+ responses:
1295
+ '200':
1296
+ description: Workflow catalog.
1297
+ content:
1298
+ application/json:
1299
+ schema:
1300
+ type: object
1301
+ properties:
1302
+ workflows:
1303
+ type: array
1304
+ items:
1305
+ type: object
1306
+ additionalProperties: true
1307
+
1308
+ /api/orchestration/workflows/context:
1309
+ get:
1310
+ tags: [Orchestration]
1311
+ summary: Read workflow execution context
1312
+ description: |
1313
+ Returns the Pixcode app root and supported target workspace modes so
1314
+ clients can decide whether child agents should run in the selected
1315
+ project, Pixcode itself, or a custom path.
1316
+ responses:
1317
+ '200':
1318
+ description: Workflow execution context.
1319
+ content:
1320
+ application/json:
1321
+ schema:
1322
+ type: object
1323
+ properties:
1324
+ appRoot: { type: string, example: /root/pixcode }
1325
+ defaultWorkspaceTarget: { type: string, example: selected_project }
1326
+ supportedWorkspaceTargets:
1327
+ type: array
1328
+ items:
1329
+ type: string
1330
+ enum: [selected_project, pixcode_app, custom]
1331
+
1332
+ /api/orchestration/workflows/{workflowId}/preview:
1333
+ post:
1334
+ tags: [Orchestration]
1335
+ summary: Preview expanded workflow DAG without running agents
1336
+ description: |
1337
+ Dry-run endpoint for API clients and automated tests. It expands
1338
+ `metadata.agents` into the actual node graph, validates dependencies,
1339
+ and returns node ids, adapters, inputs, fail policy, and timeout values.
1340
+
1341
+ Use `metadata.agents[].role` (`backend`, `frontend`, `review`,
1342
+ `implementation`) for language-independent routing. `instruction` is
1343
+ optional and fully caller-controlled.
1344
+ parameters:
1345
+ - name: workflowId
1346
+ in: path
1347
+ required: true
1348
+ schema: { type: string, example: agent_team }
1349
+ requestBody:
1350
+ required: false
1351
+ content:
1352
+ application/json:
1353
+ schema: { $ref: '#/components/schemas/WorkflowRunCreateRequest' }
1354
+ examples:
1355
+ roleBasedAgentTeam:
1356
+ summary: Role-based agent team, no fixed instruction language
1357
+ value:
1358
+ metadata:
1359
+ agents:
1360
+ - adapterId: codex
1361
+ label: Frontend Agent
1362
+ role: frontend
1363
+ - adapterId: codex
1364
+ label: Backend Agent
1365
+ role: backend
1366
+ - adapterId: codex
1367
+ label: Review Agent
1368
+ role: review
1369
+ settings:
1370
+ maxParallelAgents: 3
1371
+ isolation: host
1372
+ responses:
1373
+ '200':
1374
+ description: Expanded workflow graph.
1375
+ content:
1376
+ application/json:
1377
+ schema: { $ref: '#/components/schemas/WorkflowPreviewResponse' }
1378
+ '400':
1379
+ description: Invalid workflow metadata.
1380
+
1381
+ /api/orchestration/workflows/{workflowId}/runs:
1382
+ post:
1383
+ tags: [Orchestration]
1384
+ summary: Start a workflow run
1385
+ description: |
1386
+ Starts a multi-agent workflow. Every child A2A task shares one
1387
+ `contextId`, and the returned `nodeRuns[].a2aTaskId` values can be used
1388
+ for low-level A2A inspection.
1389
+
1390
+ For `agent_team`, Pixcode creates a coordinator, optional bounded
1391
+ backend handoff nodes, worker nodes, review nodes, and a final report.
1392
+ Frontend agents depend on backend handoff contracts, not on the full
1393
+ backend implementation, so one slow backend task does not block all
1394
+ UI work.
1395
+ parameters:
1396
+ - name: workflowId
1397
+ in: path
1398
+ required: true
1399
+ schema: { type: string, example: agent_team }
1400
+ requestBody:
1401
+ required: true
1402
+ content:
1403
+ application/json:
1404
+ schema: { $ref: '#/components/schemas/WorkflowRunCreateRequest' }
1405
+ responses:
1406
+ '202':
1407
+ description: Workflow accepted.
1408
+ content:
1409
+ application/json:
1410
+ schema: { $ref: '#/components/schemas/WorkflowRun' }
1411
+ '400':
1412
+ description: Invalid workflow request.
1413
+ '404':
1414
+ description: Workflow not found.
1415
+
1416
+ /api/orchestration/workflows/runs:
1417
+ get:
1418
+ tags: [Orchestration]
1419
+ summary: List workflow runs
1420
+ parameters:
1421
+ - name: projectId
1422
+ in: query
1423
+ required: false
1424
+ schema: { type: string }
1425
+ responses:
1426
+ '200':
1427
+ description: Runs sorted newest first.
1428
+ content:
1429
+ application/json:
1430
+ schema:
1431
+ type: object
1432
+ properties:
1433
+ runs:
1434
+ type: array
1435
+ items: { $ref: '#/components/schemas/WorkflowRun' }
1436
+
1437
+ /api/orchestration/workflows/runs/{runId}:
1438
+ get:
1439
+ tags: [Orchestration]
1440
+ summary: Read one workflow run snapshot
1441
+ parameters:
1442
+ - name: runId
1443
+ in: path
1444
+ required: true
1445
+ schema: { type: string }
1446
+ responses:
1447
+ '200':
1448
+ description: Workflow run state.
1449
+ content:
1450
+ application/json:
1451
+ schema: { $ref: '#/components/schemas/WorkflowRun' }
1452
+ '404':
1453
+ description: Run not found.
1454
+
1455
+ /api/orchestration/workflows/runs/{runId}/events:
1456
+ get:
1457
+ tags: [Orchestration]
1458
+ summary: Stream workflow run snapshots (SSE)
1459
+ description: |
1460
+ Emits `event: snapshot` frames every second while the run is active.
1461
+ Each `data:` payload is `{ "run": WorkflowRun }`. The stream ends
1462
+ automatically when the run reaches `completed`, `failed`, or
1463
+ `canceled`.
1464
+ parameters:
1465
+ - name: runId
1466
+ in: path
1467
+ required: true
1468
+ schema: { type: string }
1469
+ responses:
1470
+ '200':
1471
+ description: Server-Sent Events stream.
1472
+ content:
1473
+ text/event-stream:
1474
+ schema: { type: string }
1475
+ '404':
1476
+ description: Run not found.
1477
+
1478
+ /api/orchestration/workflows/runs/{runId}/cancel:
1479
+ post:
1480
+ tags: [Orchestration]
1481
+ summary: Cancel a workflow run and active child A2A tasks
1482
+ parameters:
1483
+ - name: runId
1484
+ in: path
1485
+ required: true
1486
+ schema: { type: string }
1487
+ responses:
1488
+ '200':
1489
+ description: Updated canceled run.
1490
+ content:
1491
+ application/json:
1492
+ schema: { $ref: '#/components/schemas/WorkflowRun' }
1493
+ '404':
1494
+ description: Run not found.
1495
+
1496
+ /api/network/endpoints:
1497
+ get:
1498
+ tags: [Network]
1499
+ summary: LAN endpoints for mobile QR pairing
1500
+ description: Returns every reachable IPv4 the host has bound, formatted as `http://<ip>:<port>`.
1501
+ responses:
1502
+ '200':
1503
+ description: LAN endpoint list.
1504
+ content:
1505
+ application/json:
1506
+ schema:
1507
+ type: object
1508
+ properties:
1509
+ endpoints: { type: array, items: { type: string } }
1510
+ port: { type: integer }
1511
+
1512
+ /api/network/external:
1513
+ get:
1514
+ tags: [Network]
1515
+ summary: Current external-access state (UPnP + tunnel)
1516
+ responses:
1517
+ '200':
1518
+ description: Snapshot.
1519
+ content:
1520
+ application/json:
1521
+ schema:
1522
+ type: object
1523
+ properties:
1524
+ upnp:
1525
+ type: object
1526
+ properties:
1527
+ active: { type: boolean }
1528
+ externalIp: { type: string, nullable: true }
1529
+ mappedPort: { type: integer, nullable: true }
1530
+ tunnel:
1531
+ type: object
1532
+ properties:
1533
+ active: { type: boolean }
1534
+ provider: { type: string, enum: [cloudflared, ngrok], nullable: true }
1535
+ url: { type: string, nullable: true }
1536
+
1537
+ /api/network/upnp:
1538
+ post:
1539
+ tags: [Network]
1540
+ summary: Open the LAN port on the router
1541
+ responses:
1542
+ '200': { description: Mapping created (or already present). }
1543
+ delete:
1544
+ tags: [Network]
1545
+ summary: Remove the UPnP mapping
1546
+ responses:
1547
+ '200': { description: Removed. }
1548
+
1549
+ /api/network/tunnel:
1550
+ post:
1551
+ tags: [Network]
1552
+ summary: Start a public tunnel (cloudflared / ngrok auto-detect)
1553
+ responses:
1554
+ '200':
1555
+ description: Tunnel started; URL returned.
1556
+ content:
1557
+ application/json:
1558
+ schema:
1559
+ type: object
1560
+ properties:
1561
+ url: { type: string, format: uri }
1562
+ provider: { type: string }
1563
+ delete:
1564
+ tags: [Network]
1565
+ summary: Stop the tunnel
1566
+ responses:
1567
+ '200': { description: Stopped. }
1568
+
1569
+ /api/settings/notification-preferences:
1570
+ get:
1571
+ tags: [Settings]
1572
+ summary: Get notification preferences
1573
+ responses:
1574
+ '200':
1575
+ description: Per-channel + per-event toggles.
1576
+ content:
1577
+ application/json:
1578
+ schema:
1579
+ type: object
1580
+ properties:
1581
+ preferences:
1582
+ type: object
1583
+ properties:
1584
+ channels:
1585
+ type: object
1586
+ properties:
1587
+ inApp: { type: boolean }
1588
+ webPush: { type: boolean }
1589
+ events:
1590
+ type: object
1591
+ properties:
1592
+ actionRequired: { type: boolean }
1593
+ stop: { type: boolean }
1594
+ error: { type: boolean }
1595
+ put:
1596
+ tags: [Settings]
1597
+ summary: Update notification preferences
1598
+ requestBody:
1599
+ required: true
1600
+ content:
1601
+ application/json:
1602
+ schema: { type: object }
1603
+ responses:
1604
+ '200': { description: Saved. }
1605
+
1606
+ /api/agent:
1607
+ post:
1608
+ tags: [Providers]
1609
+ summary: External REST entry point (API-key authenticated)
1610
+ description: |
1611
+ One-shot non-interactive run for automation/CI. Spawns the chosen
1612
+ provider, optionally cloning a GitHub repo first, optionally cutting
1613
+ a branch + opening a PR. **API key required** — accepts the same `ck_`
1614
+ keys as the rest of the API on `Authorization: Bearer`, `X-API-Key`,
1615
+ or `?apiKey=`.
1616
+
1617
+ Default response is an SSE stream of provider-native events; pass
1618
+ `stream: false` to buffer and return JSON.
1619
+ security:
1620
+ - bearerAuth: []
1621
+ - apiKeyAuth: []
1622
+ requestBody:
1623
+ required: true
1624
+ content:
1625
+ application/json:
1626
+ schema:
1627
+ type: object
1628
+ required: [message]
1629
+ properties:
1630
+ message:
1631
+ type: string
1632
+ description: Prompt text to send to the agent.
1633
+ provider:
1634
+ type: string
1635
+ enum: [claude, cursor, codex, gemini, qwen, opencode]
1636
+ default: claude
1637
+ model:
1638
+ type: string
1639
+ description: Provider-specific model id (e.g. `opencode/gpt-5.2`).
1640
+ projectPath:
1641
+ type: string
1642
+ description: Absolute path on the host. Required if `githubUrl` is omitted.
1643
+ githubUrl:
1644
+ type: string
1645
+ format: uri
1646
+ description: Clone this repo before running. Mutually inclusive with `projectPath` (used as the clone target if both are given).
1647
+ githubToken:
1648
+ type: string
1649
+ description: Optional override for the per-user GitHub PAT stored under Settings → Git.
1650
+ branchName:
1651
+ type: string
1652
+ description: 'Cutting `branchName` implies `createBranch: true`.'
1653
+ createBranch:
1654
+ type: boolean
1655
+ default: false
1656
+ createPR:
1657
+ type: boolean
1658
+ default: false
1659
+ sessionId:
1660
+ type: string
1661
+ description: Resume an existing session instead of starting a new one.
1662
+ stream:
1663
+ type: boolean
1664
+ default: true
1665
+ description: 'Set false to buffer to a single JSON response.'
1666
+ cleanup:
1667
+ type: boolean
1668
+ default: true
1669
+ description: When `githubUrl` was used, delete the temp clone after the run.
1670
+ responses:
1671
+ '200':
1672
+ description: |
1673
+ When `stream:true` — SSE stream of provider events. When `stream:false` — final JSON payload with `text` + `sessionId` + `usage`.
1674
+ content:
1675
+ application/json:
1676
+ schema:
1677
+ type: object
1678
+ properties:
1679
+ text: { type: string }
1680
+ sessionId: { type: string }
1681
+ usage:
1682
+ type: object
1683
+ properties:
1684
+ input: { type: integer }
1685
+ output: { type: integer }
1686
+ total: { type: integer }
1687
+ cost: { type: number }
1688
+ text/event-stream:
1689
+ schema: { type: string }
1690
+ '400':
1691
+ description: 'Missing required fields, unknown provider, or invalid GitHub URL.'
1692
+ '401':
1693
+ description: Missing or invalid API key.