Cross-repo writes — pushing branches and opening PRs in other OpenLyceum repos from
fleet-exec.yml / scripts/fleet-exec.sh
with --apply — need a token with write access to those repos.
The workflow's default GITHUB_TOKEN is scoped to Baton only, so it can clone public repos
(enough for dry-runs and the read-only fleet-health.yml
and compliance audits) but cannot push to or open PRs in the sim repos. For that, supply a
broader token.
fleet-exec --apply ─uses→ GH_TOKEN ─prefers→ secrets.FLEET_PAT ─else→ github.token (Baton-only, read)
You have two options. A fine-grained PAT is the quickest; a GitHub App is the more robust choice for ongoing org-wide automation (short-lived tokens, not tied to a person).
-
Create the token at GitHub → Settings → Developer settings → Fine-grained tokens → Generate new token (https://github.com/settings/personal-access-tokens).
-
Set:
- Resource owner:
OpenLyceum(not your personal account). - Repository access: All repositories, or Only select repositories and pick the sim
repos listed in
structure/repos.json. - Repository permissions:
- Contents → Read and write (clone + push branches)
- Pull requests → Read and write (open PRs)
- Metadata → Read-only (selected automatically)
- Workflows → Read and write only if a fleet change will edit files under
.github/workflows/in the target repos (GitHub rejects workflow edits otherwise).
- Expiration: pick a finite window (e.g. 90 days) and set a rotation reminder.
- Resource owner:
-
Add it as a Baton repository secret named
FLEET_PAT:gh secret set FLEET_PAT --repo OpenLyceum/Baton # paste the token when prompted
Or via the UI: Baton → Settings → Secrets and variables → Actions → New repository secret, name
FLEET_PAT.
That's it — fleet-exec.yml already reads secrets.FLEET_PAT. Org PAT policies must allow
fine-grained tokens (Org → Settings → Personal access tokens); an org admin may need to
approve the token before it works.
A GitHub App mints a short-lived installation token per run, isn't tied to anyone's account, and scopes cleanly to the installed repos.
-
Create the app: Org → Settings → Developer settings → GitHub Apps → New GitHub App.
- Permissions: Contents → Read and write; Pull requests → Read and write (+ Workflows → Read and write only if editing workflow files).
- No webhook needed.
-
Install the app on the OpenLyceum repos you want to target.
-
Generate a private key and store two secrets on Baton:
gh secret set FLEET_APP_ID --repo OpenLyceum/Baton # the app's numeric ID gh secret set FLEET_APP_PRIVATE_KEY --repo OpenLyceum/Baton < path/to/app-private-key.pem
-
Mint a token in the workflow and hand it to
fleet-execasGH_TOKEN. Add this step before "Run fleet-exec" infleet-exec.yml:- name: Mint installation token id: app-token uses: actions/create-github-app-token@v2 with: app-id: ${{ secrets.FLEET_APP_ID }} private-key: ${{ secrets.FLEET_APP_PRIVATE_KEY }} owner: OpenLyceum
then change the
GH_TOKENline to:GH_TOKEN: ${{ steps.app-token.outputs.token || secrets.FLEET_PAT || github.token }}
-
Preflight the token (read-only, no side effects). Run the Fleet Exec workflow with
check_authchecked to confirmFLEET_PATcan push to the targeted repos — it queries each repo's push permission via the API and opens nothing:gh workflow run fleet-exec.yml --repo OpenLyceum/Baton -f target=simulation -f check_auth=true # or a single repo: -f only=Resonance -f check_auth=true # locally: scripts/fleet-exec.sh --simulation --check-auth
A run reporting
Auth preflight as: <token owner>andN/N writableconfirms the secret works. -
Dry-run a real change (prints diffstats, opens nothing):
scripts/fleet-exec.sh --simulation -- npm pkg set dependencies.scenerystack=^3.1.0 -
Apply to one repo as a smoke test with
--only(or theonlyworkflow input), then re-run withapplyenabled. Verify one PR opens before scaling up.
Pushing changes to files under .github/workflows/ in Baton itself (e.g. editing
fleet-exec.yml) requires your local gh/git token to carry the workflow OAuth scope —
GitHub rejects the push otherwise (refusing to allow an OAuth App to … workflow … without workflow scope). Add it once:
gh auth refresh -h github.com -s workflowThis is separate from FLEET_PAT (which governs writes to the target sim repos); it only affects
pushing workflow edits to Baton from your machine.
- Prefer fine-grained tokens / App installs over classic PATs — grant only Contents and Pull requests, never admin.
fleet-execis dry-run by default;--apply(orapply=true) is the only thing that writes.- Add a
--labelso fleet PRs are easy to find, triage, and bulk-close if needed. - Rotate the PAT on its expiry; App tokens expire automatically each run.