10 KiB
GitHub Features Plan (PRD-ish)
Goal: implement GitHub-powered workflows (PR panel + start sessions from Issue/PR) on top of the existing GitHub auth foundation.
Non-goals (for this phase)
- Rebuild auth/token storage (already implemented)
- Rebuild worktree lifecycle/cleanup (already implemented)
- Add hard context size caps/fallback logic (explicitly out of scope)
Existing Primitives (MUST reuse)
These already exist; do not reinvent.
GitHub auth + connected user
- UI:
packages/ui/src/components/sections/openchamber/GitHubSettings.tsx - Runtime API:
GitHubAPIinpackages/ui/src/lib/api/types.ts - Web endpoints:
packages/web/server/index.js(/api/github/*) - Desktop Tauri commands:
packages/desktop/src-tauri/src/commands/github.rs - VS Code bridge + storage:
packages/vscode/src/bridge.ts,packages/vscode/src/githubAuth.ts
Projects and directories
- Projects store (one project == one repo path):
packages/ui/src/stores/useProjectsStore.ts - Active project selection is already used across the app; use it to scope all GitHub operations.
Worktree sessions
- Worktree creation and session wiring:
packages/ui/src/lib/worktreeSessionCreator.ts- Reuse
createWorktreeSession()andcreateWorktreeSessionForBranch(projectDirectory, branchName).
- Worktree cleanup/delete behavior is already present in session deletion flow:
packages/ui/src/components/session/SessionDialogs.tsx
“Synthetic parts” / hidden context in chat
- SDK supports
TextPartInput.synthetic?: boolean:node_modules/@opencode-ai/sdk/dist/v2/gen/types.gen.d.ts
- UI filters synthetic parts out of rendering:
packages/ui/src/lib/messages/synthetic.ts
- Existing “seed new session from assistant answer” uses a hidden preface part:
packages/ui/src/stores/useSessionStore.ts(createSessionFromAssistantMessage)packages/ui/src/lib/opencode/client.ts(sendMessage({ prefaceText }))
Git tab layout
- Git view where PR panel will be inserted:
packages/ui/src/components/views/GitView.tsx
- Changes + Commit already exist; History is below.
Guiding Principles
- One directory/project == one git repo. All GitHub actions are scoped to the active project.
- Do not show synthetic context to the user; only show the human prompt.
- If the user lacks permission for an operation (merge, create branch, etc), degrade to “Open in GitHub”.
- Prefer server-side Octokit for web runtime; for desktop/vscode, implement equivalent runtime commands/bridge handlers.
- Keep UI consistent with existing patterns (provider OAuth, worktree sessions, commit message generation).
Feature A: Git Tab PR Panel (Create / Status / Merge)
Status: implemented.
Intent
While working on a feature branch, show PR status and actions inside the Git tab, without leaving the app.
Placement
Implemented between Commit and History in packages/ui/src/components/views/GitView.tsx.
Visibility Rules
- Show only if:
- repo is detected (
isGitRepo === true) - branch is not the “base branch”
- repo is detected (
Base branch source (reuse existing config):
activeProject.worktreeDefaults.baseBranchfrompackages/ui/src/stores/useProjectsStore.ts- fallback default:
main
UI States
- GitHub not connected
- Show CTA: “Connect GitHub” (link to Settings -> OpenChamber -> GitHub).
- Connected but repo not resolvable to GitHub
- Show “Open remote in browser” if remote URL exists.
- Show error text explaining remote must be GitHub.
- PR does not exist for current branch
- Show create form:
- base branch (default: baseBranch)
- title (default from branch name)
- draft toggle
- description textarea
- “Generate description” button (AI)
- “Create PR” button
- PR exists
- Show summary:
- state (draft/open/merged)
- PR number + title
- checks summary
- mergeability (if available)
- “Open in GitHub”
- If user has merge permission and PR is mergeable:
- merge method dropdown (merge/squash/rebase)
- “Merge” button
- If PR is draft:
- “Ready” button (mark ready for review)
- Merge disabled until ready
- If cannot merge:
- disable merge button + show “Open in GitHub”
AI “Generate description”
Implemented as a PR-specific generator (separate prompt/endpoint/command).
Inputs:
- base branch ref (prefers
origin/<base>when available) - head branch ref
- committed range diff:
git diff <base>...<head>(file list fromgit diff --name-only <base>...<head>)
Output:
title(<= 80 chars, no commit-style prefixes)body(GFM markdown sections: Summary/Testing/Notes)
Required GitHub API Calls
- Resolve repo from git remote URL (origin)
- Find PR by head branch
- Create PR
- Get PR details + checks
- Merge PR
- Mark PR ready for review (GraphQL)
Checks logic (implemented):
- prefer GitHub Actions check-runs (
/commits/{sha}/check-runs) - fallback to classic commit statuses (
/commits/{sha}/status)
Implementation Notes
- Web runtime should use server endpoints + Octokit (token stays server-side).
- Desktop/vscode should use their runtime handlers (similar to GitHub auth) to avoid exposing token.
Implemented code pointers
- UI section:
packages/ui/src/components/views/git/PullRequestSection.tsx - Web server endpoints:
GET /api/github/pr/statusPOST /api/github/pr/createPOST /api/github/pr/mergePOST /api/github/pr/ready
- PR description generator:
POST /api/git/pr-description- Desktop:
generate_pr_description - VS Code:
api:git/pr-description
Feature B: Start Session From GitHub Issue
Intent
Create a new session seeded with issue context, without polluting chat with large issue bodies/comments.
Entry Point
Session kebab menu in packages/ui/src/components/session/SessionSidebar.tsx.
Add new item:
- “New session from GitHub issue…”
Modal UI
Issue picker modal:
- list issues for current repo (open by default)
- search by title/number
- direct input:
- full URL
#123or123
- checkbox: “Create in worktree”
Worktree option
If enabled:
- create a worktree session (reuse
createWorktreeSessionForBranch) - branch naming convention:
issue-<number>-<slug>(slug derived from title)
- base branch:
activeProject.worktreeDefaults.baseBranch
If disabled:
- create normal session in project root directory.
Session Bootstrap (message)
Send a single user message with:
- Visible text part: concise prompt, e.g.
- “Review the issue, clarify requirements, propose plan, then implement.”
- Hidden synthetic parts: issue payload
- issue title/body
- labels, assignees, author
- comments (ordered)
- metadata (repo, number, url)
This must use SDK-supported TextPartInput.synthetic = true so it is not rendered.
Do not invent a new hidden-context mechanism.
Required GitHub API Calls
- List issues
- Get issue by number
- List issue comments
Feature C: Start Session From GitHub PR (with worktree checkout)
Intent
Create a session seeded with PR context, with optional worktree checkout of PR branch (including forks).
Entry Point
Session kebab menu in packages/ui/src/components/session/SessionSidebar.tsx.
Add new item:
- “New session from GitHub PR…”
Modal UI
PR picker modal:
- list open PRs
- search by title/number
- direct input:
- full URL
#123or123
- checkbox: “Create session in PR worktree”
Worktree behavior
If enabled:
- if PR is from same repo:
- fetch head branch
- create worktree from that branch (reuse
createWorktreeSessionForBranch)
- if PR is from fork:
- add temporary remote (derived from PR head repo clone URL)
- fetch
<head.ref> - create worktree
Fallbacks:
- if fetch/remote fails or permission denied:
- still create a normal session with PR context
- show toast with “Open in GitHub” action
Session Bootstrap (message)
Same synthetic-parts approach as Issues.
Hidden parts should include:
- PR title/body
- PR comments + review comments
- changed files list
- optionally full diff (explicitly no caps)
- checks/status summary
Visible prompt text should instruct:
- review PR intent
- identify risks
- propose changes
- optionally implement changes in checked-out branch/worktree
Required GitHub API Calls
- List PRs
- Get PR
- List issue comments for PR
- List review comments
- List files
- Get checks/status
Cross-cutting: “Synthetic Parts” Sending API
Current behavior:
opencodeClient.sendMessage()supportsprefaceTextwhich becomes a separateTextPartInput.- There is no first-class way (yet) to mark arbitrary parts as
synthetic: truefrom callsites.
Required change (shared for Features B/C):
- Extend
opencodeClient.sendMessage()(inpackages/ui/src/lib/opencode/client.ts) to support synthetic parts.
Recommended minimal API change:
- allow
prefaceTextSynthetic?: boolean(default true when used for hidden context) - allow
additionalParts?: Array<{ text: string; synthetic?: boolean; files?: ... }> - ensure generated
TextPartInputincludessyntheticwhen requested
This should reuse the existing filtering/rendering logic (no new UI hacks).
Cross-cutting: Repo Resolution
Need a single helper to map current project repo -> GitHub owner/repo.
Inputs:
- project directory root
- git remote URL (origin)
Behavior:
- support common GitHub URL formats:
git@github.com:OWNER/REPO.githttps://github.com/OWNER/REPO.githttps://github.com/OWNER/REPO
Output:
{ owner, repo }or null
Use this for all GitHub feature endpoints.
Cross-cutting: Permission / Fallback Rules
- Merge button enabled only if merge endpoint succeeds or mergeability indicates allowed.
- If not allowed:
- show “Open in GitHub” as primary action
- For PR worktrees from forks:
- if remote add/fetch fails => create normal session + “Open in GitHub”
Work Breakdown (Suggested Order)
Phase 1: Shared plumbing
- Repo resolution helper (remote URL -> owner/repo)
- New message sending helper supporting
synthetic: trueparts - GitHub endpoints/commands for issue + PR fetch (read-only)
Phase 2: Session bootstrap flows 4) Issue picker modal + session bootstrap 5) PR picker modal + session bootstrap 6) PR worktree checkout (fork support)
Phase 3: Git tab PR panel 7) PR detect/status in Git tab 8) Create PR from branch 9) AI generate PR description 10) Merge (with fallback)
Open Questions (for later)
- PR description generator prompt format: do we want the exact same “highlights” UI as commit gen, or a single-shot body generation?
- Worktree naming collision strategy for PR-based worktrees (owner/ref collisions) beyond current
sanitizeWorktreeSlug.