Catalog PyPI
PACKAGE EXPLORERView in registry

addteam

PyPI

One-command collaborator management for GitHub repos with GitOps support.

accessautomationcollaboratorsgithubgitopsteam
Versions collected1
Direct dependencies7From release 1.6.0
Last observed20 Oct, 19:24 UTC

README

Version 1.6.0 documentation

addteam

Invite GitHub collaborators from a simple YAML file.

Install

pip install addteam

Or run without installing:

uvx addteam

Prerequisite: GitHub CLI must be installed and authenticated (gh auth login).

First Run

# In your repo directory, create a team.yaml
addteam --init

# Edit team.yaml with your team members, then run:
addteam

That's it! Your collaborators will be invited.

Bootstrapping From an Existing Repo

Already have collaborators on a repo and want a team.yaml that matches?

addteam --init --from-current

Groups current collaborators by permission into role buckets (admins, maintainers, developers, triagers, readers), lists pending invitations under the right bucket with a # pending invite comment (expired invites are commented out — uncomment to re-invite), and sets welcome_issue: false. Review and edit before committing — --sync run immediately after is a no-op since the file already matches current state.


team.yaml Format

default_permission: push

admins:
  - alice

developers:
  - bob
  - username: charlie
    name: Charlie Day      # optional display name

reviewers:
  - eve

name: is optional anywhere a username: is given — it shows up in audit/apply output, --json, and addresses welcome issues by name.

Role names map to permissions automatically:

RolePermission
adminsadmin
maintainersmaintain
developers, contributors, contractorspush
reviewers, readerspull
triagerstriage

Unknown keys produce a warning (not silent drops), so a typo like develoeprs: won't quietly shrink your team.

Note: maintain and triage only exist on organization-owned repos. On personal repos addteam automatically degrades to push/pull with a warning (never expands access), so one config works everywhere.

Common Commands

addteam                    # invite from local team.yaml
addteam -n                 # dry-run (preview only)
addteam -a                 # audit (show drift)
addteam -s                 # sync (also removes unlisted users, asks first)
addteam --from org/config  # use team.yaml from another repo
addteam accept             # accept invitations sent to you (see "Accepting Invitations")

Apply mode also fixes permission drift: if a collaborator exists with the wrong permission, it is updated to match team.yaml.

Accepting Invitations

If you're on the receiving end of invitations from repos that use addteam:

addteam accept                  # list + accept all your pending invitations
addteam accept --from myorg     # only from a specific org/owner
addteam accept -n               # preview only

Expired invitations (GitHub auto-expires after 7 days) are listed but can't be accepted — ask whoever invited you to re-run addteam.

Note: because accept is now a command, a local team.yaml literally named accept must be passed as addteam -f accept instead of positionally.

Central Team Config

Keep one team.yaml in a shared repo, apply it anywhere:

# Anyone on your team can run this in any repo:
uvx addteam --from myorg/team-config

(addteam myorg/team-config without --from still works and means the same thing; --from is the explicit, less ambiguous spelling. Confusing it with -r owner/repo — which selects the target repo — is a common mistake.)

Apply only one group (e.g. just the leads) to a specific repo:

uvx addteam --from myorg/team-config --group maintainers -r myorg/the-repo

The AI summary at the end is perfect for sharing via email or Slack.

Options

FlagDescription
-n, --dry-runPreview without making changes
-s, --syncRemove collaborators not in list
--max-removals NWith --sync: abort/prompt if removals exceed N or a majority (default: 3)
--allow-mass-removalWith --sync: allow exceeding --max-removals/majority
-a, --auditShow drift without making changes
--fail-on-driftWith --audit: exit 1 when drift is found (CI gates)
--sync-teamsWith --sync: also remove extra members from mapping-form teams:
-r, --repoTarget a specific repo
--fromFetch team.yaml from another repo
--from-currentWith --init: snapshot current collaborators (and pending invites) into team.yaml
--group ROLEOnly apply these role groups (repeatable; never with --sync or --sync-teams)
--org NAMEReport access across every repo in an org
--repos PATHReport access across an explicit owner/repo list, one per line
--include-forksWith --org: include forked repos in the report
--jsonMachine-readable output for audit/apply
--json-out PATHWrite the run payload to PATH (apply/audit/dry-run only)
-y, --yesSkip confirmation prompts (sync removals)
-q, --quietMinimal output
--welcome / --no-welcomeTurn welcome issues on/off for this run (default: off)
--no-aiSkip AI-generated summaries
--report DIRPermission matrix for every repo in a directory
--csv PATHWith --report: also write a spreadsheet
--format long/matrixWith --report --csv: row-per-user or grid layout
--no-namesWith --report: skip display-name lookups (faster)

Exit codes: 0 success · 1 runtime error (or drift with --fail-on-drift) · 2 usage error.

Access Reports

Audit permissions across a whole directory, GitHub org, or explicit repo list:

addteam --report ~/dev                       # local git checkouts
addteam --org myorg                          # every repo in an org (forks skipped)
addteam --org myorg --include-forks
addteam --repos repos.txt                    # explicit owner/repo list, one per line
addteam --report ~/dev --csv access.csv --format matrix

All three sources support --csv, --format long|matrix, --no-names, and --json. --org/--repos reports also carry visibility and fork per row; archived repos are included and flagged. Mutually exclusive with each other.

Scripting

addteam --audit --json | jq '.drift'
addteam --audit --fail-on-drift   # CI gate: fail the job on drift

GitOps Setup

Automatically sync collaborators when team.yaml changes:

addteam --init --init-action

This creates:

  • team.yaml - your team config
  • .github/workflows/sync-collaborators.yml - runs on push

Add a TEAM_SYNC_TOKEN secret (PAT with repo scope) to your repo.

Advanced Features

Expiring Access

contractors:
  - username: temp-dev
    permission: push
    expires: 2027-06-01

Expired users are skipped on apply and removed on --sync.

GitHub itself auto-expires a pending invitation after 7 days if the invitee never accepts. addteam detects this (separately from the expires: date above) and automatically re-sends the invite on the next apply. --audit shows pending (Nd) for a live invite's age, or expired once GitHub has timed it out.

GitHub Teams (orgs)

teams:
  - myorg/backend-team
  - myorg/frontend-team: pull
  - myorg/platform-team:
      permission: push
      members:
        - alice
        - bob
      maintainers:
        - carol

The scalar forms (bare string, or team: permission) only use the team's current members to derive repo access, same as always. The mapping form additionally manages the team's own membership on GitHub: addteam ensures members/maintainers have the right role (--audit reports drift; addteam -s --sync-teams removes anyone extra, subject to the same --max-removals/--allow-mass-removal circuit breaker, computed per team). Requires org-admin or team-maintainer rights; skipped on personal repos.

If a team lookup fails, the affected members are skipped with a warning and --sync refuses to run — a partial config must never cause mass removals.

Sync Safety (circuit breaker)

--sync removes anyone not listed in team.yaml. A misconfigured file (or an API blip) could otherwise strip a whole repo's access at once. By default, addteam refuses to remove more than 3 people, or a majority (>50%) of current collaborators (when at least 2 would go), in one run:

addteam -s                      # blocked if it would remove too many
addteam -s --max-removals 10    # raise the limit
addteam -s --allow-mass-removal # explicitly allow a large removal
addteam -s -n                   # --dry-run always reports whether it would trip

A single removal never trips the breaker — normal confirmation rules apply. Interactive runs get a loud warning and an explicit confirm instead of a hard abort.

Users removed because their authored expires: date has passed do not count toward the breaker — they are explicit, authored intent, not unlisted drift — and are still removed under the normal confirmation rules even when the breaker blocks unlisted removals.

Machine-Readable Run Output

addteam --sync --yes --json-out run.json   # write a report file (in addition to normal output)

The payload mirrors --json (independent of it) and includes a run metadata block (version, UTC timestamp, actor, repo, mode) plus, for sync runs, a circuit_breaker block with the trip decision. The --init-action / --init-multi-repo GitHub Action scaffolds use it to upload a run artifact and post a step summary; PRs touching team.yaml get a dry-run plan comment.

Multi-Repo Management

addteam --init-multi-repo

Creates repos.txt to sync the same team across multiple repos.

Welcome Issues

addteam can create a welcome issue for each new collaborator, with an AI-generated summary of your repo (requires OPENAI_API_KEY, ANTHROPIC_API_KEY, GOOGLE_API_KEY, or OPENROUTER_API_KEY).

Welcome issues are off by default. Turn them on per run with --welcome, or per repo in config:

welcome_issue: true

--no-welcome always forces them off, even if config sets welcome_issue: true.

License

MIT

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Versions 1

Collected releases
VersionPublishedDirect dependenciesOpen version
1.6.06 Sept 20267

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Repository

PENDING
michaeljabbour/addteam

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 19:24 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:0e6e5669003ae08768fe23f036182b54b28f11b8fd97174fc336c25e5e1c239e