| 1 |
# Oxygenhub for Visual Studio Code |
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
| **Status** | Draft 0.1 | |
| 6 |
| **Scope** | The forge in the editor: sign in to an Oxygenhub, see and review proposals with comments anchored to atoms, approve with a seal, land, work with issues, watch checks, and open anything on the hub. The counterpart of the GitHub Pull Requests and Issues extension. | |
| 7 |
| **Depends on** | `oxygen-vscode` ≥ 0.7.0 (its exported API and remote providers), Oxygenhub ≥ 0.5 (`/api/v1`), `oxy` with `seal --proposal` and `proposal land` | |
| 8 |
| **Date** | 2026-09-27 | |
| 9 |
|
| 10 |
## 1. Goals |
| 11 |
|
| 12 |
1. **Everything the hub can do about a proposal or an issue is reachable without leaving the editor**, and everything that changes history still goes through `oxy` on the user's machine with the user's key: sealing an approval and landing run `oxy`, never a hub-side signature. |
| 13 |
2. **Build on oxygen-vscode, never beside it.** Repositories, status, bookmarks and remotes come from its exported API; this extension registers a remote provider so "Open on Remote" works for hubs. |
| 14 |
3. **Review where the code is.** Proposal comments appear as VS Code comment threads on the projected state's files, anchored to atoms exactly as the hub stores them, so they follow the line through rebases. |
| 15 |
4. **Honest about identity.** An approval shows as pending until the hub confirms the seal; a check shows what the hub reports. |
| 16 |
|
| 17 |
Non-goals for 1.0: creating repositories or organisations, administration, notifications beyond the status bar count, editing files on the hub. |
| 18 |
|
| 19 |
## 2. How it compares |
| 20 |
|
| 21 |
|
| 22 |
|
| 23 |
| Sign in with GitHub (OAuth) | Sign in with a personal access token; an authentication provider `oxygenhub` other extensions can request | |
| 24 |
| Pull Requests view: waiting for my review, created by me, all | Proposals view: **Assigned to me** (review requested or approval needed), **Mine**, **Open**, per repository | |
| 25 |
| Checkout PR branch | Fetch the proposal's changes and check out its projected state into a bookmark (`oxy` fetch + bookmark set) | |
| 26 |
| Review comments in the diff, threads | Comment threads on the projected state's files via the Comments API, anchored to atoms | |
| 27 |
| Approve, Request changes | Same; **Approve** also offers to run `oxy seal --proposal` so it counts | |
| 28 |
| Merge button | **Land** runs `oxy proposal land` (or the hub lands when it has no policy) | |
| 29 |
| Issues view, create issue | Same, with labels, assignees and milestone | |
| 30 |
| Checks under the PR | Checks on the projected state, live over the hub's event stream | |
| 31 |
| Open on GitHub | Open on Remote, through the remote provider | |
| 32 |
|
| 33 |
## 3. Architecture |
| 34 |
|
| 35 |
``` |
| 36 |
src/ |
| 37 |
extension.ts activation, wiring, commands |
| 38 |
auth.ts AuthenticationProvider "oxygenhub": sessions = {hub base URL, token}, stored in SecretStorage |
| 39 |
hub.ts HubClient: typed fetch over /api/v1 using hub-api's generated types (src/hubapi.d.ts, copied by `npm run types`) |
| 40 |
provider.ts the RemoteProvider registered with oxygen-vscode: matches a session's base URL, builds hub URLs |
| 41 |
proposals.ts TreeDataProvider: proposals by repository and bucket; detail webview; actions |
| 42 |
review.ts CommentController over oxy: content of the projected state, threads placed by atom, reply/resolve |
| 43 |
issues.ts TreeDataProvider: issues; create, comment, close |
| 44 |
checks.ts status bar: checks of the current bookmark's proposal; SSE subscription |
| 45 |
hubapi.d.ts generated from the hub (do not edit) |
| 46 |
``` |
| 47 |
|
| 48 |
Pure modules (`hub.ts` URL building and parsing, `provider.ts`) are tested with Node against a real hub started from the oxygenhub binary when present; the rest is exercised manually. |
| 49 |
|
| 50 |
## 4. Sign in |
| 51 |
|
| 52 |
`oxygenhub.signIn` asks for the hub URL (default: the first remote that looks like a hub, `https://…/owner/name` minus the last two segments) and a personal access token (Settings › Tokens on the hub; scopes `repo:read repo:write proposals:write issues:write`). The token is kept in `SecretStorage` under the base URL; sessions are exposed through `vscode.authentication` so oxygen-vscode or others can reuse them. `oxygenhub.signOut` forgets it. |
| 53 |
|
| 54 |
## 5. Proposals |
| 55 |
|
| 56 |
The **Oxygenhub: Proposals** view lists, per repository that has a hub remote, proposals in three groups: needing me (open, not mine, where I have not approved or where my approval is pending a seal), mine, and other open ones. Each row shows number, title, author, target, state chips (draft, conflicted, landable) and the check summary. Actions: open detail, open on hub, check out, review (comment / request changes / approve), seal approval, land, close. |
| 57 |
|
| 58 |
**Detail** is a webview: description, blockers, approvals (sealed or pending), checks, the changes list with signatures, and buttons for the actions. **Check out** fetches from the hub remote and sets a local bookmark `proposal/N` to the projected heads, then switches to it, so the files in the editor are the projected state; review threads then appear in place. |
| 59 |
|
| 60 |
### 5.1 Diff editors |
| 61 |
|
| 62 |
Each proposal row expands to the files it changes (`GET …/proposals/N/files`), with a diff icon per kind and `+added −removed`. Clicking a file opens VS Code's own diff editor; **View Changes** on the row (or in the detail) opens every file in one multi-file diff editor (`vscode.changes`). Both sides are read-only documents of the `oxygenhub-proposal` scheme, served from `GET …/proposals/N/content/{base|head}/{path}`: the target bookmark's state on the left, the projected state on the right, so a proposal can be read and reviewed without checking it out. A side where the file does not exist is empty; a rename shows its old path on the left. Open sides reload on refresh, since a proposal gains changes when its source bookmark moves. |
| 63 |
|
| 64 |
## 6. Review threads |
| 65 |
|
| 66 |
A `CommentController` for the checked-out proposal. Threads come from `GET …/proposals/N/comments`; each anchored comment is placed by asking oxy for the current line of its atom (`oxy blame --json` gives atoms per line; the extension finds the line whose `(hash, index)` matches). Replying posts a comment anchored to the same atom; a new thread on a line posts with the line's atom. Resolve toggles the hub's resolved flag. Threads whose atom is no longer live are shown in a separate "outdated" list in the view. |
| 67 |
|
| 68 |
In the diff editors (§5.1) the same controller places threads on the projected side only, at the line the hub reports for each anchored comment (the API's `line`, found by blame on the projected state), so no checkout or local `oxy` call is needed. A new thread or reply there posts the file and line; the hub anchors it to that line's atom. |
| 69 |
|
| 70 |
## 7. Approvals and landing |
| 71 |
|
| 72 |
**Approve** posts the review, then offers to run `oxy seal --proposal <url>` in the repository's terminal so the approval is backed by the user's seal; the row shows "pending seal" until the hub reports it sealed. **Land** runs `oxy proposal land <url>` in a terminal (the hub's own landing is offered when the hub reports it can land, for repositories without a policy). Both use the integrated terminal so the user sees exactly what runs with their key. |
| 73 |
|
| 74 |
## 8. Issues |
| 75 |
|
| 76 |
The **Oxygenhub: Issues** view lists open issues per repository (assigned to me first). Actions: open detail (webview with the timeline and a comment box), open on hub, create issue (title and body inputs), close, reopen, assign to me. |
| 77 |
|
| 78 |
## 9. Checks and status bar |
| 79 |
|
| 80 |
A status bar item shows, for the current repository's current bookmark, the open proposal whose source it is and the state of its checks (✔ n passed, ✘ failing, … running). It subscribes to the hub's proposal event stream and refreshes on `check` events; clicking opens the proposal. |
| 81 |
|
| 82 |
## 10. Configuration |
| 83 |
|
| 84 |
`oxygenhub.hubs`: known hub base URLs (also learnt from sign in). `oxygenhub.proposalBookmarkPrefix`: `proposal/`. `oxygenhub.autoRefresh`: seconds between view refreshes (60). |
| 85 |
|
| 86 |
## 11. Milestones |
| 87 |
|
| 88 |
|
| 89 |
|
| 90 |
| **0.1** | Sign in, hub client with generated types, remote provider (Open on Remote works), proposals view with detail and open-on-hub, issues view with create and comment | |
| 91 |
| **0.2** | Check out a proposal, review threads on atoms, reviews, seal and land through the terminal, checks in the status bar with live events | |
| 92 |
| **0.3** | Issues: labels, assignees, milestones; notifications count; create proposal from the current bookmark | |
| 93 |
| **1.0** | Marketplace listing beside oxygen-vscode, three-platform tests | |
| 94 |
|
| 95 |
## 12. Open questions |
| 96 |
|
| 97 |
1. Whether to render the proposal diff in a native diff editor (base vs projected content via an `oxyhub:` content provider) instead of the webview's file list. Likely yes in 0.2, since threads need real editors anyway. |
| 98 |
2. Token scopes: the extension could ask for a narrower token per action. Not for 1.0. |