Skip to content

GitHub.Repository reference

Source: src/GitHub/BranchProtection.ts

A GitHub branch protection rule.

BranchProtection manages the classic branch protection settings on a single branch: required status checks, required pull request reviews, push restrictions, admin enforcement, signed commits, linear history, and the force-push / deletion / lock toggles. Pair it with GitHub.Repository to protect the default branch of a repository provisioned in the same stack.

Branch protection is available on public repositories on every plan; private repositories require GitHub Pro, Team, or Enterprise. Push restrictions and dismissal restrictions are only available on organization-owned repositories.

Authentication is resolved via the GitHubCredentials service supplied by GitHub.providers() (env, stored PAT, gh CLI, or OAuth). The token needs repo scope and admin access to the repository.

Require Pull Request Reviews

yield* GitHub.BranchProtection("main", {
owner: "my-org",
repository: "my-repo",
branch: "main",
requiredPullRequestReviews: {
requiredApprovingReviewCount: 1,
dismissStaleReviews: true,
},
});

Require Status Checks and a Linear History

yield* GitHub.BranchProtection("main", {
owner: "my-org",
repository: "my-repo",
branch: "main",
requiredStatusChecks: {
strict: true,
checks: [{ context: "ci" }],
},
requiredLinearHistory: true,
requiredConversationResolution: true,
enforceAdmins: true,
});

BranchProtection: Protecting a Repository’s Default Branch

Section titled “BranchProtection: Protecting a Repository’s Default Branch”
import * as Output from "alchemy/Output";
const repo = yield* GitHub.Repository("repo", {
owner: "my-org",
name: "my-repo",
autoInit: true,
});
yield* GitHub.BranchProtection("main", {
owner: "my-org",
repository: Output.map(repo.fullName, (fullName) => fullName.split("/")[1]!),
branch: repo.defaultBranch,
requiredPullRequestReviews: { requiredApprovingReviewCount: 1 },
allowForcePushes: false,
allowDeletions: false,
});
yield* GitHub.BranchProtection("release", {
owner: "my-org",
repository: "my-repo",
branch: "release",
restrictions: { teams: ["release-managers"] },
blockCreations: true,
requiredSignatures: true,
});

Source: src/GitHub/Collaborator.ts

A GitHub repository collaborator.

Collaborator grants a user direct access to a repository. For organization-owned repositories, prefer GitHub.TeamAccess to grant access through teams instead of individual users.

Collaborators default to retain on removal — destroying the stack does NOT remove the collaborator, preventing accidental lockout. Opt in to actual removal by wrapping the resource in destroy() from alchemy/RemovalPolicy.

Authentication is resolved via the GitHubCredentials service supplied by GitHub.providers() (env, stored PAT, gh CLI, or OAuth). The token needs repo scope (and admin:repo for removal when opted in via destroy()).

Grant Push Access

yield* GitHub.Collaborator("collaborator", {
owner: "my-org",
repository: "my-repo",
username: "contributor",
permission: "push",
})

Grant Admin Access

yield* GitHub.Collaborator("admin", {
owner: "my-org",
repository: "my-repo",
username: "team-lead",
permission: "admin",
})

Grant Read-Only Access

yield* GitHub.Collaborator("readonly", {
owner: "my-org",
repository: "my-repo",
username: "auditor",
permission: "pull",
})
import { destroy } from "alchemy/RemovalPolicy"
yield* GitHub.Collaborator("temp", {
owner: "my-org",
repository: "my-repo",
username: "contractor",
permission: "push",
}).pipe(destroy())

Source: src/GitHub/Repository.ts

A GitHub repository.

Repository manages the lifecycle of a repository owned by a user or organization. The repository is created on first deploy and its settings are converged on every subsequent deploy.

Repositories default to retain on removal — destroying the stack does NOT delete the repository on GitHub, protecting its irreplaceable history (issues, pull requests, commits). Opt in to actual deletion by wrapping the resource (or the whole stack) in destroy() from alchemy/RemovalPolicy.

Authentication is resolved via the GitHubCredentials service supplied by GitHub.providers() (env, stored PAT, gh CLI, or OAuth). The token needs repo scope (and delete_repo when deletion is opted in via destroy()).

Basic Repository

const repo = yield* GitHub.Repository("api", {
owner: "my-org",
name: "api",
description: "API service",
autoInit: true,
});

Private Repository with Settings

const repo = yield* GitHub.Repository("internal-tools", {
owner: "my-org",
name: "internal-tools",
visibility: "private",
hasWiki: false,
hasProjects: false,
deleteBranchOnMerge: true,
});

Initialize from Templates

The autoInit, gitignoreTemplate, and licenseTemplate props seed the first commit. They are only honored at create time — changing them on a later deploy has no effect on an existing repository.

const repo = yield* GitHub.Repository("service", {
owner: "my-org",
name: "service",
autoInit: true,
gitignoreTemplate: "Node",
licenseTemplate: "mit",
});

Repository: Topics and Merge Configuration

Section titled “Repository: Topics and Merge Configuration”
const repo = yield* GitHub.Repository("sdk", {
owner: "my-org",
name: "sdk",
topics: ["typescript", "effect", "sdk"],
allowMergeCommit: false,
allowRebaseMerge: false,
allowSquashMerge: true,
allowAutoMerge: true,
});

Keep the same logical ID and change name to rename the live repository instead of replacing it — the repository’s history, issues, and pull requests are preserved. Only changing owner triggers a replacement.

// First deploy creates "api".
const repo = yield* GitHub.Repository("api", {
owner: "my-org",
name: "api",
});
// A later deploy with the SAME logical ID ("api") renames it to "gateway".
const repo = yield* GitHub.Repository("api", {
owner: "my-org",
name: "gateway",
});

Archiving sets the repository to read-only. Set archived back to false on a later deploy to un-archive it.

yield* GitHub.Repository("legacy", {
owner: "my-org",
name: "legacy-service",
archived: true,
});

The repository’s outputs can drive other GitHub resources so the whole repository configuration lives in one program.

Seed a Variable into the Repository

const repo = yield* GitHub.Repository("api", {
owner: "my-org",
name: "api",
autoInit: true,
});
yield* GitHub.Variable("region", {
owner: "my-org",
repository: repo.name!,
name: "AWS_REGION",
value: "us-east-1",
});

Store a Secret in the Repository

import * as Redacted from "effect/Redacted";
const repo = yield* GitHub.Repository("api", {
owner: "my-org",
name: "api",
autoInit: true,
});
yield* GitHub.Secret("deploy-token", {
owner: "my-org",
repository: repo.name!,
name: "DEPLOY_TOKEN",
value: Redacted.make("my-secret-value"),
});
import { destroy } from "alchemy/RemovalPolicy";
yield* GitHub.Repository("ephemeral", {
owner: "my-org",
name: "ephemeral-preview",
}).pipe(destroy());

Source: src/GitHub/Ruleset.ts

A GitHub repository ruleset.

Ruleset manages branch and tag protection rules at the repository level. Rulesets replace the legacy branch protection API with a more flexible system that can target multiple branches or tags with a single ruleset.

Rulesets default to retain on removal — destroying the stack does NOT delete the ruleset on GitHub, protecting production branches from accidental removal. Opt in to actual deletion by wrapping the resource in destroy() from alchemy/RemovalPolicy.

Authentication is resolved via the GitHubCredentials service supplied by GitHub.providers() (env, stored PAT, gh CLI, or OAuth). The token needs repo scope, or repository Administration write permission for a fine-grained token. Ruleset deletion does not require delete_repo.

Protect Main Branch

yield* GitHub.Ruleset("main-protection", {
owner: "my-org",
repository: "my-repo",
name: "main protection",
target: "branch",
conditions: {
include: ["refs/heads/main"],
},
rules: {
nonFastForward: true,
deletion: true,
requiredLinearHistory: true,
},
})

Require PR Reviews

yield* GitHub.Ruleset("pr-reviews", {
owner: "my-org",
repository: "my-repo",
name: "require reviews",
target: "branch",
conditions: {
include: ["refs/heads/main", "refs/heads/release/*"],
},
rules: {
pullRequest: {
requiredApprovingReviewCount: 2,
requireCodeOwnerReview: true,
dismissStaleReviewsOnPush: true,
requiredReviewThreadResolution: true,
},
},
})
yield* GitHub.Ruleset("ci-checks", {
owner: "my-org",
repository: "my-repo",
name: "CI required",
target: "branch",
conditions: {
include: ["refs/heads/main"],
},
rules: {
requiredStatusChecks: {
checks: [
{ context: "ci/test" },
{ context: "ci/lint" },
],
strictRequiredStatusChecksPolicy: true,
},
},
})
yield* GitHub.Ruleset("protected-with-bypass", {
owner: "my-org",
repository: "my-repo",
name: "protected with bypass",
target: "branch",
conditions: {
include: ["refs/heads/main"],
},
bypassActors: [
{ actorType: "RepositoryRole", actorId: 5 },
],
rules: {
nonFastForward: true,
},
})

Source: src/GitHub/TeamAccess.ts

A GitHub team repository access grant.

TeamAccess grants a team access to a repository within an organization. Teams provide a scalable way to manage repository permissions — add users to teams instead of granting individual collaborator access.

Team access grants default to retain on removal — destroying the stack does NOT remove the team’s access, preventing accidental lockout. Opt in to actual removal by wrapping the resource in destroy() from alchemy/RemovalPolicy.

Authentication is resolved via the GitHubCredentials service supplied by GitHub.providers() (env, stored PAT, gh CLI, or OAuth). The token needs repo scope and admin:org for managing team access.

Grant Push Access to a Team

yield* GitHub.TeamAccess("platform-access", {
owner: "my-org",
repository: "my-repo",
teamSlug: "platform",
permission: "push",
})

Grant Admin Access to a Team

yield* GitHub.TeamAccess("admin-access", {
owner: "my-org",
repository: "my-repo",
teamSlug: "admins",
permission: "admin",
})

Grant Read-Only Access

yield* GitHub.TeamAccess("readonly", {
owner: "my-org",
repository: "my-repo",
teamSlug: "contractors",
permission: "pull",
})
yield* GitHub.TeamAccess("platform-write", {
owner: "my-org",
repository: "api",
teamSlug: "platform",
permission: "push",
})
yield* GitHub.TeamAccess("security-read", {
owner: "my-org",
repository: "api",
teamSlug: "security",
permission: "pull",
})
import { destroy } from "alchemy/RemovalPolicy"
yield* GitHub.TeamAccess("temp", {
owner: "my-org",
repository: "my-repo",
teamSlug: "contractors",
permission: "push",
}).pipe(destroy())

Source: src/GitHub/WikiPage.ts

A GitHub wiki page.

WikiPage manages the lifecycle of a page in a repository’s wiki. Wiki pages are created on first deploy and updated in place on subsequent deploys when the content changes. By default, pages are never deleted to preserve documentation history — set allowDelete: true to opt in.

The repository’s wiki must be enabled (hasWiki: true on the Repository resource) and initialized by creating its first page in the GitHub web UI. Enabling the wiki or setting autoInit on the repository does not initialize the separate wiki Git repository. An inaccessible or uninitialized wiki produces WikiRepositoryUnavailable with setup instructions.

Git must be installed on the deployment machine. Pages are managed through the wiki’s Git repository, not the GitHub REST API. Each content or format change creates a commit; unchanged pages do not. Concurrent pushes are retried against a fresh checkout without force-pushing. Deletion removes the current page file, not its Git history. Authentication uses a transient process-environment header; tokens are not stored in clone URLs or Git config.

Authentication is resolved via the GitHubCredentials service supplied by GitHub.providers() (env, stored PAT, gh CLI, or OAuth). The token needs repo scope for private repositories or public_repo for public ones.

Basic Wiki Page

const home = yield* GitHub.WikiPage("home", {
owner: "my-org",
repository: "my-repo",
title: "Home",
content: "Welcome to the wiki!",
});

Formatted Wiki Page

yield* GitHub.WikiPage("getting-started", {
owner: "my-org",
repository: "my-repo",
title: "Getting Started",
content: `
# Getting Started
Install the package:
\`\`\`bash
npm install my-package
\`\`\`
`,
format: "markdown",
message: "Add getting started guide",
});

Deploy with the same logical ID and a different content to update the existing page in place rather than creating a new one.

yield* GitHub.WikiPage("api-docs", {
owner: "my-org",
repository: "my-repo",
title: "API Documentation",
content: "Updated API documentation content",
});
yield* GitHub.WikiPage("architecture", {
owner: "my-org",
repository: "my-repo",
title: "Architecture",
content: `
= System Architecture
== Overview
The system is built with...
`,
format: "asciidoc",
});
const temp = yield* GitHub.WikiPage("temp-page", {
owner: "my-org",
repository: "my-repo",
title: "Temporary Page",
content: "This page can be deleted",
allowDelete: true,
});

Deploy the repository first and create its first wiki page in the GitHub web UI before adding WikiPage to the stack.

import * as Output from "alchemy/Output";
const repo = yield* GitHub.Repository("docs", {
owner: "my-org",
name: "docs",
hasWiki: true,
autoInit: true,
});
yield* GitHub.WikiPage("home", {
owner: repo.owner!,
repository: Output.map(repo.fullName, (fullName) => fullName.split("/")[1]!),
title: "Home",
content: "Welcome to the documentation wiki!",
});