The e2e job on GitHub Actions runs the full end-to-end suite (init / push / pull / source / env / tags / roles / contribute / dashboard / uninstall …), matching the coverage that used to be checked by hand, one command at a time. This page explains the configuration the job needs before it will run on CI.
The e2e job runs on:
- a push to
master/main - any PR targeting
master/main - only when the repository variable
TEAMAI_TEST_REPO_URLis set; otherwise the job skips itself (a fork without the secrets skips cleanly, with no red CI)
Several PRs or pushes operating on the same fixture repo at once would corrupt its state, so the job runs under concurrency: e2e-fixture-repo: runs queue up and a run in progress is not cancelled, so it finishes and leaves a clean state behind.
PRs from forks run fork-e2e (no token; the remote cases skip). A test must never rebuild dist/ or reinstall the OpenCode binary: workers share both. Both jobs also install a pinned OpenCode 2 from npm (@opencode/cli) and point TEAMAI_OPENCODE_V2_BIN at it; to bump it, change OPENCODE2_VERSION and OPENCODE2_LINUX_X64_SHA256 together in the env block at the top of .github/workflows/ci.yml.
GitHub repo → Settings → Secrets and variables → Actions → Variables → New repository variable
| Name | Value | Notes |
|---|---|---|
TEAMAI_TEST_REPO_URL |
<owner>/<repo> |
The fixture repo the E2E suite works against (owner/repo or a full https URL) |
The maintainers of this repository pick the fixture repo. Any private or public repo dedicated to e2e will do. CI pushes, pulls and uninstalls against it over and over, so do not reuse a production repo. To switch fixture repos, change this variable; no code change is needed.
Settings → Secrets and variables → Actions → Secrets → New repository secret
| Name | Value |
|---|---|
TEAMAI_TEST_TOKEN |
A GitHub fine-grained personal access token with read/write access to the fixture repo |
- Sign in with an account that has admin or write access to the fixture repo.
- Open https://github.com/settings/personal-access-tokens/new
- Configure:
- Token name:
teamai-cli e2e fixture (CI) - Expiration: 90 days (renew before it expires)
- Repository access → Only select repositories → the fixture repo that
TEAMAI_TEST_REPO_URLpoints at - Permissions → Repository permissions:
Contents: Read and write (needed by push/pull)Pull requests: Read and write (the push flow opens a PR)Metadata: Read-only (default)
- Token name:
- Generate → copy the token (shown once) → paste it into the GitHub secret
⚠️ The token is a credential. It lives only in GitHub Secrets; never commit it to code or a.envfile.⚠️ GitHub emails a reminder before expiry. Renew the token then and update the secret.
The remote commands and init project scope describes in src/__tests__/e2e/e2e.test.ts (token required) cover:
| Command | What it checks |
|---|---|
members / members list / members add |
Listing members; confirming the add flow is gone |
status |
Runs without crashing |
pull --dry-run / pull --force |
Sync flow |
push --dry-run |
Push flow (nothing is actually pushed) |
tags / tags subscribe / tags unsubscribe |
Tag subscription round trip |
tags add / tags remove |
Admin tag operations round trip (on a real skill) |
source list |
Listing sources (also runs without a token) |
env add / env list / env remove |
Team env variable round trip |
stats / digest / recall |
Read-only analysis commands |
track --tool claude |
Hook event reporting |
contribute --dry-run --file ... |
Learning contribution dry run |
dashboard -p 37210 |
Spawns the web server, checks it with curl, kills it |
uninstall --dry-run / uninstall --force |
Uninstall preview, real uninstall, re-init recovery |
roles set + pull |
The skill set changes after switching role |
init <repo> --force (default workspace scope) |
Fresh init (sandbox cwd + isolated HOME) |
Without a token: --version / --help / tags --help / members --help / uninstall --help / source sanity checks, plus the source add → list → browse → pull/deploy → remove/cleanup lifecycle in source-project-scope-e2e.test.ts, which uses a real local Git repo. PRs from forks can run these.
Most cases use only local fixtures and need no token. While developing, run only the affected files; run the whole npm run test:e2e when you change the e2e runner, shared fixtures or test isolation (add --maxWorkers=2 on a small machine):
npm run test:e2e -- <test-file>The e2e setup file src/__tests__/helpers/isolate-e2e-env.ts gives each test file a temporary sandbox HOME (with its own git identity in .gitconfig), puts a teamai that runs this build's dist/ first on PATH, and deletes the whole sandbox when the file ends. So there is no need to export HOME yourself, and the run never touches your real ~/.teamai/ or ~/.gitconfig. The remote cases (src/__tests__/e2e/e2e.test.ts) clone the fixture repo into the sandbox HOME with the token and write ~/.teamai/config.yaml in beforeAll (prepareRemoteTeamHome); nothing needs preparing by hand.
# 1. Point at the fixture repo and token (fill in owner/repo; without them the remote cases skip)
export TEAMAI_TEST_PROVIDER=github
export TEAMAI_TEST_REPO_URL=<owner>/<repo>
export TEAMAI_TEST_TOKEN=ghp_xxxxx
export GITHUB_TOKEN=$TEAMAI_TEST_TOKEN
# 2. Run
npm run build
npx vitest run --config vitest.e2e.config.ts --reporter=verboseOn CI: check that the secret and variable names match exactly (case matters). A PR from a fork cannot read the secret and skips; that is expected.
The fine-grained token is missing a permission. Confirm Contents: read/write and Pull requests: read/write are both on and the right repository is selected.
Startup took longer than 10 seconds. Raise testTimeout in vitest.e2e.config.ts, or the i < 20 bound in the loop.
Normally the tests clean up after themselves with add/remove round trips. If a run crashed halfway and left residue: clone the fixture repo locally, git revert or reset by hand, and push. The tests' local clone lives in the sandbox HOME and is deleted with it, so it needs no cleanup.