GitHub Integration
Deep GitHub grounding — 7 agent tools for reading repos, plus OAuth connection, issue creation, and bidirectional status sync.
Overview
The GitHub integration does two jobs for Praxiom AI. First, it grounds the agent in your actual codebase — seven read-only tools let the agent inspect files, directory trees, commits, and open PRs before making a recommendation, so suggestions match what's really in main rather than hallucinated shape. Second, it pushes recommendations out as GitHub issues, with a back-channel sync that flips recommendation status to implemented when the issue closes.
Connecting
Initiate OAuth
Call POST /api/integrations/github/connect with workspace_id. The response returns { auth_url, state }. Redirect the user to auth_url. The server persists an OAuthState row with a 10-minute expiry.
{
"workspace_id": "your-workspace-uuid"
}Handle callback
GitHub redirects to GET /api/integrations/github/callback?code=...&state=.... The backend validates state against the DB row (one-time use, deletes on read), exchanges the code for an access token, fetches the authenticated user, encrypts the token with the workspace-level key, and upserts an Integration record with integration_type="github".
Config stored: github_user_id, github_username, github_avatar_url, selected_repos (initialized to []).
Select repositories
List accessible repos:
GET /api/integrations/github/repos?workspace_id={id}&search=...&page=1Save the user's picks:
POST /api/integrations/github/repos/select{
"workspace_id": "your-workspace-uuid",
"repos": ["org/repo-1", "org/repo-2"]
}Only selected repos are visible to the agent's read tools and are the only valid targets for create_github_issue.
GitHub connection is gated on the has_github feature flag. Tokens are encrypted at rest; if GitHub returns 401, the integration surfaces a GITHUB_TOKEN_ERROR and the user must reconnect.
Agent Tools (Read)
These seven tools are what make GitHub more than a push target — the agent uses them to ground recommendations in the real code. All seven are read-only and do not go through HITL approval.
| Tool | Args | Returns | Purpose |
|---|---|---|---|
read_repo_file | workspace_id, path, repo?, start_line?, end_line? | content, start_line, end_line, total_lines, total_bytes, truncated, sha | Read a file. Pass start_line/end_line (1-indexed, inclusive) to slice a range. Without a range, a default cap trims by lines then bytes (never mid-character — UTF-8 safe). |
list_repo_tree | workspace_id, repo?, path?, depth? | entries[], total_entries, truncated, depth | List files/dirs under path. depth is clamped to 1–5 (default 2). Echoes the clamped value so an agent asking for 99 sees it got 5. |
search_repo_code | workspace_id, query, repo?, path_filter?, max_results? | matches[] (path + snippet), total_matches, truncated | GitHub code search. Supports qualifiers like language:python. max_results clamped 1–50. Note: GitHub's search API is rate-limited to 30 req/min — use sparingly. |
list_recent_commits | workspace_id, repo?, limit?, path?, since? | commits[], total, limit | Recent commits. limit clamped 1–100 (default 20). path filters to commits touching that path; since accepts ISO 8601. |
list_open_pull_requests | workspace_id, repo?, state?, limit? | pull_requests[], total, state, limit | PRs in the repo. state enum: open (default), closed, all; invalid values return error_code: invalid_state. limit clamped 1–50. |
get_readme | workspace_id, repo? | content, path, total_lines, total_bytes, sha | Fetch the README. Agents call this on first contact to orient. |
get_package_manifest | workspace_id, repo? | detected, manifest_type, path, content, total_bytes, sha | Probes for package.json, pyproject.toml, requirements.txt, go.mod, Cargo.toml, Gemfile, composer.json in that order. Returns the first found, or detected: false with paths_probed. |
When the workspace has exactly one selected repo, repo can be omitted from any read tool — it's auto-resolved. With multiple selected repos, the tool returns a structured error asking the agent to pass repo explicitly.
Error shape
All seven tools translate GitHubServiceError into a structured payload the agent can reason over:
{
"success": false,
"error": "Repository 'org/missing' not found or access denied.",
"error_code": "not_found"
}
Common error_code values: not_found, forbidden, rate_limited (with retry_after), token_expired, too_large, unknown.
Agent Tools (Write)
| Tool | Args | HITL | Purpose |
|---|---|---|---|
create_github_issue | workspace_id, title, body, repo?, labels?, recommendation_id? | Yes (@gated) | Create an issue. If recommendation_id is provided, auto-populates title/body via build_issue_body() and creates a RecommendationGitHubLink for sync. |
list_github_issues | workspace_id, repo?, state?, limit? | No | List cached recommendation-linked issues. Filters: state enum all/open/closed; limit clamped 1–200. |
get_github_issue | workspace_id, repo, issue_number | No | Fetch one linked issue. If an OAuth token is present, syncs fresh state from GitHub and updates the cache before returning. |
create_github_issue is gated — calling it from the agent returns { status: "queued", pending_action_id }. The user approves the action from the pending-actions inbox; the executor then calls the __original__ handler with gating disabled.
Creating Issues (API)
Push a recommendation to GitHub as an issue:
POST /api/integrations/github/issues
{
"workspace_id": "your-workspace-uuid",
"recommendation_id": "rec-uuid",
"repo": "org/repo-name",
"title": "Improve onboarding flow",
"body": "Based on user research...",
"labels": ["enhancement", "priority:high"]
}
The endpoint validates the repo is in selected_repos (returns REPO_NOT_SELECTED otherwise), calls GitHubService.create_issue, and persists a RecommendationGitHubLink row with the issue number, URL, title, and state. The response includes the issue_url, issue_number, and the link_id used by sync.
Status Sync
POST /api/integrations/github/sync
{
"workspace_id": "your-workspace-uuid"
}
For each link in the workspace, the endpoint calls GET /repos/{repo}/issues/{n}, updates github_issue_state and last_synced_at on the link, and — if the issue has a linked PR — stores github_pr_url. When an issue transitions to closed, the linked Recommendation.status is flipped to implemented (unless it was already implemented or rejected).
Response:
{
"synced_count": 42,
"updated_count": 3
}
Sync is manual — there are no webhooks in the current cut. Call /sync on a cron or user action. Individual agent tools (get_github_issue) also opportunistically sync when the user inspects a single issue.
Management Endpoints
| Endpoint | Purpose |
|---|---|
GET /api/integrations/github/status?workspace_id={id} | connected, github_username, github_avatar_url, repos_count, selected_repos, last_synced_at |
GET /api/integrations/github/repos?workspace_id={id}&search=...&page=1 | List accessible repos (paginated, client-side search filter) |
POST /api/integrations/github/repos/select | Save selected_repos |
POST /api/integrations/github/issues | Create issue + link |
GET /api/integrations/github/links?workspace_id={id}&recommendation_id=... | List recommendation-issue links |
POST /api/integrations/github/sync | Bulk sync all links |
DELETE /api/integrations/github/disconnect | Removes all links + the Integration row |
Key Concepts
- Selected-repo firewall — the agent can only read and write to repos the user has explicitly picked. An unknown repo in any tool returns a typed error listing the available ones.
- Bidirectional traceability — every linked issue knows its source recommendation; every recommendation with a link knows its issue state. Close the loop from user evidence → recommendation → issue → merged PR.
- Truncation is visible — read tools always return
truncated: booland line/byte counts so the agent knows when it's only seen part of a file and can issue a follow-up slice. - Gated writes — only
create_github_issueis a write; it goes through the pending-actions queue so the user approves the title/body/labels/repo before anything hits GitHub.
What's Next
- Linear Integration — 9 agent tools for querying and updating tickets.
- Pending Actions — how HITL approval works for
create_github_issue. - Execution Tickets — bulk push workflow when you want to ship a whole document, not one recommendation.
Was this helpful?