# Doctor

**Package:** Laravel Compose | **Version:** 1 | **URL:** https://mozex.dev/docs/laravel-compose/v1/deploying/doctor

---

```bash
php artisan compose:doctor
php artisan compose:doctor --no-daemon   # skip everything that needs docker
```

The doctor is a preflight. Every check is something that broke a real deploy once. It exits 1 on any error and 0 otherwise; warnings are printed but don't fail it.

## Host checks

- The docker binary runs (the configured `docker.binary`, `docker` by default).
- The Compose plugin is installed and is 2.17 or newer. The redeploy needs `pull --ignore-buildable` (added in 2.15) and `up --wait-timeout` (2.17).
- The daemon answers. A `permission denied` becomes a hint naming the user and the `usermod -aG docker` command; anything else is printed as Docker reported it. With a remote host or context, the address reached is printed.

## Per-stack checks

- The compose file parses.
- A `Stack` class found in the directory can be autoloaded. When it can't, the stack silently runs class-less, and the warning names the class.
- `environment()` renders: valid keys, no line breaks, supported value types.
- Every `${VAR}` the compose file consumes without a default is a key of `environment()`. A stack with nothing to write (a class-less one) is checked against the env file already in its directory instead, the one a redeploy leaves alone. `${COMPOSE_PROJECT_NAME}` always counts as provided. A variable that only the shell provides (`${HOME}`, a CI secret) is a warning rather than an error: compose will resolve it on this machine, but the stack doesn't control it.
- `docker compose config` accepts the file with the environment the stack would write. The env is passed through a temporary file, so the stack directory isn't touched. A stack with nothing to write is checked with its own env file.
- No publish listens on every interface. Addresses given as `${BIND:-...}` are resolved through the stack's environment first (or the hand-written env file, for a stack with nothing to write), so a variable that resolves to `127.0.0.1` passes.
- For remote daemons, no bind mounts.
- For local daemons with a link directory, the link can be created or refreshed by this user. When it can't, the warning names the directory that needs `chown` and the user to give it to. A directory with content sitting at the link path gets its own warning, since the redeploy leaves it alone; so does one this user can't read.
- The env file would be ignored by git, when the stack lives in a repository.
- Disabled stacks and a disabled master switch are noted, so "why didn't it deploy" has an answer.

## In your test suite

The same checks are available as a report, which makes a good architecture test: it catches a compose file that consumes a renamed variable before the branch merges.

```php
use Mozex\Compose\Facades\Compose;

it('keeps every stack consistent with its compose file', function (): void {
    $report = Compose::validate(withDaemon: false);

    expect($report->isClean())->toBeTrue(implode("\n", $report->lines()));
});
```

`Report` exposes `errors()`, `warnings()`, `notes()`, `forStack($name)`, `isClean()`, `hasWarnings()`, and `lines()`, which is every error and warning as one string each for an assertion message. Each `Problem` has a `severity`, a `message`, and the `stack` it belongs to, or null for host-level findings.

---

## Table of Contents

- [Introduction](https://mozex.dev/docs/laravel-compose/v1)
- [AI Integration](https://mozex.dev/docs/laravel-compose/v1/ai-integration)
- [Support Us](https://mozex.dev/docs/laravel-compose/v1/support-us)
- [Requirements](https://mozex.dev/docs/laravel-compose/v1/requirements)
- [Changelog](https://mozex.dev/docs/laravel-compose/v1/changelog)
- [Contributing](https://mozex.dev/docs/laravel-compose/v1/contributing)
- [Questions & Issues](https://mozex.dev/docs/laravel-compose/v1/questions-and-issues)
- [About Mozex](https://mozex.dev/docs/laravel-compose/v1/about)
- [Installation](https://mozex.dev/docs/laravel-compose/v1/installation)
- [Configuration](https://mozex.dev/docs/laravel-compose/v1/configuration)

### Stacks

- [Defining a Stack](https://mozex.dev/docs/laravel-compose/v1/stacks/defining-a-stack)
- [Discovery](https://mozex.dev/docs/laravel-compose/v1/stacks/discovery)
- [Environment Files](https://mozex.dev/docs/laravel-compose/v1/stacks/environment-files)
- [Compose Files](https://mozex.dev/docs/laravel-compose/v1/stacks/compose-files)

### Deploying

- [Redeploy](https://mozex.dev/docs/laravel-compose/v1/deploying/redeploy)
- [Hosting Platforms](https://mozex.dev/docs/laravel-compose/v1/deploying/hosting-platforms)
- [Remote Daemons](https://mozex.dev/docs/laravel-compose/v1/deploying/remote-daemons)
- [Doctor](https://mozex.dev/docs/laravel-compose/v1/deploying/doctor)

### Operating

- [Status, Logs, and Down](https://mozex.dev/docs/laravel-compose/v1/operating/status-logs-down)
- [Health Check](https://mozex.dev/docs/laravel-compose/v1/operating/health-check)
- [Events](https://mozex.dev/docs/laravel-compose/v1/operating/events)
- [Testing](https://mozex.dev/docs/laravel-compose/v1/operating/testing)

### Recipes

- [Meilisearch](https://mozex.dev/docs/laravel-compose/v1/recipes/meilisearch)
- [Telegram Bot API](https://mozex.dev/docs/laravel-compose/v1/recipes/telegram-bot-api)