This guide walks through setting up the Teamwork auto-installer — a GitHub App paired with a Cloudflare Worker that automatically pushes Teamwork framework files to every new repository you create.
For design rationale, see ADR-006.
- GitHub account with permission to create GitHub Apps
- Cloudflare account (free tier is sufficient)
- Node.js 18+ installed
- Wrangler CLI — install with
npm install -g wrangler - GitHub CLI (
gh) — install and authenticate withgh auth login
-
Fill in the following fields:
Field Value App name Choose a unique name (e.g., teamwork-installer-<your-username>)Homepage URL https://github.com/JoshLuedeman/teamworkWebhook URL https://example.com/webhook(placeholder — you'll update this in Step 5)Webhook secret Generate one now and save it: openssl rand -hex 32 -
Under Permissions, set:
- Repository permissions → Contents: Read & Write
- Repository permissions → Metadata: Read-only
-
Under Subscribe to events, check:
- Repositories
-
Under Where can this GitHub App be installed?, select:
- Only on this account
-
Click Create GitHub App.
- On the App settings page, scroll down to Private keys.
- Click Generate a private key.
- Save the downloaded
.pemfile securely — you'll need its contents in Step 6. - Note your App ID displayed at the top of the settings page.
- In your App settings, go to the Install App tab.
- Click Install next to your account.
- Choose All repositories (recommended — ensures new repos are automatically covered).
If you select specific repositories instead, the auto-installer will only work for those repos. New repos won't be covered unless you update the installation.
cd workers/github-app
npm install
wrangler login # if not already authenticated
wrangler deployNote the deployed URL in the output — it will look like:
https://teamwork-installer.<your-subdomain>.workers.dev
- Go back to your GitHub App settings page.
- Update the Webhook URL to:
Replace
https://teamwork-installer.<your-subdomain>.workers.dev/webhook<your-subdomain>with your actual Cloudflare Workers subdomain from Step 4. - Click Save changes.
Set the three required secrets using the Wrangler CLI. Each command will prompt you to enter the value:
# Your App ID (numeric, from the App settings page)
wrangler secret put GITHUB_APP_ID
# Your private key (paste the entire PEM file content, including -----BEGIN/END RSA PRIVATE KEY-----)
wrangler secret put GITHUB_APP_PRIVATE_KEY
# The webhook secret you generated in Step 1
wrangler secret put GITHUB_WEBHOOK_SECRETTip: For the private key, you can pipe the file directly:
cat path/to/your-app.private-key.pem | wrangler secret put GITHUB_APP_PRIVATE_KEY
- Create a new test repository on GitHub (e.g.,
test-teamwork-auto-install). - Wait up to 30 seconds for the webhook to fire and the Worker to process it.
- Check the repository — it should have Teamwork framework files committed:
.github/agents/,.github/skills/,docs/,Makefile, etc.MEMORY.md,CHANGELOG.md, and a starterREADME.md
- Verify the commit author shows as your GitHub App.
- Delete the test repository when done.
wrangler tailShows live output from console.log and console.error calls in the Worker.
- Go to your GitHub App settings → Advanced → Recent Deliveries.
- Each delivery shows the request payload, response status, and response body.
- Click Redeliver on any failed delivery to retry it.
Two mechanisms prevent auto-installation for specific repositories:
| Mechanism | How it works |
|---|---|
.teamwork-skip file |
Add a .teamwork-skip file to the repository. The Worker checks for this file before pushing framework files. Useful for template repos that include the marker, or to prevent re-installation on manual webhook redelivery. |
| Forked repositories | Forks are automatically skipped — they inherit conventions from their upstream repo. |
Note: Since most repos are empty at creation time, the
.teamwork-skipcheck is primarily useful for repos created from templates that include the marker file. To remove the framework after installation, delete the files and add.teamwork-skipto prevent future re-installation.
| Problem | Cause | Fix |
|---|---|---|
| Webhook not received | Webhook URL is incorrect or App is not installed | Verify the URL in App settings matches the Worker URL with /webhook path. Confirm the App is installed on your account. |
401 Invalid signature |
Webhook secret mismatch | Ensure the secret set via wrangler secret put GITHUB_WEBHOOK_SECRET matches the secret in your GitHub App settings exactly. |
500 Internal server error |
Worker runtime error | Run wrangler tail and redeliver the webhook to see the error. Common causes: malformed private key, incorrect App ID, GitHub API rate limit. |
| Permission denied (403) | App lacks required permissions | Check App settings → Permissions. Contents must be Read & Write, Metadata must be Read-only. |
| Files not appearing (empty repo) | Ref creation failed | Check wrangler tail logs. The Worker handles empty repos by creating the initial ref — verify the App has write access to the repo. |
| Files not appearing (non-empty repo) | Ref update failed | The Worker uses base_tree to preserve existing files. Check logs for tree/commit creation errors. Run teamwork install --force to repair manually. |
| Wrong framework version | Source ref is outdated | The Worker fetches files from main at runtime. Check wrangler.toml — the SOURCE_REF var controls which branch is used. Redeploy after changing it: wrangler deploy. |
| Secret | Purpose |
|---|---|
GITHUB_APP_ID |
GitHub App identifier, used as the iss claim in JWTs |
GITHUB_APP_PRIVATE_KEY |
RSA private key (PEM format) for signing JWTs |
GITHUB_WEBHOOK_SECRET |
Shared secret for HMAC-SHA256 webhook signature verification |
| Variable | Purpose | Default |
|---|---|---|
SOURCE_REPO_OWNER |
Owner of the Teamwork framework source repo | JoshLuedeman |
SOURCE_REPO_NAME |
Name of the source repo | teamwork |
SOURCE_REF |
Git ref to fetch framework files from | main |
To change the source (e.g., to test from a branch), edit wrangler.toml and run wrangler deploy.
- You create a new repository on GitHub.
- GitHub sends a
repository.createdwebhook to the Cloudflare Worker. - The Worker verifies the webhook signature (HMAC-SHA256).
- The Worker authenticates as the GitHub App (JWT → installation access token).
- The Worker checks skip conditions (fork,
.teamwork-skip). - The Worker fetches the latest framework files from
JoshLuedeman/teamworkvia the Git Trees API. - The Worker pushes all framework files + starter templates as a single atomic commit to the new repo.
All framework files are fetched at runtime from the source repo — no redeployment needed when framework files are updated.