The CLI ships as a macOS binary today. The job needs a macOS runner (
runs-on: macos-latest) — an ubuntu-latest or windows-latest runner cannot install it.Why This Instead of an API Key
A long-lived API key sitting in a repository secret is the credential that actually leaks in practice: it outlives whoever created it, gets copied into forks, and nothing expires it. The CI lane replaces that with a token that:- is minted fresh for every workflow run and never stored anywhere,
- expires in 15 minutes,
- can edit existing components, tools, and content through push, but can’t add new ones with CLI 0.10.5, manage users, mint API keys, or change project settings — including the binding that grants this capability.
Bind a Repository to a Project
Tell Metabind which repository is allowed to obtain a CI token for a project. There’s no dedicated CLI verb for this yet, so set it through a project update:
Without a
ref, any branch pushed to the bound repository can obtain a CI token — a pull request from a fork does not receive a token, but any branch pushed within the repository does. Pin ref to your release branch if you don’t want that.
Example Workflow
permissions: id-token: writeat the job or workflow level. Without it,core.getIDToken()fails, and the failure reads as a missing function rather than a missing permission.- The exchange response is wrapped in
data— readdata.accessToken, not a top-levelaccessToken. --organd--projecton each CLI command. A runner has no saved context, so without thempushstops before sending a request.core.setSecret()masks the token in the job log. It expires in 15 minutes regardless, but there’s no reason to leave it unmasked.- Only edits to entities that already exist. A push that includes a file with no recorded id in
.metabind/state.jsonlists components first, and that read fails with403because the token lacksread:components. Add new files from a signed-in session. - A current
.metabind/state.jsonin the repository.pushdoesn’t update it and the CI token can’t runpull, so after the workflow pushes, runmetabind pullin a signed-in session and commit the refreshed state. Otherwise the next change to an entity the workflow already pushed is refused as a conflict. - No project settings changes. The token can’t write
metabind.jsonc,mcp-instructions.md, oragent/, so a push that includes one fails with403after writing the other changes. Push settings changes from a signed-in session.
metabind auth login, with MB_TOKEN unset so the CLI uses your login:
Diagnosing a Rejected Exchange
Every rejected exchange returns the same generic denial, on purpose — a more specific error would let a caller enumerate which repositories are bound to which projects. When an exchange is denied, check in order:What the Token Can Do
A push writes component source, so the token can change the code a release is built from. It can’t re-point the binding at a different repository even if the token itself leaks.
Preview Projects for Pull Requests
An ephemeral preview gives every pull request its own project to test against, without anyone having to remember to clean it up. The CI token can’t create or delete previews, because it only works against the project it was minted for, so run these commands signed in withmetabind auth login:
- The copy is shallow: current draft state only, no version history and no published packages.
- Every preview expires — there’s no option to create one that doesn’t. The default is 48 hours, up to a maximum of 7 days.
- Delete it explicitly when the pull request closes:
preview delete refuses to run against a project that isn’t marked as a preview, so a wrong id won’t take down a real project.
Next Steps
Flat-File Sync
Pull a project to disk, edit it, and push changes back.
Workflow Patterns
Build, publish, and roll back changes with the CLI.