GitHub
Verified request, response and authorization contracts.
GitHub connections belong to the member who connects them. Every human workspace member can connect their GitHub account; other members and machine credentials cannot list, browse, or disconnect that connection. Several people can authorize the same GitHub App installation independently.
Connecting authorizes Melso on behalf of the GitHub user. The repository picker lists only repositories available to both that user and the App. Only me is the default: selected repositories go into a private My repositories Area. Only its owner can see its Tasks, files, and repository work. Its membership cannot be widened, and its existing Tasks cannot be moved into shared Areas.
To delegate a repository, select an Area or Whole company, or use Change where it's used. The sharer must have GitHub admin permission on that repository and permission to edit the Melso destination. This shares just that repository, not the connection or other repositories. Members of the destination can use the repository without connecting GitHub themselves. An existing company share can also be used in an Area. The member's GitHub permission is checked again when issuing agent credentials or performing live PR actions; removing a share, revoking the authorization, or disconnecting stops new credential issuance.
A coding Run's credentials cover its Task's repositories. Personal read-only access stays read-only; shared repositories receive the App's approved coding permissions. Tokens never receive Workflows or Administration access. The chat command VM gets read-only access to company repositories and repositories in Areas the member can open; when the member's Vault holds a GH_TOKEN or GITHUB_TOKEN, it uses that token instead. User OAuth credentials stay encrypted on the server and never reach a Run or browser.
Existing repositories explicitly linked to the company or an Area keep their sharing on upgrade. Existing connections become private to their original connector; reconnect to enable personal repository browsing. No other repositories from those installations are shared. Disconnect removes that member's connection and its repository grants; it never uninstalls the shared GitHub App.
Self-hosted deployments must configure MELSO_VCS_SECRET_KEY (base64, 32 bytes) before enabling personal connections. It encrypts the user and refresh tokens at rest; preserve it across restarts and include it in your secret backup/rotation plan.
Examples use the environment variables from Overview. UUID placeholders must be replaced with your own IDs.
GET /api/workspaces/{workspaceId}/github/installations
Auth: Workspace member with access to this resource.
Request: Path: workspace UUID.
Response: {installations:GitHubInstallationResponse[],can_manage:boolean,configured:boolean,repository_browse_configured:boolean,configuration_error:string}; only the current member’s connections are included. has_shared_repositories:boolean reports usable repositories without exposing other members’ connections. can_manage is true for human members and false for machine credentials.
Status: 200; 503 GitHub authorization unavailable. Authentication and resource-access errors follow Overview.
curl -sS -X GET "$MELSO_URL/api/workspaces/$WORKSPACE_ID/github/installations" \
-H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID"GET /api/workspaces/{workspaceId}/github/connect
Auth: Human workspace member; Run/MCP actors rejected.
Request: Optional query return_to:"github"|"repositories"|"chat", the page GitHub returns to. Optional mode:"install" opens GitHub's installation page to add another account instead of finding existing installations.
Response: {configured:boolean,url?:string,error?:string}. Open url in the member's browser; it expires with its one-use state after 10 minutes.
Status: 200; 400 invalid return target or mode; 403 human member required. Authentication and resource-access errors follow Overview.
curl -sS -X GET "$MELSO_URL/api/workspaces/$WORKSPACE_ID/github/connect" \
-H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID"GET /api/workspaces/{workspaceId}/github/connect/candidates
Auth: The human workspace member who authorized on GitHub.
Request: Query state:string, the github_choose value GitHub returned to the page.
Response: {candidates:{installation_id:integer,account_login:string,account_type:string,account_avatar_url?:string}[],return_to:string}. The user authorization proof stays on the server.
Status: 200; 400 invalid state; 403 human member required; 404 no pending choice. Authentication and resource-access errors follow Overview.
POST /api/workspaces/{workspaceId}/github/connect/complete
Auth: The human workspace member who authorized on GitHub.
Request: {state:string,installation_ids:integer[]}, installations from the pending choice.
Response: Empty.
Status: 204; 400 installation outside the choice; 403 access revoked; 404 no pending choice; 409 the choice expired or an installation changed. Authentication and resource-access errors follow Overview.
GET /api/workspaces/{workspaceId}/github/installations/{installationId}/repositories
Auth: The human member who owns the connection.
Request: Path: workspace and installation record UUIDs. Query page?:integer (default 1), per_page?:integer (default/max 100).
Response: {repositories:GitHubRepositoryResponse[],total_count:integer,next_page:integer|null}.
Status: 200; 403 reconnect required; 404 installation mismatch; 502 GitHub request failed; 503 GitHub unavailable. Authentication and resource-access errors follow Overview.
curl -sS -X GET "$MELSO_URL/api/workspaces/$WORKSPACE_ID/github/installations/$INSTALLATION_ID/repositories" \
-H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID"DELETE /api/workspaces/{workspaceId}/github/installations/{installationId}
Auth: The human member who owns the connection.
Request: Path: workspace and installation record IDs.
Removes only this member’s connection and its repository grants. Other members’ connections to the installation remain. The GitHub App stays installed. Mirrored PR history is retained but requires a current repository grant to read.
Response: Empty.
Status: 204; 404 no connection owned by this member matches the installation. Authentication and resource-access errors follow Overview.
curl -sS -X DELETE "$MELSO_URL/api/workspaces/$WORKSPACE_ID/github/installations/$INSTALLATION_ID" \
-H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID"POST /api/workspaces/{workspaceId}/github/personal-repositories
Auth: Human workspace member.
Request: {urls:string[]}; 1–100 GitHub repository URLs the member can access through their own connection.
Response: Empty. Creates or reuses the member's private My repositories Area and adds the repositories atomically. Repeating the request is safe.
Status: 204; 400 invalid input; 403 machine credential; 422 GitHub access could not be verified.
GET /api/tasks/{id}/pull-requests
Auth: Workspace member with access to this resource.
Request: Path: Task ID.
Response: {pull_requests:GitHubPullRequestResponse[]}.
Status: 200. Authentication and resource-access errors follow Overview.
curl -sS -X GET "$MELSO_URL/api/tasks/$ID/pull-requests" \
-H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID"GET /api/pull-requests/resolve
Auth: Workspace member with access to this resource.
Request: Query owner:string, repo:string, number:integer required.
Response: {id:UUID} for an authorized linked PR.
Status: 200; 400 missing/invalid query; 404 no accessible PR. Authentication and resource-access errors follow Overview.
curl -sS -X GET "$MELSO_URL/api/pull-requests/resolve?owner=example&repo=product&number=1" \
-H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID"GET /api/pull-requests/{id}
Auth: Workspace member with access to this resource.
Request: Path: PR record UUID.
Response: GitHubPullRequestDetailResponse.
Status: 200; 404 inaccessible PR. Authentication and resource-access errors follow Overview.
curl -sS -X GET "$MELSO_URL/api/pull-requests/$ID" \
-H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID"POST /api/pull-requests/{id}/merge
Auth: Workspace owner/admin (a person), or a workspace API key with admin scope. Run and MCP credentials are rejected, and tasks API keys get 403 workspace_key_scope; can_merge on the PR detail reports whether the caller may merge.
Request: merge_method?:"merge"|"squash"|"rebase", commit_title?:string, commit_message?:string.
Response: {merged:boolean,sha:string,pull_request:GitHubPullRequestResponse}.
Status: 200; 400 invalid method; 403 denied; 409 merge/check conflict; 502 GitHub failure. Authentication and resource-access errors follow Overview.
This action merges the PR. Use it only after review and authorization; closing keywords may also complete linked Tasks.
curl -sS -X POST "$MELSO_URL/api/pull-requests/$ID/merge" \
-H "Authorization: Bearer $MELSO_TOKEN" -H "X-Workspace-ID: $WORKSPACE_ID" \
-H "Content-Type: application/json" -d '{"merge_method":"squash"}'GitHubPullRequestDetailResponse
Source: server/internal/handler/github_pr_detail.go (GitHubPullRequestDetailResponse). Referenced nested objects retain their handler-defined fields; clients should tolerate additional fields.
| Field | JSON type |
|---|---|
body | string |
commits_count | integer |
checks | GitHubPullRequestCheckResponse[] |
preferred_merge_method | string |
allow_merge_commit | boolean |
allow_squash_merge | boolean |
allow_rebase_merge | boolean |
can_merge | boolean |
review_decision | string (may be omitted) |
review_task | GitHubPRReviewTaskResponse or null (may be omitted) |
GitHubInstallationResponse
Source: server/internal/handler/github.go (GitHubInstallationResponse). Referenced nested objects retain their handler-defined fields; clients should tolerate additional fields.
| Field | JSON type |
|---|---|
id | string |
workspace_id | string |
installation_id | integer or null (may be omitted) |
requires_reconnect | boolean |
account_login | string |
account_type | string |
account_avatar_url | string or null |
created_at | string |
GitHubPullRequestResponse
Source: server/internal/handler/github.go (GitHubPullRequestResponse). Referenced nested objects retain their handler-defined fields; clients should tolerate additional fields.
| Field | JSON type |
|---|---|
id | string |
provider | string |
workspace_id | string |
repo_owner | string |
repo_name | string |
number | integer |
title | string |
state | string |
html_url | string |
branch | string or null |
head_sha | string or null: the head commit Melso last mirrored for the pull request; null when unknown |
author_login | string or null |
author_avatar_url | string or null |
merged_at | string or null |
closed_at | string or null |
pr_created_at | string |
pr_updated_at | string |
mergeable_state | string or null |
mergeable | string or null |
merge_state_status | string or null |
snapshot_available | boolean or null (may be omitted) |
checks_rollup | string or null |
checks_conclusion | string or null |
checks_total | integer |
checks_passed | integer |
checks_failed | integer |
checks_running | integer |
checks_pending | integer |
failed_check_names | string[] |
snapshot_stale | boolean |
snapshot_fetched_at | string or null |
snapshot_head_sha | string or null: the head commit the stored CI and merge snapshot describes. It equals head_sha exactly when snapshot_available is true; another commit means the snapshot is for an older head, and its fields stay empty until one for the current head arrives. Null before the first snapshot and when snapshots are not configured. Always null for other providers, whose check counts describe head_sha |
additions | integer |
deletions | integer |
changed_files | integer |
GitHubRepositoryResponse
Source: server/internal/handler/github.go (GitHubRepositoryResponse). Referenced nested objects retain their handler-defined fields; clients should tolerate additional fields.
| Field | JSON type |
|---|---|
id | integer |
full_name | string |
html_url | string |
clone_url | string |
description | string or null |
private | boolean |
archived | boolean |
default_branch | string |
GitHubPullRequestDetailResponse also includes every GitHubPullRequestResponse field.