Skip to content
← Public packages

@kody/github

Call GitHub REST, GraphQL, and pull requests with a GitHub OAuth App or a personal access token.

AGENTS.md

154 lines · 4.2 KB · Markdown

@kody/github — agent notes

Human setup and intent live in README.md. This file is for agents: imports, smoke/dryRun snippets, and edge cases. Secrets by name only — never paste token values. Do not disable live webhooks or jobs.

Secrets / integrations

LaneCredentialDefault name
OAuth AppSaved integrationgithub
PATUser secretgithubAccessToken

Pass integrationName (OAuth) or secretName (PAT). Extra OAuth identities: github-work, etc. account aliases integrationName. Retired alias bot throws with setup URLs.

Import paths

ExportImport
overviewkody:@kody/github
accountskody:@kody/github/accounts
get-viewerkody:@kody/github/get-viewer
graphqlkody:@kody/github/graphql
paginatekody:@kody/github/paginate
requestkody:@kody/github/request
typeskody:@kody/github/types
pr/get-infokody:@kody/github/pr/get-info
pr/get-checkskody:@kody/github/pr/get-checks
pr/mergekody:@kody/github/pr/merge
pr/set-review-statuskody:@kody/github/pr/set-review-status

Prefer static kody:@kody/github/... imports from execute. If you must invoke dynamically, pass bare kody id github (not @kody/github).

Smoke test (read-only)

OAuth (default integration github):

import getGithubViewer from 'kody:@kody/github/get-viewer'

export default async function main() {
	return await getGithubViewer()
	// or: getGithubViewer({ integrationName: 'github' })
}

PAT:

import getGithubViewer from 'kody:@kody/github/get-viewer'

export default async function main() {
	return await getGithubViewer({ secretName: 'githubAccessToken' })
}

dryRun / confirm (mutations)

import mergePr from 'kody:@kody/github/pr/merge'

export default async function main() {
	return await mergePr({
		owner: 'example-org',
		repo: 'example',
		prNumber: 1,
		mergeMethod: 'squash',
		dryRun: true,
	})
}
import githubRequest from 'kody:@kody/github/request'

export default async function main() {
	return await githubRequest({
		method: 'POST',
		path: '/repos/example-org/example/issues',
		body: { title: 'Example', body: 'Preview only' },
		dryRun: true,
	})
}
import setPrReviewStatus from 'kody:@kody/github/pr/set-review-status'

export default async function main() {
	return await setPrReviewStatus({
		owner: 'example-org',
		repo: 'example',
		prNumber: 1,
		status: 'ready',
		dryRun: true,
	})
}

Common reads

import githubRequest from 'kody:@kody/github/request'

export default async function main() {
	const response = await githubRequest({
		path: '/user/repos',
		query: { per_page: 5 },
		throwOnError: true,
	})
	return response.data
}
import getPrInfo from 'kody:@kody/github/pr/get-info'

export default async function main() {
	return await getPrInfo({
		owner: 'example-org',
		repo: 'example',
		prNumber: 1,
		integrationName: 'github-work',
	})
}

PR locators: { prUrl } or { owner, repo, prNumber } (number aliases prNumber).

Edge cases

  • On 401 / 403, helpers throw GitHubRequestError naming missing OAuth scopes (X-Accepted-OAuth-Scopes vs X-OAuth-Scopes) and the next setup step.
  • OAuth: reconnect at /connect/oauth?provider=<integrationName> after adding the missing scope on the GitHub OAuth App.
  • PAT: grant the missing permission, then update the secret.
  • Rate limit: 403 with X-RateLimit-Remaining: 0 — wait or batch with GraphQL.
  • Org-restricted OAuth App: request third-party access approval, or use a fine-grained PAT approved for that org.
  • redirect_uri must be exactly https://kody.codes/connect/oauth.
  • Token exchange in Lane B still needs the client secret even with PKCE.
  • Authenticated rate limit is typically 5,000 requests/hour per user.

Fork / adapt

  1. Fork into the caller's account (kody id stays github).
  2. Connect their OAuth App and/or save their PAT; approve GitHub hosts.
  3. Run ./get-viewer for the selected lane before treating the copy as ready.
  4. Keep ## Intent and community-icon.svg intact for community listing; do not hard-code personal account aliases.