Skip to main content

Forgejo

@shrug/forgejov2026.09.29.2· 1mo agoBEHAVIORS
01README

Drive Forgejo and Gitea instances from swamp over their shared /api/v1 REST surface, authenticated with a personal access token — a swamp node for a self-hosted git forge with read and confirm-gated write paths.

Every method persists a typed, CEL-referenceable snapshot. Per-repo snapshots are keyed owner__repo (single issues/PRs add __<index>):

data.latest("forgejo", "acme__infra").attributes.issues
data.latest("forgejo", "testuser__demo__12").attributes

Methods

Read: list_repos, get_repo, list_issues (pins type=issues, so pull requests are excluded; filter open/closed/all), get_issue, list_pulls, get_pull (populates additions/deletions/changed_files the list endpoint omits), list_releases, list_deploy_keys, list_orgs, list_org_repos, list_org_teams, list_collaborators, get_user, list_labels (excludes org-level labels), list_milestones.

Write (all confirm-gated): create_repo, create_org_repo, edit_repo, delete_repo, create_deploy_key, add_collaborator, remove_collaborator, add_org_team_member, create_issue (labels are numeric IDs; milestone is a numeric ID), edit_issue (milestone set / clear_milestone unset; assignees replace/clear), create_issue_comment, add_issue_labels, create_pull (open a PR head->base; optional labels/milestone/assignees), create_label, create_milestone, create_user (site-admin token).

Label names and milestone titles are not unique in Forgejo/Gitea, and the issue API expects label/milestone IDs — resolve IDs from a list_labels / list_milestones snapshot via CEL before creating/associating.

Security

  • token is a sensitive global argument — wire it from a vault at model-create time, never inline it.
  • The token is sent as an Authorization: token … header and is never logged.
  • Every mutating method is confirm-gated (confirm=true required) and every caller-supplied path segment is percent-encoded.

Quickstart

swamp vault put forgejo token           # hidden prompt
swamp model create @shrug/forgejo forgejo \
  --global-arg host=https://git.example.org \
  --global-arg token='${{ vault.get(forgejo, token) }}'

swamp model method run forgejo list_repos
swamp model method run forgejo list_issues --arg owner=acme --arg repo=infra

Known limitations

  • List methods expose page / limit but do not auto-paginate.
  • No rate-limit backoff: a 429 throws immediately.
  • No Projects API: Gitea 1.27.x exposes no /projects surface, so no project/board method ships.
  • Bare creates (create_deploy_key/create_label/create_milestone) are not idempotent — verify-first with the matching list_* (the caller's job).
  • create_pull opens PRs, but there is no merge_pull or reviewer-request path yet; no label/milestone edit/delete surface yet.
02Behaviors1
@shrug/forgejov2026.09.29.2forgejo.ts

Global Arguments

ArgumentTypeDescription
hoststringForgejo or Gitea instance URL (e.g. https://codeberg.org). No trailing slash.
tokenstringPersonal access token for the Forgejo/Gitea instance.
metadatarecord
fn list_repos()
List repositories owned by or accessible to the authenticated user.
fn get_repo(owner: string, repo: string)
Get details for a specific repository.
ArgumentTypeDescription
ownerstringRepository owner (user or org login).
repostringRepository name.
fn list_issues(state: enum)
List issues for a repository.
ArgumentTypeDescription
stateenumFilter by issue state.
fn get_issue(index: number)
Get a specific issue by number.
ArgumentTypeDescription
indexnumberIssue number.
fn list_pulls(state: enum)
List pull requests for a repository.
ArgumentTypeDescription
stateenumFilter by pull request state.
fn get_pull(index: number)
Get a specific pull request by number.
ArgumentTypeDescription
indexnumberPull request number.
fn list_releases()
List releases for a repository.
fn list_deploy_keys()
List deploy keys registered on a repository (verify-first before create).
fn create_deploy_key(title: string, key: string, read_only: boolean)
Register a deploy key on a repository. Defaults to read-only (least privilege).
ArgumentTypeDescription
titlestringHuman-readable label for the deploy key.
keystringPublic key material, e.g. 'ssh-ed25519 AAAA...'.
read_onlybooleanGrant read-only access (true, default) or read/write (false).
fn create_repo(name: string, description: string, private: boolean, auto_init: boolean, default_branch: string, confirm: boolean)
Create a repository owned by the authenticated user (POST /user/repos). Confirm-gated (a live mutation). Push existing history afterwards, or set auto_init to seed an initial commit.
ArgumentTypeDescription
namestringRepository name.
descriptionstringRepository description.
privatebooleanWhether the repository is private (default false — public, anonymously cloneable).
auto_initbooleanInitialize with an initial commit (README). Leave false to push an existing history.
default_branchstringDefault branch name.
confirmbooleanMust be true to create the repository — this is a live mutation.
fn create_org_repo(org: string, name: string, description: string, private: boolean, auto_init: boolean, default_branch: string, confirm: boolean)
Create a repository owned by an organization (POST /orgs/{org}/repos). Confirm-gated (a live mutation).
ArgumentTypeDescription
orgstringOrganization login that will own the repository.
namestringRepository name.
descriptionstringRepository description.
privatebooleanWhether the repository is private (default false).
auto_initbooleanInitialize with an initial commit (README). Leave false to push an existing history.
default_branchstringDefault branch name.
confirmbooleanMust be true to create the repository — this is a live mutation.
fn edit_repo(private?: boolean, description?: string, default_branch?: string, archived?: boolean, confirm: boolean)
Edit a repository's settings (PATCH /repos/{owner}/{repo}). Only provided fields are sent. Confirm-gated (a live mutation).
ArgumentTypeDescription
private?booleanSet the repository private (true) or public (false). Omit to leave unchanged.
description?stringNew description. Omit to leave unchanged.
default_branch?stringNew default branch. Omit to leave unchanged.
archived?booleanArchive (true) or unarchive (false) the repository. Omit to leave unchanged.
confirmbooleanMust be true to edit the repository — this is a live mutation.
fn delete_repo(confirm: boolean)
Delete a repository (DELETE /repos/{owner}/{repo}). Destructive and confirm-gated: the driver should get_repo first to verify the target (Rule 5). No snapshot is written.
ArgumentTypeDescription
confirmbooleanMust be true to delete the repository — this is a destructive live mutation.
fn list_orgs()
List organizations the authenticated user belongs to (GET /user/orgs).
fn list_org_repos(org: string)
List repositories owned by an organization (GET /orgs/{org}/repos).
ArgumentTypeDescription
orgstringOrganization login.
fn get_user(username: string)
Get a user account by login (GET /users/{username}).
ArgumentTypeDescription
usernamestringUser login.
fn list_collaborators()
List collaborators on a repository (GET /repos/{owner}/{repo}/collaborators). Verify-first before add.
fn add_collaborator(username: string, confirm: boolean)
Add or update a collaborator on a repository (PUT /repos/{owner}/{repo}/collaborators/{username}). Defaults to write permission (least privilege). Confirm-gated (a live mutation).
ArgumentTypeDescription
usernamestringUser to add as a collaborator.
confirmbooleanMust be true to add the collaborator — this is a live mutation.
fn remove_collaborator(username: string, confirm: boolean)
Remove a collaborator from a repository (DELETE /repos/{owner}/{repo}/collaborators/{username}). Confirm-gated (a live mutation). No snapshot is written.
ArgumentTypeDescription
usernamestringCollaborator to remove.
confirmbooleanMust be true to remove the collaborator — this is a live mutation.
fn list_org_teams(org: string)
List teams within an organization (GET /orgs/{org}/teams).
ArgumentTypeDescription
orgstringOrganization login.
fn add_org_team_member(team_id: number, username: string, confirm: boolean)
Add a user to a team (PUT /teams/{team_id}/members/{username}). Confirm-gated (a live mutation).
ArgumentTypeDescription
team_idnumberTeam ID.
usernamestringUser to add to the team.
confirmbooleanMust be true to add the team member — this is a live mutation.
fn create_issue(title: string, body: string, labels?: array, milestone?: number, assignees?: array, confirm: boolean)
Create an issue in a repository (POST /repos/{owner}/{repo}/issues). Confirm-gated (a live mutation).
ArgumentTypeDescription
titlestringIssue title.
bodystringIssue body (markdown).
labels?arrayLabel IDs to apply (Forgejo's issue API expects IDs, not names — resolve names to IDs from a list_labels snapshot). Omit to apply none.
milestone?numberMilestone ID to associate (resolve from a list_milestones snapshot). Omit for none.
assignees?arrayUsernames to assign. Omit to assign none.
confirmbooleanMust be true to create the issue — this is a live mutation.
fn edit_issue(index: number, title?: string, body?: string, state?: enum, milestone?: number, clear_milestone?: boolean, assignees?: array, confirm: boolean)
Edit an issue (PATCH /repos/{owner}/{repo}/issues/{index}). Only provided fields are sent; set state to open/closed to reopen/close. Confirm-gated (a live mutation).
ArgumentTypeDescription
indexnumberIssue number.
title?stringNew title. Omit to leave unchanged.
body?stringNew body. Omit to leave unchanged.
state?enumNew state (open/closed). Omit to leave unchanged.
milestone?numberSet the milestone to this ID. Omit to leave unchanged (use clear_milestone to unset).
clear_milestone?booleanUnset the issue's milestone (sends milestone=0). Mutually exclusive with milestone.
assignees?arrayReplace the issue's assignees with these usernames. Omit to leave unchanged; pass [] to clear all assignees.
confirmbooleanMust be true to edit the issue — this is a live mutation.
fn create_issue_comment(index: number, body: string, confirm: boolean)
Comment on an issue (POST /repos/{owner}/{repo}/issues/{index}/comments). Confirm-gated (a live mutation).
ArgumentTypeDescription
indexnumberIssue number to comment on.
bodystringComment body (markdown).
confirmbooleanMust be true to create the comment — this is a live mutation.
fn create_user(username: string, email: string, password: string, must_change_password: boolean, restricted: boolean, visibility: enum, confirm: boolean)
Create a normal user account (POST /admin/users). Requires the model's token to have SITE-ADMIN privileges; the created account is a normal (non-admin) user. Defaults to least privilege: must_change_password=true, restricted=false, visibility=private. Confirm-gated (a live mutation).
ArgumentTypeDescription
usernamestringLogin for the new account.
emailstringEmail address for the new account.
passwordstringInitial password for the new account. Sensitive — never logged.
must_change_passwordbooleanForce a password change on first sign-in (default true).
restrictedbooleanCreate the account as restricted (default false).
visibilityenumAccount visibility (default private — least privilege).
confirmbooleanMust be true to create the user — this is a live mutation.
fn list_labels()
List labels defined on a repository (GET /repos/{owner}/{repo}/labels). Verify-first before create_label. Excludes org-level labels (GET /orgs/{org}/labels), which org repos may also carry.
fn create_label(name: string, color: string, description: string, exclusive: boolean, is_archived: boolean, confirm: boolean)
Create a label on a repository (POST /repos/{owner}/{repo}/labels). Confirm-gated (a live mutation). A BARE create: it does NOT check for an existing same-named label — verify-first with list_labels. Gitea/Forgejo does NOT enforce unique label names, and list_labels returns only one page by default, so page through before deciding a name is absent or a duplicate may be created.
ArgumentTypeDescription
namestringLabel name.
colorstringLabel color as a 6-digit hex (leading # optional; normalized).
descriptionstringLabel description.
exclusivebooleanWhether the label is exclusive within its scoped group (default false).
is_archivedbooleanWhether the label is archived (default false).
confirmbooleanMust be true to create the label — this is a live mutation.
fn list_milestones(state: enum)
List milestones on a repository (GET /repos/{owner}/{repo}/milestones). Verify-first before create_milestone. Only one page is returned by default.
ArgumentTypeDescription
stateenumFilter by milestone state.
fn create_milestone(title: string, description: string, due_on?: string, state: enum, confirm: boolean)
Create a milestone on a repository (POST /repos/{owner}/{repo}/milestones). Confirm-gated (a live mutation). A BARE create: it does NOT check for an existing same-titled milestone — verify-first with list_milestones (titles are not unique; only one page is returned by default).
ArgumentTypeDescription
titlestringMilestone title.
descriptionstringMilestone description.
due_on?stringDue date as an ISO-8601 datetime (e.g. 2026-12-31T00:00:00Z). Omit for no deadline.
stateenumInitial milestone state (default open).
confirmbooleanMust be true to create the milestone — this is a live mutation.
fn add_issue_labels(index: number, labels: array, confirm: boolean)
Add labels to an existing issue (POST /repos/{owner}/{repo}/issues/{index}/labels). Appends to the issue's existing labels. Label IDs are resolved by the caller from a list_labels snapshot. Confirm-gated (a live mutation).
ArgumentTypeDescription
indexnumberIssue number to add labels to.
labelsarrayLabel IDs to add (resolve from a list_labels snapshot). Appended to the issue's existing labels.
confirmbooleanMust be true to add the labels — this is a live mutation.
fn create_pull(head: string, base: string, title: string, body: string, labels?: array, milestone?: number, assignees?: array, confirm: boolean)
Open a pull request (POST /repos/{owner}/{repo}/pulls). Confirm-gated (a live mutation). A BARE create — verify-first with list_pulls (state=open) for an existing head->base PR before calling; Forgejo also rejects a duplicate open head->base PR server-side (409/422), so this is not idempotent on its own. `base` is required; resolve label/milestone IDs from list_labels/list_milestones snapshots. Reviewers are set via a separate endpoint and are not supported here.
ArgumentTypeDescription
headstringSource branch, or '<user>:<branch>' for a fork's branch.
basestringTarget branch to merge into. Required — read the repo's default branch from a get_repo/list_repos snapshot if you want it.
titlestringPull request title.
bodystringPull request body (markdown).
labels?arrayLabel IDs to apply (resolve from a list_labels snapshot). Omit to apply none.
milestone?numberMilestone ID to associate (resolve from a list_milestones snapshot). Omit for none.
assignees?arrayUsernames to assign. Omit to assign none.
confirmbooleanMust be true to create the pull request — this is a live mutation.

Resources

repos(1h)— Repositories accessible to the authenticated user
repo(1h)— Details for a single repository
issues(30m)— Issues for a repository
issue(30m)— A single issue
pulls(30m)— Pull requests for a repository
pull(30m)— A single pull request
releases(1h)— Releases for a repository
deploy_keys(1h)— Deploy keys registered on a repository
deploy_key(1h)— A single deploy key created on a repository
orgs(1h)— Organizations the authenticated user belongs to
org_repos(1h)— Repositories owned by an organization
org_teams(1h)— Teams within an organization
collaborators(1h)— Collaborators on a repository
user(1h)— A single user account
collaborator(1h)— A synthesized collaborator membership record (the add endpoint returns no body)
team_member(1h)— A synthesized team membership record (the add endpoint returns no body)
issue_comment(30m)— A single comment created on an issue
labels(1h)— Labels defined on a repository
label(1h)— A single label created on a repository
milestones(1h)— Milestones defined on a repository
milestone(1h)— A single milestone created on a repository
issue_labels(30m)— The label set on an issue after an add-labels write
03Previous Versions4
2026.09.29.1
2026.09.28.1

Modified 1 behaviors

2026.07.17.1

Added 1, removed 1 behaviors

2026.04.13.1
04Stats
B
80 / 100
Downloads
40
Archive size
33.4 KB
  • Has README or module doc2/2earned
  • README has a code example1/1earned
  • README is substantive1/1earned
  • Most symbols documented1/1earned
  • No slow types (deprecated)1/1earned
  • Dependencies pass trust audit2/2earned
  • Has description1/1earned
  • Platform support declared (or universal)2/2earned
  • License1/2partial

    no SPDX license declared

  • Verified public repository0/2missing
05Platforms
06Labels