@pixelbyte-software/pixcode 1.35.1 → 1.35.2

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 (172) 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 -548
  10. package/dist/assets/{index-CBdsvGSR.js → index-D1-AIL_5.js} +1 -1
  11. package/dist/clear-cache.html +85 -85
  12. package/dist/convert-icons.md +52 -52
  13. package/dist/favicon.svg +8 -8
  14. package/dist/generate-icons.js +48 -48
  15. package/dist/icons/codex-white.svg +3 -3
  16. package/dist/icons/codex.svg +3 -3
  17. package/dist/icons/cursor-white.svg +11 -11
  18. package/dist/icons/icon-128x128.svg +9 -9
  19. package/dist/icons/icon-144x144.svg +9 -9
  20. package/dist/icons/icon-152x152.svg +9 -9
  21. package/dist/icons/icon-192x192.svg +9 -9
  22. package/dist/icons/icon-384x384.svg +9 -9
  23. package/dist/icons/icon-512x512.svg +9 -9
  24. package/dist/icons/icon-72x72.svg +9 -9
  25. package/dist/icons/icon-96x96.svg +9 -9
  26. package/dist/icons/icon-template.svg +9 -9
  27. package/dist/icons/qwen-logo.svg +14 -14
  28. package/dist/index.html +58 -58
  29. package/dist/logo.svg +12 -12
  30. package/dist/manifest.json +60 -60
  31. package/dist/openapi.yaml +1693 -1693
  32. package/dist/sw.js +124 -124
  33. package/dist-server/server/cli.js +96 -96
  34. package/dist-server/server/daemon/manager.js +33 -33
  35. package/dist-server/server/daemon-manager.js +64 -64
  36. package/dist-server/server/routes/commands.js +25 -25
  37. package/dist-server/server/routes/git.js +17 -17
  38. package/dist-server/server/routes/taskmaster.js +419 -419
  39. package/package.json +180 -180
  40. package/scripts/fix-node-pty.js +67 -67
  41. package/scripts/smoke/a2a-roundtrip.mjs +167 -167
  42. package/scripts/smoke/orchestration-api.mjs +172 -172
  43. package/scripts/smoke/orchestration-live-run.mjs +176 -176
  44. package/server/claude-sdk.js +898 -898
  45. package/server/cli.js +935 -935
  46. package/server/constants/config.js +4 -4
  47. package/server/cursor-cli.js +342 -342
  48. package/server/daemon/manager.js +564 -564
  49. package/server/daemon-manager.js +959 -959
  50. package/server/database/db.js +794 -794
  51. package/server/database/json-store.js +197 -197
  52. package/server/gemini-cli.js +535 -535
  53. package/server/gemini-response-handler.js +79 -79
  54. package/server/index.js +3135 -3135
  55. package/server/load-env.js +34 -34
  56. package/server/middleware/auth.js +173 -173
  57. package/server/modules/orchestration/a2a/adapter-registry.ts +108 -108
  58. package/server/modules/orchestration/a2a/adapters/abstract-a2a.adapter.ts +55 -55
  59. package/server/modules/orchestration/a2a/adapters/claude-code.adapter.ts +284 -284
  60. package/server/modules/orchestration/a2a/adapters/codex.adapter.ts +244 -244
  61. package/server/modules/orchestration/a2a/adapters/cursor.adapter.ts +249 -249
  62. package/server/modules/orchestration/a2a/adapters/gemini.adapter.ts +248 -248
  63. package/server/modules/orchestration/a2a/adapters/opencode.adapter.ts +248 -248
  64. package/server/modules/orchestration/a2a/adapters/qwen.adapter.ts +248 -248
  65. package/server/modules/orchestration/a2a/routes.ts +577 -577
  66. package/server/modules/orchestration/a2a/task-store.ts +178 -178
  67. package/server/modules/orchestration/a2a/types.ts +125 -125
  68. package/server/modules/orchestration/a2a/validator.ts +113 -113
  69. package/server/modules/orchestration/index.ts +66 -66
  70. package/server/modules/orchestration/preview/port-watcher.ts +112 -112
  71. package/server/modules/orchestration/preview/preview-proxy.ts +60 -60
  72. package/server/modules/orchestration/preview/types.ts +19 -19
  73. package/server/modules/orchestration/tasks/orchestration-task-store.ts +45 -45
  74. package/server/modules/orchestration/tasks/orchestration-task.routes.ts +73 -73
  75. package/server/modules/orchestration/tasks/orchestration-task.service.ts +145 -145
  76. package/server/modules/orchestration/tasks/orchestration-task.types.ts +29 -29
  77. package/server/modules/orchestration/workflows/built-in-workflows.ts +127 -127
  78. package/server/modules/orchestration/workflows/workflow-runner.ts +1206 -1206
  79. package/server/modules/orchestration/workflows/workflow-store.ts +97 -97
  80. package/server/modules/orchestration/workflows/workflow.routes.ts +169 -169
  81. package/server/modules/orchestration/workflows/workflow.types.ts +70 -70
  82. package/server/modules/orchestration/workflows/workspace-target.ts +120 -120
  83. package/server/modules/orchestration/workspace/docker-workspace.ts +135 -135
  84. package/server/modules/orchestration/workspace/path-safety.ts +55 -55
  85. package/server/modules/orchestration/workspace/types.ts +52 -52
  86. package/server/modules/orchestration/workspace/workspace-manager.ts +97 -97
  87. package/server/modules/orchestration/workspace/worktree-workspace.ts +125 -125
  88. package/server/modules/providers/index.ts +2 -2
  89. package/server/modules/providers/list/claude/claude-auth.provider.ts +145 -145
  90. package/server/modules/providers/list/claude/claude-mcp.provider.ts +135 -135
  91. package/server/modules/providers/list/claude/claude-sessions.provider.ts +306 -306
  92. package/server/modules/providers/list/claude/claude.provider.ts +15 -15
  93. package/server/modules/providers/list/codex/codex-auth.provider.ts +115 -115
  94. package/server/modules/providers/list/codex/codex-mcp.provider.ts +135 -135
  95. package/server/modules/providers/list/codex/codex-sessions.provider.ts +319 -319
  96. package/server/modules/providers/list/codex/codex.provider.ts +15 -15
  97. package/server/modules/providers/list/cursor/cursor-auth.provider.ts +143 -143
  98. package/server/modules/providers/list/cursor/cursor-mcp.provider.ts +108 -108
  99. package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +421 -421
  100. package/server/modules/providers/list/cursor/cursor.provider.ts +15 -15
  101. package/server/modules/providers/list/gemini/gemini-auth.provider.ts +163 -163
  102. package/server/modules/providers/list/gemini/gemini-mcp.provider.ts +110 -110
  103. package/server/modules/providers/list/gemini/gemini-sessions.provider.ts +227 -227
  104. package/server/modules/providers/list/gemini/gemini.provider.ts +15 -15
  105. package/server/modules/providers/list/opencode/opencode-auth.provider.ts +130 -130
  106. package/server/modules/providers/list/opencode/opencode-mcp.provider.ts +126 -126
  107. package/server/modules/providers/list/opencode/opencode-sessions.provider.ts +232 -232
  108. package/server/modules/providers/list/opencode/opencode.provider.ts +29 -29
  109. package/server/modules/providers/list/qwen/qwen-auth.provider.ts +145 -145
  110. package/server/modules/providers/list/qwen/qwen-mcp.provider.ts +114 -114
  111. package/server/modules/providers/list/qwen/qwen-sessions.provider.ts +265 -265
  112. package/server/modules/providers/list/qwen/qwen.provider.ts +21 -21
  113. package/server/modules/providers/provider.registry.ts +40 -40
  114. package/server/modules/providers/provider.routes.ts +819 -819
  115. package/server/modules/providers/services/mcp.service.ts +86 -86
  116. package/server/modules/providers/services/provider-auth.service.ts +26 -26
  117. package/server/modules/providers/services/sessions.service.ts +45 -45
  118. package/server/modules/providers/shared/base/abstract.provider.ts +20 -20
  119. package/server/modules/providers/shared/mcp/mcp.provider.ts +151 -151
  120. package/server/modules/providers/shared/provider-configs.ts +142 -142
  121. package/server/modules/providers/tests/mcp.test.ts +293 -293
  122. package/server/openai-codex.js +462 -462
  123. package/server/opencode-cli.js +459 -459
  124. package/server/opencode-response-handler.js +107 -107
  125. package/server/projects.js +3105 -3105
  126. package/server/qwen-code-cli.js +395 -395
  127. package/server/qwen-response-handler.js +73 -73
  128. package/server/routes/agent.js +1365 -1365
  129. package/server/routes/auth.js +138 -138
  130. package/server/routes/codex.js +19 -19
  131. package/server/routes/commands.js +554 -554
  132. package/server/routes/cursor.js +52 -52
  133. package/server/routes/gemini.js +24 -24
  134. package/server/routes/git.js +1488 -1488
  135. package/server/routes/mcp-utils.js +31 -31
  136. package/server/routes/messages.js +61 -61
  137. package/server/routes/network.js +120 -120
  138. package/server/routes/plugins.js +318 -318
  139. package/server/routes/projects.js +915 -915
  140. package/server/routes/qwen.js +27 -27
  141. package/server/routes/settings.js +286 -286
  142. package/server/routes/taskmaster.js +1496 -1496
  143. package/server/routes/telegram.js +125 -125
  144. package/server/routes/user.js +123 -123
  145. package/server/services/external-access.js +171 -171
  146. package/server/services/install-jobs.js +571 -571
  147. package/server/services/notification-orchestrator.js +242 -242
  148. package/server/services/provider-credentials.js +189 -189
  149. package/server/services/provider-models.js +381 -381
  150. package/server/services/telegram/bot.js +279 -279
  151. package/server/services/telegram/telegram-http-client.js +130 -130
  152. package/server/services/telegram/translations.js +170 -170
  153. package/server/services/vapid-keys.js +36 -36
  154. package/server/sessionManager.js +225 -225
  155. package/server/shared/interfaces.ts +54 -54
  156. package/server/shared/types.ts +172 -172
  157. package/server/shared/utils.ts +193 -193
  158. package/server/tsconfig.json +36 -36
  159. package/server/utils/colors.js +21 -21
  160. package/server/utils/commandParser.js +303 -303
  161. package/server/utils/frontmatter.js +18 -18
  162. package/server/utils/gitConfig.js +34 -34
  163. package/server/utils/mcp-detector.js +147 -147
  164. package/server/utils/plugin-loader.js +457 -457
  165. package/server/utils/plugin-process-manager.js +184 -184
  166. package/server/utils/port-access.js +209 -209
  167. package/server/utils/runtime-paths.js +37 -37
  168. package/server/utils/taskmaster-websocket.js +128 -128
  169. package/server/utils/url-detection.js +71 -71
  170. package/server/vite-daemon.js +78 -78
  171. package/shared/modelConstants.js +162 -162
  172. package/shared/networkHosts.js +22 -22
package/dist/openapi.yaml CHANGED
@@ -1,1693 +1,1693 @@
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.
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.