Integrations
Connecting GitHub
Install the ProductOS GitHub App for Claude Code session orchestration + repo indexing, or use the lightweight Personal Access Token integration for one-shot issue imports.
ProductOS has two GitHub paths. Pick the one that matches what you need.
| Path | When to use | What it requires |
|---|---|---|
| GitHub App (recommended) | Send to Claude Code, repo indexing, propose-CLAUDE.md, PR-driven Claude session reconciliation, links from pull requests back to ProductOS | Install the ProductOS GitHub App on the repo / org |
| PAT-based provider | One-shot import of GitHub issues as ProductOS features | Personal Access Token with repo (classic) or Issues: read (fine-grained) |
You can run either independently. Most workspaces install the App; the PAT provider is the simpler surface.
GitHub App: install
- Settings → Integrations → ProductOS GitHub App → Connect GitHub. Admin or owner only.
- You're redirected to GitHub's app install flow. Pick:
- Account / org: install on your personal account or a GitHub org you admin.
- Repository access: All repositories or Only select repositories (recommended for orgs with many private repos).
- GitHub asks you to authorize the ProductOS GitHub Integration. ProductOS uses that one authorization to confirm your GitHub account can access the installation you just made, so nobody can connect an installation that isn't theirs. It revokes the token straight after that check and never stores it.
- GitHub redirects you back to Settings → Integrations. ProductOS runs the first crawl of the installed repos right away; Sync now on the installation re-runs it, and each repo has an Include in AI context switch.
What the App unlocks
- Send to Claude Code. From a feature's detail page, dispatch a GitHub Action that runs Claude Code in the linked repo. ProductOS provisions a session-bound MCP token; the session uses MCP tools (
get_feature,get_golden_thread,report_progress,attach_artifact,update_feature_status,mark_session_complete) to load context, post progress, attach the PR it opens, and close itself out. See Using ProductOS with Claude Code. - Repo indexing. Indexes every repo the installation can see: all of its pull requests, issues and commits, plus its file tree, symbols and docs (README, CLAUDE.md, AGENTS.md). Repos marked Include in AI context feed the Copilot and the Code page. See What gets indexed.
- Propose CLAUDE.md. A button on the Code page for a connected repo drafts a
CLAUDE.md(based on workspace knowledge) and opens it as a PR. - Pull request details on features. A linked pull request shows its status, lines added and removed, files, commits, review state, author and branch on the feature's Links tab. See Linked pull requests on a feature.
- Links back to ProductOS. Every pull request linked to a feature gets one ProductOS comment listing what it implements, and PRs that name a feature id link themselves. See Linking GitHub back to ProductOS.
Linking GitHub back to ProductOS
The comment on a linked pull request
When a pull request is linked to a feature, the ProductOS GitHub App posts one comment on it. It lists every feature linked to the PR with its id (a link to the feature), title, status and latest release:
ProductOS: this pull request is linked to
- WRK-000361 Collapsed sidebar shows each group's pages in a hover flyout · In Progress · v0.11.0There is only ever one. ProductOS edits it in place when another feature is linked, when a link is removed (with the last one gone it says the PR is no longer linked), and when a linked feature's title or status changes in the feature itself, through the API, MCP or the Copilot. A status changed by dragging a card on the roadmap shows up the next time the PR or its links change.
A PR is linked when someone adds it in a feature's Documents section, when a coding session records it (start_session or update_session with pr_url, or attach_artifact), or by the webhook (below). Sessions recorded from history (start_session with started_at) link the PR without commenting, so a backfill doesn't comment on every old PR at once.
| Private or internal repo | Public repo | |
|---|---|---|
| Feature id and link | Yes | Yes |
| Title, status, release | Yes | No |
Anyone can read a comment on a public repo, so it carries the id links only, and opening one still needs a ProductOS sign-in.
Each installation has a Comment on linked pull requests switch in Settings → Integrations → ProductOS GitHub App, on by default. Turning it off stops new comments and edits; comments already posted stay until you delete them on GitHub.
Linked pull requests on a feature
The Code list on a feature's Links tab shows each linked pull request with:
- its title and a status pill: Open, Draft, Merged or Closed
- lines added and removed, files changed, commits and comments
- the review decision (Approved or Changes Requested) while it is open, from each reviewer's latest review
- CI checks on its latest commit while it is open: how many passed, failed or are still running, with the failing checks' names on hover
- its author, head and base branch, and when it was last updated, merged or closed
ProductOS reads these from GitHub through the App when the tab opens and keeps them on the link: open and draft pull requests are read again after five minutes (one minute while checks are running), merged and closed ones after a day. The rows show what was last read straight away and fill in when the read returns. The refresh button on a row reads it again now. A pull request in a repo outside the App's install scope shows only its repo and number.
Pull requests that name a feature
When a pull request is opened, reopened or edited, the webhook reads its title, head branch and description for feature ids (your workspace's prefix, such as WRK-000361, or the original FEAT-000361) and ProductOS feature links, and links the PR to each matching feature in the workspace. Branch names count, so wrk-000361-sidebar-flyout links too. Ids inside HTML comments (PR template instructions) are ignored, and a description that names more than 10 ids is read as a list, so only the title and branch count. Removing an id later doesn't unlink the PR; remove the link from the feature's Documents section. A PR on a Claude Code session's branch is linked to the session's feature the same way.
Autolinks: every feature id becomes a link
GitHub autolink references turn text like WRK-000361 into a link wherever it appears in issues, pull requests, commit messages and release notes. ProductOS gives every sequence id a stable address for this, /go/<workspace-slug>/<id>, which opens the entity (a feature, theme, initiative, release and so on) for anyone signed in to that workspace. Someone signed out is sent to sign in and lands on the entity afterwards; someone from another workspace is told whose link it is.
To set it up, a repo admin opens the repo's Settings → Autolink references → Add autolink reference and copies the two values shown under Link feature ids in GitHub in Settings → Integrations → ProductOS GitHub App:
| Field | Value for a workspace with the slug acme and the prefix WRK |
|---|---|
| Reference prefix | WRK- |
| Target URL | https://productos.ca/go/acme/WRK-<num> |
Repeat it in each repo. If your workspace renamed its feature prefix, Settings also shows a row for the original FEAT- prefix so ids written before the rename still link. ProductOS doesn't create autolinks for you: GitHub only allows that with the repository administration permission, which the App doesn't ask for.
What gets indexed
| What | How much | Kept current by |
|---|---|---|
| Repos | Every repo the installation can see, with no cap | Each crawl re-lists them |
| Pull requests | All of them, open, closed and merged, with title, body, branches, author and dates | The first crawl reads the full history; later ones read only what changed since. Each pull_request event updates its PR at once |
| Issues | All of them (pull requests are stored once, as pull requests) | Same, and each issues event updates its issue |
| Commits | Every commit on the default branch | Same, and each push to the default branch adds its commits |
| File tree | Paths, sizes and languages, up to 5,000 per repo (contents are fetched on demand) | Every crawl and every push to the default branch |
| Docs | Root README, CLAUDE.md, AGENTS.md, CONTRIBUTING, LICENSE, SECURITY and docs/adr/* | Re-read only when the file changed |
| Symbols | Top-level functions, classes, types and components in TS and JS files | Re-extracted only for changed files, up to 200 per sync |
The GitHub App card lists each repo with how many pull requests, issues and commits it holds, and the MCP tool get_workspace_knowledge shows the same counts for every connected repository.
Large installations take more than one run. A crawl run stops after about four minutes, or when GitHub's hourly rate limit for the installation (5,000 requests) runs low, and saves its place. The card then shows how many repos are done and Sync now reads Resume. The crawl continues on the next Sync now, the next sync_repo_connection call, the installation's next GitHub event, or the daily pass, whichever comes first. A crawl paused for the rate limit waits for GitHub's reset time, which the card shows.
Webhooks keep the index current while they are delivered. Once a day (06:45 UTC) a pass also re-crawls every installation that hasn't been crawled in the last 20 hours, which catches anything a missed or failed webhook left out. A crawl after the first reads only what changed, so the pass costs a request or two per list per repo. To refresh sooner, Sync now on the installation runs the crawl again, and a connected MCP client can do the same with sync_repo_connection (owner or admin).
Webhook events the App handles
The webhook handler verifies X-Hub-Signature-256 against the App's webhook secret, then dispatches:
| Event | What ProductOS does |
|---|---|
installation | Install / uninstall lifecycle, starts a new crawl that re-lists the installation's repos |
installation_repositories | Repos added or removed from an install, starts a new crawl |
push | A push to the default branch stores the commits it carries, then re-syncs the repo after answering GitHub: what changed in its pull requests, issues and commits since the last pass, and the files, docs and symbols that changed. A push to any other branch changes nothing indexed |
issues | Stores the issue from the event, or removes it when it was deleted or transferred to another repo |
pull_request | Stores the pull request from the event, then: reconciles any Claude Code session on the PR's branch (running while open, succeeded on merge, cancelled if closed unmerged) and links the PR to the session's feature; links the PR to any feature its title, branch or description names; refreshes the PR's ProductOS comment; on merge, advances the session's feature from in-progress to testing and notifies the Lead and assignees of any feature the PR is attached to |
workflow_run | Moves a Claude Code session from queued to running when GitHub starts its run, and closes it from the run's conclusion when the run ends, so a run that fails or exits without a PR doesn't sit open. The run is matched by the session id in its title (workflow v7 and later); runs of older workflows match the newest open dispatch session in the same repo started up to ten minutes before the run. A run GitHub refuses at startup sends no event, so while a session is open, viewing it also looks its run up through the App, at most once a minute, and applies what the run shows the same way |
Every event also continues the installation's crawl if one is unfinished and not already running.
GitHub counts a delivery as failed when the answer takes longer than 10 seconds, and it doesn't redeliver failed deliveries on its own. So ProductOS answers with only what the event carries written, and does anything that needs GitHub (a re-sync after a push, a crawl, the PR comment, the merge notification) after answering. If writing the event fails, ProductOS answers with an error. The delivery then shows as failed under the App's Advanced → Recent Deliveries, where you can redeliver it. The failure also appears on the installation in Settings → Integrations and on the repo in sync_repo_connection, until the next crawl clears it. The daily pass picks up whatever the failed delivery would have changed.
PAT-based provider: install
For the lighter "just import some issues" use case:
- Settings → Integrations: find the GitHub card in the provider grid (separate from the ProductOS GitHub App card at the top) and click Connect.
- Paste a Personal Access Token. Classic:
repo(orpublic_repofor public-only). Fine-grained:Issues: readon the target repos. - Comma-separated list of
owner/nameslugs in the Repositories option. Include closed issues is on by default and Max pages per repo (default 3, 100 issues per page) caps each run.
What the sync does (one-way, GitHub → ProductOS):
- For each repo,
GET /repos/{owner}/{repo}/issues?state=all&per_page=100: pull requests are skipped (they appear alongside issues but are filtered). - Each issue → a ProductOS feature row. Dedup by
metadata.github.issue_id. - Issue state → feature status:
open → in-progress,closed (completed) → shipped,closed (not_planned) → wont-do,closed (other) → shipped. - Labels matching
priority/*,p0–p3, or plaincritical/high/medium/lowmap to feature priority.
This integration does not write back to GitHub.
Repo surface on /code
Once the App is installed and a repo is indexed, the Code page gets richer:
- Repo health card: open PRs, PRs merged this sprint, open and stale issues, commits this sprint, and when README / CLAUDE.md / AGENTS.md were last synced, in one tile.
- Cached file fetches: repeat views of a file revalidate against GitHub instead of re-downloading, so they don't burn your installation's API quota.
- Workspace-scoped search: one search box across indexed file paths, docs, issue titles and PR titles, so you can grep across every repo connected to the workspace without leaving ProductOS.
Disconnecting
- GitHub App: Disconnect on the installation removes it and its indexed repo metadata; webhooks for that installation are ignored afterwards. PR and session links already attached to features stay.
- PAT provider: Disconnect from the GitHub card in the provider grid. Historical imported features stay.
- From the GitHub side: uninstalling the App from your org/account settings stops the data flow immediately (ProductOS mints a fresh installation token for every request, so nothing keeps working after uninstall); remove the stale installation with Disconnect.
Troubleshooting
- "App not installed" on connect: finish the install flow on the GitHub side; the redirect sometimes happens before the install actually completes.
- "Your GitHub account can't access that installation": the GitHub account you authorized with isn't a member of the account or org the App was installed on. Switch to that account on GitHub and click Connect GitHub again.
- "GitHub authorization was cancelled": you declined the authorize prompt after installing. Nothing was connected; click Connect GitHub again and approve it.
- Claude Code dispatch fails: ProductOS refuses to dispatch when
productos-claude.ymlisn't on the default branch, the repo has noANTHROPIC_API_KEYsecret, or the repo's Actions policy would refuse the run, and says which. The key can be a repository secret (Settings → Secrets and variables → Actions → New repository secret) or an organization secret shared with the repo; on GitHub Free, organization secrets never reach a private repo. Checking for the secret needs the App's Secrets: read permission and checking the policy needs Administration: read (names and settings only); without them the dialog says it can't check. A v7 workflow run that still fails closes its session asfailedwith the reason; otherwise check the Action logs, and confirm Anthropic's Claude GitHub App is installed on the repo. - A session sat Queued, then failed with "GitHub couldn't start the run": GitHub ended the run before its first step, so nothing ran. The run page names the cause; usually it is an organization Actions policy that doesn't allow
anthropics/claude-code-action@*andoven-sh/setup-bun@*. Allow both, then Retry the session. - The run's PR ignores your repo's title or commit convention: from workflow v9 the run follows
CLAUDE.mdorAGENTS.mdfor commits, PR titles and descriptions, and titles the PR after the feature only when neither says how. An older workflow always uses the feature title, which a squash merge then uses as the commit subject. Open the update PR from the dialog and merge it, and write the convention intoCLAUDE.mdorAGENTS.mdif it isn't there. - The run ignores the model you picked: the dialog's Model reaches Claude Code only from workflow v8. An older workflow runs the default model, and the dialog and the dispatch response say so; open the update PR from the dialog and merge it.
- PR not linked to a Claude Code session: verify the PR's branch matches the session's branch. Sessions are matched by branch; features are also linked by an id in the PR's title, branch or description.
- No ProductOS comment on a linked PR: check the installation's Comment on linked pull requests switch, and that the repo is in the App's install scope. A status change alone never posts a first comment; linking the PR (or opening it) does.
- A linked PR's check count is lower than GitHub's: the App can't read check runs yet, so ProductOS counts each GitHub Actions workflow and commit statuses, and checks from other apps (Supabase, Vercel comments) are left out. Grant the App Checks: read in its GitHub settings and approve the change on each installation.
- A linked PR shows only its repo and number: the App can't see that repo. Add it to the installation's repo selection on GitHub, then press the row's refresh button.
- Repo not appearing in the picker: the App can't see repos outside its install scope. Update the repo selection in the App's GitHub Configure page.
Next
- Using ProductOS with Claude Code, the App's headline use case.
- MCP server: the tools the dispatched session calls back through.
- Golden Thread concept: what gets bundled into the Claude Code prompt.