Assemble the whole project
$ grim install --dry-run
You have a directory with a grim.json in it and not much else: a project cloned from its repository, which carries grim.json and grim.lock and leaves core, modules and themes to be fetched, or one whose grim.json you edited by hand. grim install makes the directory match the file. On a fresh clone that means everything, from fetching core to a running stack with an admin account.
grim create-project ends by running it for you. To add one package to a project that is already installed, grim require is the shorter road. To move an installed project to a newer core, the command is grim update; install never does that.
Usage
$ grim install --dry-run # resolve and report, touch nothing
$ grim install # the whole thing
$ grim install --no-composer # files and lock only, no build, nothing started
$ grim install --dry-run --strict # for CI: exit 1 on modules nobody asked forRun it anywhere inside the project; it walks up to the nearest grim.json. You must be logged in with grim auth:login, and Docker must be running unless you pass --no-docker or --dry-run.
Arguments and options
Install modules and themes from grim.json
Usage
grim install [--dry-run] [--strict] [--no-composer] [--force-composer] [--no-docker] [--no-enable] [--allow-unpublished-theme ALLOW-UNPUBLISHED-THEME]Options
| Option | Description |
|---|---|
--dry-run |
Resolve and report what would be installed, without touching the project |
--strict |
With --dry-run: exit 1 when the closure contains modules grim.json does not require |
--no-composer |
Skip composer install |
--force-composer |
Run composer install even when vendor/ already matches composer.lock |
--no-docker |
Skip Docker file generation |
--no-enable |
Skip enabling modules (generate modules-available.php only) |
--allow-unpublished-theme=ALLOW-UNPUBLISHED-THEME |
Resolve the named theme slug from resources/themes/<type>/<slug>/theme.json without contacting GitHub. Used by create-project --new-theme when the publish pipeline could not push the new theme (missing git identity, no GitHub permissions, etc.). |
What it actually does
Each step is printed with its duration, and the first failure stops the run.
- Resolves core. The
coreconstraint ingrim.jsonbecomes a grim-core tag. In a directory withoutcomposer.jsonandconfig/the core tree is fetched, at the versiongrim.lockrecords when there is a lock, and the step readsInstalling grim-core. Where they exist it readsResolving grim-coreand core on disk is left alone. - Checks package availability. Every module and theme in
grim.jsonis looked up before anything is cloned. The same check runs again on the full closure after step 3. - Resolves dependencies. The
requiresofgrim.json, then therequiresof everymodule.jsonthey lead to, each to the versiongrim.lockrecords. A module the lock does not know yet gets the newest tag its constraint allows on the project's train. - Installs modules. One git checkout per module under
src/<Module>/. - Installs themes. Every theme of every slot, into
resources/themes/<type>/<name>. The first of a slot is the active one. - Generates configuration. The module lists, the Docker files and
.env, each under the conditions in the table below. An emptyAPP_KEYis filled in, and shared secrets from the registry are written into.env. - Writes
grim.lock. Train, core version and commit, every module with version, commit andrequires, every theme. - Creates the local database. Only when a MySQL on your machine answers to
rootwithout a password. The name isDB_DATABASEfrom.env, reduced to lowercase letters, digits and underscores. - Builds and starts. Builds the image, runs
composer installin a one-off container unlessvendor/already matchescomposer.lock, makes sure the local Traefik is up, starts the stack and waits for theappcontainer. Thenyarn installand a Vite build on your machine, whenyarnis there. - Migrates, generates translations, creates an admin.
php artisan migrate --force,lang:jsandusers:admin, all in theappcontainer.
The closing table shows project, core, the number of modules and themes and, when the account was created, the admin email admin@<project domain> with a generated password. With --no-composer, steps 9 and 10 do not run at all.
The admin password is printed once and cannot be shown again. Copy it before you clear the terminal. grim user makes a new account if it is lost.
Reading the dry run
--dry-run needs no Docker and writes nothing. It prints a table of every module the install would land, with its version and a why column: grim.json, or the modules that require it. Then the themes with (active) on the first of each slot, the core constraint as written, and a total.
Between the table and the themes sits the part worth reading when you take over a project.
Resolved but not in grim.json:
`payments` required by `cart`Each line is a module the project would get without having asked for it. That is normal for a dependency. It becomes a finding when the app uses the module directly: then it belongs in grim.json. With --strict a non-empty section ends the run with exit code 1 and --strict: 1 module(s) resolved that grim.json does not require.
What it generates, and when
| Files | Written |
|---|---|
grim.lock, config/modules-available.php |
On every run. |
docker-compose.yml, .dockerignore, and in docker/: Dockerfile.dev, Dockerfile.production, nginx-dev.conf, .env.docker.example |
Only when docker-compose.yml or docker/Dockerfile.dev is missing. Never with --no-docker. |
docker/nginx-production.conf, docker/php-override.ini |
Overwritten on every run without --no-docker. |
.env, storage/config/modules-enabled.php |
Only when missing. .env is a copy of docker/.env.docker.example; the enabled list is a copy of the available one. |
An installed project keeps its compose file and Dockerfiles through any number of installs. Bringing those up to date is the job of grim upgrade.
Pitfalls
Install does not move an installed core
Core 2.4.2 is installed but 2.5.0 satisfies "~2.4" — run `grim update` to move onto it. is a notice, not an error. Once core is on disk, install records the version the lock already had and changes nothing under it. Run grim update --dry-run when you want the move.
The lock wins over a newer tag
Install reproduces, it does not move. Core, modules and themes land at the versions in grim.lock, so a fresh clone matches what your colleagues committed even when newer tags exist. Only a unit the lock has never seen is resolved fresh, and then within the train the lock names. Newer versions are the business of grim update.
A constraint in grim.json that you tightened by hand can exclude the locked version. Install then stops with No version of module 'cart' satisfies constraint '~2.5' and lists the locked version as the only one available. Run grim update, which rewrites the lock.
One unavailable package stops everything
1 package cannot be installed:
webhooks is archived — it is part of core since 2.5; remove it from grim.json
Nothing was installed. Fix grim.json (or request access) and run the command again.There is no partial install. The message names the remedy for each package: remove it from grim.json, or ask for access to a private one.
Shared secrets replace values you set yourself
A key that exists both in .env and in the registry gets the registry's value on every install. Keep project-specific values under names the registry does not use. When the registry cannot be reached the step is skipped without a word; -v prints the reason.
A missing PHP extension is only a warning
⚠ php extension "soap" is missing — required by invoices does not fail the run. The check reads php.extensions from the installed modules and compares it with php -m in the app container, or on your machine when the container is not up. Add the extension to the image before you use those modules.
After it finishes
The stack is already up; grim up adds the Vite dev server. When grim.json no longer requires modules that are still in src/, install lists them and offers to delete them, which is grim prune run for you. Then commit the lock.
$ grim up
$ git add grim.lockQuestions
Do I run install after every git pull?
When grim.json or grim.lock changed, yes: install lands the modules and themes the new lock records. It does not move a core that is already on disk. When the lock names a newer core or train, run grim update instead.
Why did install not enable my new module?
modules-enabled.php is copied from the available list only when it does not exist. On an installed project, grim require enables what it adds; after a hand edit of grim.json, add the provider line yourself.
Related spells
grim require
Summon a module or theme
Add a module or theme to grim.json, install it with everything it depends on, and rewrite grim.lock, all inside the train the project is on.
grim remove
Banish a module
Drop a module from grim.json and delete it from src/ together with every installed module nothing requires any more.
grim prune
Clear what nothing asks for
Delete the modules under src/ that can no longer be reached from the requires in grim.json.
grim update
Board the newest train
Move core, every module and every theme onto the newest release train grim.json allows, or a single module within the train it is on.
grim up
Raise the stack
Start the project's containers and its Vite dev server, with a trusted certificate and a working address, and say where to open it.
grim create-project
Conjure a project
Create a project directory with a grim.json on the current train and install it, or write the grim.json for an application that already runs.
Recipes that use it
Onboard as a collaborator
Get access to the packages, log grim in, clone the project, install what its lock records, bring the stack up and run the suite once.
Bring an existing app onto grim
Convert the instance into a grim.json without installing, read the dry run, settle the modules nobody asked for, point the copied .env at this machine, install, move your own files in, then test and commit.