Documentation
CrateServing packages
Updated
Crate serves the repositories you register with it. The list lives in Crate's database, so adding or removing a package never needs a redeploy. Every change queues a Satis build, and the build writes Composer metadata and zip archives to your bucket.
Running Crate's commands
Crate's commands run wherever you type them. On Laravel Cloud, run them in your environment through Cloud's command runner, for example:
cloud command:run <environment-id> --cmd="php artisan crate:repos:list" -n
The examples below show only the php artisan ... part.
Register a repository
php artisan crate:repos:add vendor/package https://github.com/vendor/package.git
- The name must be a lowercase
vendor/package: letters, numbers, dots, underscores and hyphens. Crate lowercases what you type. - Use the package's real name from its
composer.json. The build asks Satis for that name from the repository you gave, so a different name builds nothing. --typesets the Satis repository type:vcs(the default),gitorpath.vcsis right for GitHub and other Git hosts.- Registering a name that already exists fails with
The repository [vendor/package] already exists.
On success Crate prints Added repository [vendor/package]. and queues a build for that package.
Private repositories and source tokens
Add --source-token=<token> when the repository is private:
php artisan crate:repos:add vendor/package https://github.com/vendor/package.git --source-token=<token>
Crate stores the token encrypted and uses it only during builds. For github.com it is passed to Composer as a GitHub OAuth token; for any other host it is sent as a bearer token. Use a read-only, narrowly scoped token you can revoke. For GitHub, a fine-grained token with read access to the repository's contents and metadata is enough.
Crate encrypts the token in its own database, but a token passed through cloud command:run stays visible in Laravel Cloud's command history. Rotate it after setup.
Crate keeps one token per host. If several repositories on the same host have different tokens, a build uses only one of them, so give every repository on a host a token that can read all of them, or store the token on one repository only.
crate:repos:list never prints tokens, and neither do Crate's API or MCP tools; they only say whether a repository has one.
List and remove
php artisan crate:repos:list
php artisan crate:repos:remove vendor/package
The list shows each repository's name, URL, type, status and the time it was last built. Removing a repository queues a full build, which also deletes that package's archives from your bucket.
Repository status
| Status | Meaning |
|---|---|
pending |
Registered, not built yet. |
building |
A build that includes it is running. |
active |
The last build that included it succeeded. |
failed |
The last build that included it failed. |
A full build covers every repository, so one failing repository marks all of them failed until the next successful build. Packages that were already built keep being served from the bucket in the meantime.
When builds run
- When you add a repository, or replace or clear its source token: a build of that one package.
- When you remove a repository: a full build.
- When you run
php artisan crate:build(full) orphp artisan crate:build vendor/package(one package). - Once a day, from the scheduler: a full build.
- When an agent asks for one through the
trigger_buildMCP tool. See Agents.
Pushing a new tag to a repository does not trigger a build. Run crate:build vendor/package when you want a release available before the daily rebuild.
Builds run one at a time on the queue. crate:build only queues the job and prints Dispatched Crate Satis build.; the result shows up in the repository status and the build history.
What a build produces
Crate generates the Satis configuration from the database on every build. It serves only the packages you registered, without their dependencies; your projects still resolve public dependencies from Packagist. Every branch and tag is archived as a zip, including development branches.
The output is written to the bucket under the satis prefix and served at /packages.json, /p2/... and /dist/... behind the credential check described in Credentials. Archive links point at your Crate, never at the bucket.
Each build record keeps the last 10,000 characters of the Satis output, with source tokens replaced by ***. Neither the HTTP endpoints nor the MCP tools return that output.
Managing repositories over HTTP
Signed-in users can also manage repositories through JSON endpoints that use the browser session (with Laravel's CSRF token on writes):
| Request | Who |
|---|---|
GET /crate/repositories |
Any active member |
POST /crate/repositories with name, url, optional type and source_credential |
Owners and Admins |
DELETE /crate/repositories/{name} |
Owners and Admins |
PUT /crate/repositories/{name}/source-credential with source_credential |
Any active member |
DELETE /crate/repositories/{name}/source-credential |
Any active member |
GET /crate/builds |
Any active member |
The Artisan commands have no way to change a token on an existing repository. Use the source-credential endpoints, or remove the repository and add it again with the new token.