The CLI ships as a macOS binary today. The publish 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 only push file changes and publish a package from components that already exist. It cannot create or edit a component, manage users, mint API keys, or change project settings — including the binding that grants this whole capability.
Bind a Repository to a Project
Tell Metabind which repository is allowed to publish to 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 publish — 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. core.setSecret()masks the token in the job log. It expires in 15 minutes regardless, but there’s no reason to leave it unmasked.
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 a publish is denied, check in order:What the Token Can Do
Publishing a package is a release action over code that already exists; authoring a component is a write action over the code a release is built from. A token minted automatically for a third-party runner gets the first, never the second — and it can’t re-point the binding at a different repository even if the token itself leaks.
Preview Projects for Pull Requests
Pair the publish lane with an ephemeral preview so every pull request gets its own project to test against, without anyone having to remember to clean it up:- 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.