@starlove/orbit 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dockerignore +13 -0
- package/Dockerfile +34 -0
- package/README.md +216 -0
- package/SKILL-ORBIT.md +94 -0
- package/build.mjs +204 -0
- package/dist/full/apple-touch-icon.png +0 -0
- package/dist/full/cursors/live_arrow.cur +0 -0
- package/dist/full/cursors/live_link.cur +0 -0
- package/dist/full/cursors/live_move.cur +0 -0
- package/dist/full/cursors/live_select.cur +0 -0
- package/dist/full/cursors/live_unavail.cur +0 -0
- package/dist/full/favicon-32x32.png +0 -0
- package/dist/full/index.html +314 -0
- package/dist/full/js/app.70be7d06.js +554 -0
- package/dist/full/js/app.70be7d06.js.map +7 -0
- package/dist/full/orbits-favicon.png +0 -0
- package/dist/full/orbits-logo-bg.png +0 -0
- package/dist/full/orbits-logo.png +0 -0
- package/dist/full/styles.c2e3d20a.css +4892 -0
- package/dist/full/version.json +6 -0
- package/docs/AGENT_PROTOCOL.md +379 -0
- package/docs/MCP_SETUP.md +49 -0
- package/docs/mcp-client.example.json +13 -0
- package/package.json +62 -0
- package/pnpm-workspace.yaml +2 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/cursors/live_arrow.cur +0 -0
- package/public/cursors/live_link.cur +0 -0
- package/public/cursors/live_move.cur +0 -0
- package/public/cursors/live_select.cur +0 -0
- package/public/cursors/live_unavail.cur +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/index.html +314 -0
- package/public/js/api.js +35 -0
- package/public/js/app.js +35 -0
- package/public/js/board-menu.js +145 -0
- package/public/js/config.js +19 -0
- package/public/js/create-card.js +153 -0
- package/public/js/dom.js +19 -0
- package/public/js/drawer.js +137 -0
- package/public/js/format.js +108 -0
- package/public/js/kanban.js +475 -0
- package/public/js/local-backend.js +934 -0
- package/public/js/main.js +142 -0
- package/public/js/modal.js +31 -0
- package/public/js/router.js +114 -0
- package/public/js/search.js +53 -0
- package/public/js/settings-tabs.js +7 -0
- package/public/js/settings.js +931 -0
- package/public/js/sse.js +156 -0
- package/public/js/starscape.js +315 -0
- package/public/js/state.js +54 -0
- package/public/js/ticket-detail.js +766 -0
- package/public/js/toast.js +74 -0
- package/public/js/transport.js +22 -0
- package/public/js/unread.js +121 -0
- package/public/orbits-favicon.png +0 -0
- package/public/orbits-logo-bg.png +0 -0
- package/public/orbits-logo.png +0 -0
- package/public/styles.css +4892 -0
- package/src/cli/orbit.js +438 -0
- package/src/core/agent.js +262 -0
- package/src/core/auth.js +49 -0
- package/src/core/backups.js +136 -0
- package/src/core/board.js +112 -0
- package/src/core/boards.js +310 -0
- package/src/core/bootstrap.js +162 -0
- package/src/core/db.js +237 -0
- package/src/core/delete-board.js +53 -0
- package/src/core/events.js +314 -0
- package/src/core/http.js +81 -0
- package/src/core/paths.js +25 -0
- package/src/core/provision-repo-board.js +113 -0
- package/src/core/queries.js +246 -0
- package/src/core/registry.js +207 -0
- package/src/core/relations.js +163 -0
- package/src/core/router.js +414 -0
- package/src/core/search.js +70 -0
- package/src/core/seed.js +226 -0
- package/src/core/snapshots.js +255 -0
- package/src/core/states.js +167 -0
- package/src/core/system-picker.js +93 -0
- package/src/core/tickets.js +344 -0
- package/src/core/util.js +105 -0
- package/src/mcp-server.js +773 -0
- package/src/server.js +48 -0
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
# Agent Protocol
|
|
2
|
+
|
|
3
|
+
The board is intentionally agent-first. Agents should not scrape the UI. They should call the API and ask for narrow context packs.
|
|
4
|
+
|
|
5
|
+
If an MCP client is available, use the MCP server instead of rebuilding these HTTP calls yourself. The MCP tools map directly to the same core operations.
|
|
6
|
+
|
|
7
|
+
## Core Flow
|
|
8
|
+
|
|
9
|
+
1. `POST /api/agent/claim-next`
|
|
10
|
+
2. Implement using the returned context pack.
|
|
11
|
+
3. Add progress comments with `POST /api/tickets/:id/comments`.
|
|
12
|
+
4. If blocked by human judgment, call `POST /api/agent/checkpoint`.
|
|
13
|
+
5. When ready for review, call `POST /api/agent/complete`.
|
|
14
|
+
|
|
15
|
+
### End-to-end example
|
|
16
|
+
|
|
17
|
+
```http
|
|
18
|
+
POST /api/agent/claim-next
|
|
19
|
+
Content-Type: application/json
|
|
20
|
+
|
|
21
|
+
{ "board": "your-board-slug" }
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The response includes the claimed `ticket` and a `context` pack. After working the ticket:
|
|
25
|
+
|
|
26
|
+
```http
|
|
27
|
+
POST /api/tickets/abc123/comments
|
|
28
|
+
Content-Type: application/json
|
|
29
|
+
|
|
30
|
+
{ "body": "Wired the new endpoint and added a smoke test.", "kind": "agent_note" }
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
```http
|
|
34
|
+
POST /api/agent/complete
|
|
35
|
+
Content-Type: application/json
|
|
36
|
+
|
|
37
|
+
{
|
|
38
|
+
"ticket_id": "abc123",
|
|
39
|
+
"summary": "Implemented the new endpoint with input validation and tests.",
|
|
40
|
+
"updates": "Hit a flaky test on Windows; pinned timeouts to 5s.",
|
|
41
|
+
"pr_url": "https://github.com/you/repo/pull/42"
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Endpoints
|
|
46
|
+
|
|
47
|
+
### List boards (thin)
|
|
48
|
+
|
|
49
|
+
```http
|
|
50
|
+
GET /api/boards
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Returns `{ "boards": [ ... ] }` with registry metadata only (`id`, `slug`, `name`, `repo_path`, `repo_url`, `default_branch`, `db_path`, `last_active_at`). Does not load tickets or lanes. MCP equivalent: `board_list`.
|
|
54
|
+
|
|
55
|
+
For the web UI’s full default-board snapshot (tickets, states, labels, entries), the SPA calls `GET /api/bootstrap`. Agents over MCP should use `board_list`, `board_set_active`, `board_context`, and ticket-scoped tools instead—there is no MCP mirror of bootstrap.
|
|
56
|
+
|
|
57
|
+
### Claim Next
|
|
58
|
+
|
|
59
|
+
```http
|
|
60
|
+
POST /api/agent/claim-next
|
|
61
|
+
Content-Type: application/json
|
|
62
|
+
|
|
63
|
+
{
|
|
64
|
+
"board": "your-board-slug",
|
|
65
|
+
"type": "feature"
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Returns the first schedulable `AI Ready` ticket. The scheduler skips tickets blocked by unresolved `blocked_by` relations.
|
|
70
|
+
|
|
71
|
+
By default, `claim-next` skips `epic` cards because they are index/planning cards. To claim an epic for planning, pass `"type": "epic"` or `"include_epics": true`.
|
|
72
|
+
|
|
73
|
+
The response shape is `{ claimed: true, ticket_id, context }` where `context` is the lightweight `board_read_ticket` pack (`ticket` with title/description/labels/state, full `comments`, and the `board_manual`). For the heavier ticket pack with relations, blockers, and child cards, call `GET /api/tickets/:id/context` (or MCP `board_get_ticket_context`).
|
|
74
|
+
|
|
75
|
+
### Get Context Pack
|
|
76
|
+
|
|
77
|
+
```http
|
|
78
|
+
GET /api/tickets/:id/context?depth=1
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
|
|
83
|
+
- Ticket, board, state, labels.
|
|
84
|
+
- The board manual (`board_manual`), including `agent_instructions` and `project_notes`.
|
|
85
|
+
- Full comments for the assigned ticket.
|
|
86
|
+
- Dedicated implementation fields: `ai_plan`, `implementation_summary`, and `implementation_updates`.
|
|
87
|
+
- Parent epic/story ticket when present.
|
|
88
|
+
- Child feature cards when the ticket is an epic/story.
|
|
89
|
+
- Related tickets.
|
|
90
|
+
- Recent comments from directly related tickets.
|
|
91
|
+
- Blockers and blocking tickets.
|
|
92
|
+
|
|
93
|
+
### Get Ticket Relations
|
|
94
|
+
|
|
95
|
+
```http
|
|
96
|
+
GET /api/tickets/:id/relations
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Returns every link touching the ticket. Each entry has `type`, `direction` (`outgoing` / `incoming`), `source`, and a compact `other_ticket` summary.
|
|
100
|
+
|
|
101
|
+
- `source: "relation"` — peer rows from the relations table (`relates_to` / `blocks` / `blocked_by`). These have a real `id` and are mutated via `POST /api/relations` and `DELETE /api/relations/:id`.
|
|
102
|
+
- `source: "hierarchy"` — read-only synthetic entries surfacing epic ownership: `child_of` pointing at the parent epic, `parent_of` pointing at each child. `id` is `null`. Mutate via `PATCH /api/tickets/:id` setting `parent_ticket_id`; the relations endpoints reject `child_of` / `parent_of` writes (`hierarchy_uses_parent_ticket_id`).
|
|
103
|
+
|
|
104
|
+
### Get Ticket Blockers
|
|
105
|
+
|
|
106
|
+
```http
|
|
107
|
+
GET /api/tickets/:id/blockers
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"ticket_id": "...",
|
|
115
|
+
"can_start": false,
|
|
116
|
+
"blockers": [
|
|
117
|
+
{ "id": "...", "number": 12, "title": "...", "state_name": "In Progress", "state_role": "in_progress" }
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Source of truth.** Blocker dependencies are defined exclusively by per-card `blocked_by` (and the inverse `blocks`) rows in the relations table — see `POST /api/tickets/:id/relations`. If a row exists, the blocker is unresolved. Rows are removed two ways: a user deletes the relation manually in the UI, or the *blocking* ticket moves into the Done lane (state role `done`) and the server auto-deletes every relation that named it as a blocker. `can_start` is `false` whenever any `blocked_by` row remains. Agents must not move a `can_start: false` ticket into a started state. The `claim-next` scheduler enforces this automatically.
|
|
123
|
+
|
|
124
|
+
**Epic expansion.** When a `blocked_by` target is an epic, the epic itself is not treated as a blocker — its open children are. A child counts as "open" while it sits in any lane whose role is not `done` (and isn't archived). Each expanded blocker carries `via_epic_id` pointing at the epic that brought it into the list, so reports can explain the dependency.
|
|
125
|
+
|
|
126
|
+
### Create / Delete Relation
|
|
127
|
+
|
|
128
|
+
```http
|
|
129
|
+
POST /api/relations
|
|
130
|
+
Content-Type: application/json
|
|
131
|
+
|
|
132
|
+
{
|
|
133
|
+
"source_ticket_id": "...",
|
|
134
|
+
"target_ticket_id": "...",
|
|
135
|
+
"type": "blocked_by"
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
```http
|
|
140
|
+
DELETE /api/relations/:id
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Rejected with HTTP 400 if the pair already has a `parent_ticket_id` link in either direction (`relation_redundant_with_parent`) or if source equals target (`relation_self`). Use `parent_ticket_id` for epic ↔ direct-child ownership; use relations only for cross-cutting links.
|
|
144
|
+
|
|
145
|
+
### Search
|
|
146
|
+
|
|
147
|
+
```http
|
|
148
|
+
GET /api/search?q=auth%20middleware&board=your-board-slug
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Searches ticket titles, descriptions, and comments.
|
|
152
|
+
|
|
153
|
+
### Board context (settings + journal)
|
|
154
|
+
|
|
155
|
+
```http
|
|
156
|
+
GET /api/boards/:board_id/context?include_struck=false
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Returns the same shape as MCP `board_context`: a trimmed `board` (`name`, `agent_instructions`, `updated_at`), `entries` (journal / decisions / lessons), and `deployment` paths. Use `include_struck=true` to include struck journal rows (default off).
|
|
160
|
+
|
|
161
|
+
MCP: `board_context` with optional `board_id` / `board_slug` / `board` and optional `include_struck`.
|
|
162
|
+
|
|
163
|
+
### Update Board
|
|
164
|
+
|
|
165
|
+
```http
|
|
166
|
+
PATCH /api/boards/:board_id
|
|
167
|
+
Content-Type: application/json
|
|
168
|
+
|
|
169
|
+
{
|
|
170
|
+
"name": "...",
|
|
171
|
+
"repo_url": "https://github.com/you/repo",
|
|
172
|
+
"system_path": "C:/path/to/repo",
|
|
173
|
+
"default_branch": "main",
|
|
174
|
+
"project_notes": "Personal reminders (optional).",
|
|
175
|
+
"agent_instructions": "Why this repo exists, capabilities, stack, constraints, and how agents should operate..."
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Each board carries a `repo_url` and `system_path` (both optional). They surface in Settings → Repository and travel with the board through export/import.
|
|
180
|
+
|
|
181
|
+
### Add Board Memory Entry
|
|
182
|
+
|
|
183
|
+
```http
|
|
184
|
+
POST /api/boards/:board_id/entries
|
|
185
|
+
Content-Type: application/json
|
|
186
|
+
|
|
187
|
+
{
|
|
188
|
+
"type": "decision",
|
|
189
|
+
"title": "Use journal entries as agent-facing project memory",
|
|
190
|
+
"body": "Record Decisions for UX and architecture choices agents should follow. Record Lessons for mistakes or discoveries distilled as 'do X instead of Y when working with Z.'"
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Allowed entry types:
|
|
195
|
+
|
|
196
|
+
- `decision`: UX or architecture choices agents should follow instead of defaulting to generic codegen.
|
|
197
|
+
- `lesson`: mistakes or discoveries distilled as "do X instead of Y when working with Z."
|
|
198
|
+
|
|
199
|
+
Entries with `struck_at` set are retained for human review but omitted from board manual/context responses unless the REST client explicitly requests `include_struck=true`.
|
|
200
|
+
|
|
201
|
+
### Strike Or Restore Board Memory Entry
|
|
202
|
+
|
|
203
|
+
```http
|
|
204
|
+
PATCH /api/board-entries/:entry_id
|
|
205
|
+
Content-Type: application/json
|
|
206
|
+
|
|
207
|
+
{
|
|
208
|
+
"struck": true
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Export Board Snapshot
|
|
213
|
+
|
|
214
|
+
```http
|
|
215
|
+
GET /api/boards/:board_id/export
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Returns a JSON snapshot of the board, states, tickets, comments, relations, board entries, and relevant event history.
|
|
219
|
+
|
|
220
|
+
### Import Board Snapshot
|
|
221
|
+
|
|
222
|
+
```http
|
|
223
|
+
POST /api/admin/import
|
|
224
|
+
Content-Type: application/json
|
|
225
|
+
|
|
226
|
+
{
|
|
227
|
+
"snapshot": { "...": "export payload" },
|
|
228
|
+
"replace_existing": true
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Replaces the current board with a previously exported snapshot. Export first if you want a rollback point.
|
|
233
|
+
|
|
234
|
+
### Add Comment
|
|
235
|
+
|
|
236
|
+
```http
|
|
237
|
+
POST /api/tickets/:id/comments
|
|
238
|
+
Content-Type: application/json
|
|
239
|
+
|
|
240
|
+
{
|
|
241
|
+
"body": "Implementation note...",
|
|
242
|
+
"kind": "agent_note"
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Comments are for discussion and event breadcrumbs. Use the dedicated fields below for durable implementation records.
|
|
247
|
+
|
|
248
|
+
### Update AI Plan / Implementation Fields
|
|
249
|
+
|
|
250
|
+
```http
|
|
251
|
+
PATCH /api/tickets/:id
|
|
252
|
+
Content-Type: application/json
|
|
253
|
+
|
|
254
|
+
{
|
|
255
|
+
"ai_plan": "The current plan...",
|
|
256
|
+
"implementation_summary": "What shipped...",
|
|
257
|
+
"implementation_updates": "Progress notes, mistakes to avoid, discoveries..."
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Field intent:
|
|
262
|
+
|
|
263
|
+
- `ai_plan`: The current plan. For epics, this should describe the high-level vision and feature breakdown. For feature/task/bug cards, this should describe the concrete implementation approach.
|
|
264
|
+
- `implementation_summary`: The final concise summary of what changed, usually written when the card moves to review or done.
|
|
265
|
+
- `implementation_updates`: Chronological notes, mistakes, discoveries, and "avoid this next time" material. Later this can feed a separate insights system.
|
|
266
|
+
|
|
267
|
+
### Archive, Restore, and Delete
|
|
268
|
+
|
|
269
|
+
Removing a card is a two-step contract: archive first (soft-delete), then optionally permanently delete. Restore reverses an archive.
|
|
270
|
+
|
|
271
|
+
```http
|
|
272
|
+
POST /api/tickets/:id/archive
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Soft-deletes the ticket: sets `archived_at` to the current time and bumps `updated_at`. Archived tickets are filtered out of `GET /api/bootstrap`, `GET /api/search`, `POST /api/agent/claim-next`, `GET /api/tickets/:id/blockers`, `GET /api/tickets/:id/relations`, and child-of-epic listings. Their data, comments, labels, and relations are preserved. Idempotent — archiving an already-archived ticket is a no-op.
|
|
276
|
+
|
|
277
|
+
```http
|
|
278
|
+
POST /api/tickets/:id/restore
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Clears `archived_at`. The ticket reappears on the kanban in its previous lane (the `state_id` is preserved across archive/restore).
|
|
282
|
+
|
|
283
|
+
```http
|
|
284
|
+
DELETE /api/tickets/:id
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Permanently removes the ticket. Returns `409 ticket_not_archived` if the ticket is not currently archived. Cascades delete all comments, ticket-label rows, and relations. Events for the ticket are kept but their `ticket_id` is set to `NULL`. Response: `{ "ok": true, "deleted_id": "..." }`.
|
|
288
|
+
|
|
289
|
+
```http
|
|
290
|
+
GET /api/boards/:board_id/archive
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Returns `{ "tickets": [...] }` — all archived tickets for the board, ordered by `archived_at` descending (most recent first). Each ticket carries the same fields as `bootstrap.tickets`.
|
|
294
|
+
|
|
295
|
+
Over MCP these are exposed as `board_archive_ticket`, `board_restore_ticket`, `board_delete_ticket`, and `board_list_archive`. Always archive when intent is "remove"; only delete when intent is "delete forever and you have already confirmed."
|
|
296
|
+
|
|
297
|
+
### Create Epic With Feature Cards
|
|
298
|
+
|
|
299
|
+
Ticket types are `epic`, `feature`, `task`, and `bug`.
|
|
300
|
+
|
|
301
|
+
Create the epic/story parent first:
|
|
302
|
+
|
|
303
|
+
```http
|
|
304
|
+
POST /api/tickets
|
|
305
|
+
Content-Type: application/json
|
|
306
|
+
|
|
307
|
+
{
|
|
308
|
+
"board_id": "board-id",
|
|
309
|
+
"type": "epic",
|
|
310
|
+
"title": "Build offline-first sync",
|
|
311
|
+
"description": "High-level vision and outcome.",
|
|
312
|
+
"ai_plan": "Feature 1: schema. Feature 2: queue. Feature 3: conflict UI.",
|
|
313
|
+
"labels": ["ai-eligible"]
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Then create feature cards with `parent_ticket_id`:
|
|
318
|
+
|
|
319
|
+
```http
|
|
320
|
+
POST /api/tickets
|
|
321
|
+
Content-Type: application/json
|
|
322
|
+
|
|
323
|
+
{
|
|
324
|
+
"board_id": "board-id",
|
|
325
|
+
"type": "feature",
|
|
326
|
+
"parent_ticket_id": "epic-ticket-id",
|
|
327
|
+
"title": "Feature 1: sync schema",
|
|
328
|
+
"ai_plan": "Implement the local operation log and migration.",
|
|
329
|
+
"labels": ["ai-eligible"]
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Checkpoint
|
|
334
|
+
|
|
335
|
+
```http
|
|
336
|
+
POST /api/agent/checkpoint
|
|
337
|
+
Content-Type: application/json
|
|
338
|
+
|
|
339
|
+
{
|
|
340
|
+
"ticket_id": "ticket-id",
|
|
341
|
+
"message": "CHECKPOINT: Option A vs B..."
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
Moves the ticket to `Review` (same lane as `/api/agent/complete`) and adds a **`checkpoint`** comment with `message`—use it for mid-flight forks; use `complete` when work is done.
|
|
346
|
+
|
|
347
|
+
### Complete
|
|
348
|
+
|
|
349
|
+
```http
|
|
350
|
+
POST /api/agent/complete
|
|
351
|
+
Content-Type: application/json
|
|
352
|
+
|
|
353
|
+
{
|
|
354
|
+
"ticket_id": "ticket-id",
|
|
355
|
+
"summary": "Implemented the requested change. Tests pass.",
|
|
356
|
+
"updates": "Important implementation notes and lessons.",
|
|
357
|
+
"pr_url": "https://github.com/you/repo/pull/123"
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
Moves the ticket to `Review` by default and writes `summary` into `implementation_summary`. If `updates` is present, it is appended to `implementation_updates`.
|
|
362
|
+
|
|
363
|
+
## Ticket Writing Contract
|
|
364
|
+
|
|
365
|
+
Agents perform best when tickets include:
|
|
366
|
+
|
|
367
|
+
- Clear requirements.
|
|
368
|
+
- Acceptance criteria.
|
|
369
|
+
- Relations for dependencies, especially `blocked_by`. Use `parent_ticket_id` for epic ownership, not relations.
|
|
370
|
+
- Pointers to previous related tickets or comments.
|
|
371
|
+
|
|
372
|
+
## Two Relationship Models
|
|
373
|
+
|
|
374
|
+
The board separates structural ownership from cross-cutting links. Treat these as non-overlapping:
|
|
375
|
+
|
|
376
|
+
- **Hierarchy (`parent_ticket_id`)** — set on the ticket row. Only epics can own children; non-epics carry the parent id. Detach by `PATCH`-ing `parent_ticket_id: null`. The dispatcher and context pack walk this link to surface parent / child cards.
|
|
377
|
+
- **Relations table** — typed links between any two tickets with `relates_to`, `blocks`, or `blocked_by`. The server rejects relation rows that mirror a `parent_ticket_id` link or point a ticket at itself, so the two models stay disjoint.
|
|
378
|
+
|
|
379
|
+
A ticket is workable only when its `can_start` is `true` (no unresolved `blocked_by`). Use `GET /api/tickets/:id/blockers` for a status check, or read the context pack which already embeds blockers and relations.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# MCP Setup
|
|
2
|
+
|
|
3
|
+
Use `mcp-client.example.json` in this folder as a copy-editable starting point for any MCP-capable client, including Cursor, Claude Desktop, Claude Code, Codex, OpenCode, and similar tools.
|
|
4
|
+
|
|
5
|
+
The easiest path is **Settings -> AI** in the web app:
|
|
6
|
+
|
|
7
|
+
1. Confirm or change the detected operating system.
|
|
8
|
+
2. Choose the AI app or agent harness.
|
|
9
|
+
3. Copy the generated setup snippet.
|
|
10
|
+
4. Paste it into that app's MCP settings or run the generated CLI command.
|
|
11
|
+
|
|
12
|
+
Orbit generates neutral template paths for Windows, macOS, and Linux. Replace those placeholders with the real path to **`src/mcp-server.js`** inside your Orbit checkout. That tells the AI client **how to spawn the MCP helper**; it does not ship markdown or project context—the agent reads files (like `SKILL-ORBIT.md`) from whichever repo/workspace you opened.
|
|
13
|
+
|
|
14
|
+
Board data lives under each tracked repo at `.orbit/board.db` (flat file or `.orbit/boards/<slug>/` for extra boards)—not beside the MCP script.
|
|
15
|
+
|
|
16
|
+
After installing Orbit as a package, run **`orbit init`** in (or with `--cwd` pointing at) the repo where you want `.orbit/`, **`AGENTS.md`**, and a copy of **`SKILL-ORBIT.md`** so agents and MCP line up with that tree. Add `--ai` to enable the AI Ready / In Progress / Review agent lanes immediately, and add `--example` if you want the onboarding example tickets.
|
|
17
|
+
|
|
18
|
+
The generated format changes by app:
|
|
19
|
+
|
|
20
|
+
- Cursor, Claude Desktop, and generic MCP clients get `mcpServers` JSON.
|
|
21
|
+
- Claude Code gets a `claude mcp add ... -- node ...` command.
|
|
22
|
+
- Codex gets a `[mcp_servers.starscape-orbit]` TOML snippet.
|
|
23
|
+
- OpenCode gets an `opencode.json` snippet under `mcp`.
|
|
24
|
+
|
|
25
|
+
The checked-in example file is not read automatically by Starscape Orbit. It exists so a user can:
|
|
26
|
+
|
|
27
|
+
1. Open the example.
|
|
28
|
+
2. Copy the `minimal-agent-board` server block into their own MCP client config.
|
|
29
|
+
3. Replace the path to `src/mcp-server.js` with the absolute path on your machine.
|
|
30
|
+
4. Restart the MCP client.
|
|
31
|
+
|
|
32
|
+
The MCP server finds a board from an explicit project root first: pass `orbit mcp --cwd <repo>` or set `PROJECT_ROOT=<repo>` in persistent MCP configs. If neither is set, it falls back to the process cwd and walks upward to the first ancestor with `.orbit/board.db`. Prefer explicit roots for long-lived agent configs so launching the agent from another folder does not attach the wrong board. **`AGENTS.md` / `SKILL-ORBIT.md`** are unrelated to MCP transport: agents open them via the workspace file tree, and `orbit init` keeps a terse Orbit pointer section in `AGENTS.md`.
|
|
33
|
+
|
|
34
|
+
Typical use:
|
|
35
|
+
|
|
36
|
+
- Keep the web UI running with `node src/server.js`.
|
|
37
|
+
- Point the MCP client at `node src/cli/orbit.js mcp --cwd /absolute/project`, set `PROJECT_ROOT=/absolute/project` with `node src/mcp-server.js`, or paste the generated setup from Settings -> AI.
|
|
38
|
+
- Use the MCP tools to claim tickets, read context, update implementation fields, and write project memory.
|
|
39
|
+
|
|
40
|
+
## System Impact
|
|
41
|
+
|
|
42
|
+
Running the MCP server starts a small local helper process. It reads and updates the same local board data as the web app, does not publish the board to the internet, and can be removed from your AI app's MCP settings whenever you want.
|
|
43
|
+
|
|
44
|
+
The MCP server is only the bridge. Your AI app is still the part that decides what to do, and that app may send ticket context to its AI provider when you ask it to work on cards. Only connect AI apps you trust with this project.
|
|
45
|
+
|
|
46
|
+
Important:
|
|
47
|
+
|
|
48
|
+
- Run the MCP helper and web server against the **same Orbit checkout and `DATA_DIR`** (default `~/.orbit`, override with `DATA_DIR=/path`) so they share one `registry.db` and agree on paths to `.orbit/board.db` files—but remember **`AGENTS.md` / `SKILL-ORBIT.md` are plain repo text**, not streamed over MCP.
|
|
49
|
+
- The generated setup assumes local/open mode. Protected deployments can still add MCP auth manually later.
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@starlove/orbit",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Starscape Orbit — SQLite-backed, agent-first task board (Starscape suite).",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"packageManager": "pnpm@10.20.0",
|
|
8
|
+
"bin": {
|
|
9
|
+
"orbit": "./src/cli/orbit.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
".dockerignore",
|
|
13
|
+
"Dockerfile",
|
|
14
|
+
"SKILL-ORBIT.md",
|
|
15
|
+
"build.mjs",
|
|
16
|
+
"docs",
|
|
17
|
+
"dist/full",
|
|
18
|
+
"pnpm-lock.yaml",
|
|
19
|
+
"pnpm-workspace.yaml",
|
|
20
|
+
"public",
|
|
21
|
+
"src",
|
|
22
|
+
"package.json"
|
|
23
|
+
],
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"prepublishOnly": "node build.mjs --edition=full",
|
|
29
|
+
"dev": "node src/server.js",
|
|
30
|
+
"dev:site": "pnpm run build:preview && pnpm run build:site && node serve-site.mjs",
|
|
31
|
+
"orbit": "node src/cli/orbit.js",
|
|
32
|
+
"build": "pnpm run build:full && pnpm run build:preview && pnpm run build:site",
|
|
33
|
+
"build:vercel": "pnpm run build:preview && pnpm run build:site",
|
|
34
|
+
"build:full": "node build.mjs --edition=full",
|
|
35
|
+
"build:preview": "node build.mjs --edition=preview",
|
|
36
|
+
"build:site": "node build.mjs --edition=site",
|
|
37
|
+
"serve:site": "node serve-site.mjs",
|
|
38
|
+
"test": "node --test"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"esbuild": "^0.25.0"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=22.0.0"
|
|
45
|
+
},
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "git+https://github.com/brucestarlove/ss-orbit.git"
|
|
49
|
+
},
|
|
50
|
+
"bugs": {
|
|
51
|
+
"url": "https://github.com/brucestarlove/ss-orbit/issues"
|
|
52
|
+
},
|
|
53
|
+
"homepage": "https://orbit.starscape.app",
|
|
54
|
+
"keywords": [
|
|
55
|
+
"kanban",
|
|
56
|
+
"agents",
|
|
57
|
+
"mcp",
|
|
58
|
+
"sqlite",
|
|
59
|
+
"task-board",
|
|
60
|
+
"claude-code"
|
|
61
|
+
]
|
|
62
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|