GitHub.Repository reference
BranchProtection
Section titled “BranchProtection”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.
BranchProtection: Protecting a Branch
Section titled “BranchProtection: Protecting a Branch”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,});BranchProtection: Restricting Pushes
Section titled “BranchProtection: Restricting Pushes”yield* GitHub.BranchProtection("release", { owner: "my-org", repository: "my-repo", branch: "release", restrictions: { teams: ["release-managers"] }, blockCreations: true, requiredSignatures: true,});Collaborator
Section titled “Collaborator”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()).
Collaborator: Adding a Collaborator
Section titled “Collaborator: Adding a Collaborator”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",})Collaborator: Removing a Collaborator
Section titled “Collaborator: Removing a Collaborator”import { destroy } from "alchemy/RemovalPolicy"
yield* GitHub.Collaborator("temp", { owner: "my-org", repository: "my-repo", username: "contractor", permission: "push",}).pipe(destroy())Repository
Section titled “Repository”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()).
Repository: Creating a Repository
Section titled “Repository: Creating a Repository”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,});Repository: Renaming a Repository
Section titled “Repository: Renaming a Repository”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",});Repository: Archiving a Repository
Section titled “Repository: Archiving a Repository”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,});Repository: Wiring with Other Resources
Section titled “Repository: Wiring with Other Resources”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"),});Repository: Deleting a Repository
Section titled “Repository: Deleting a Repository”import { destroy } from "alchemy/RemovalPolicy";
yield* GitHub.Repository("ephemeral", { owner: "my-org", name: "ephemeral-preview",}).pipe(destroy());Ruleset
Section titled “Ruleset”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.
Ruleset: Creating a Ruleset
Section titled “Ruleset: Creating a Ruleset”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, }, },})Ruleset: Status Checks
Section titled “Ruleset: Status Checks”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, }, },})Ruleset: Bypass Actors
Section titled “Ruleset: Bypass Actors”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, },})TeamAccess
Section titled “TeamAccess”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.
TeamAccess: Granting Team Access
Section titled “TeamAccess: Granting 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",})TeamAccess: Multiple Teams
Section titled “TeamAccess: Multiple Teams”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",})TeamAccess: Removing Team Access
Section titled “TeamAccess: Removing Team Access”import { destroy } from "alchemy/RemovalPolicy"
yield* GitHub.TeamAccess("temp", { owner: "my-org", repository: "my-repo", teamSlug: "contractors", permission: "push",}).pipe(destroy())WikiPage
Section titled “WikiPage”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.
WikiPage: Creating Wiki Pages
Section titled “WikiPage: Creating Wiki Pages”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",});WikiPage: Updating Wiki Pages
Section titled “WikiPage: Updating Wiki Pages”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",});WikiPage: Alternative Formats
Section titled “WikiPage: Alternative Formats”yield* GitHub.WikiPage("architecture", { owner: "my-org", repository: "my-repo", title: "Architecture", content: ` = System Architecture
== Overview
The system is built with... `, format: "asciidoc",});WikiPage: Deleting Wiki Pages
Section titled “WikiPage: Deleting Wiki Pages”const temp = yield* GitHub.WikiPage("temp-page", { owner: "my-org", repository: "my-repo", title: "Temporary Page", content: "This page can be deleted", allowDelete: true,});WikiPage: Wiring with Other Resources
Section titled “WikiPage: Wiring with Other Resources”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!",});