# Versions and compatibility

pfcloud reads a site's code for the language versions it needs (PHP, Node.js, Python, Go, Ruby, Rust, Java, .NET, Elixir) and the framework versions it uses, and compares them with what the server has. An AI tool can use the same answer to fix problems before a deploy fails.

## When to use this
- Before the first deploy of a site: does the server fit the code?
- After a deploy fails with a version error ("requires php ^8.4", "engine node >=22").
- Before moving a site to another server.
- To pick the PHP version for a new site.

## Step 1: read what the server has
```bash
curl -s $MYFORGE/servers/SERVER_ID/runtimes -H "Authorization: Bearer $TOKEN"
```
The answer lists `php.installed`, `php.installable` (versions pfcloud can add), `php.offered_by_package_source`, and `tools` (node, npm, python, composer, go, ruby, rust, java, dotnet, elixir). `checked_at` says when it was read: daily, after installs, and when you ask:
```bash
curl -s -X POST $MYFORGE/servers/SERVER_ID/runtimes/check \
  -H "Authorization: Bearer $TOKEN" -H "Idempotency-Key: check-web1-1"
```
This is read-only. Wait a minute, then read again.

## Step 2: ask whether a site fits
```bash
curl -s $MYFORGE/sites/SITE_ID/compatibility -H "Authorization: Bearer $TOKEN"
```
| Field | Meaning |
| --- | --- |
| `status` | `ok`, `warning` (probably works), `problem` (a deploy would fail) or `unknown` (not read yet) |
| `items[]` | One per language the code pins: `runtime`, `needs` (for example `^8.4`), `server_has`, `state`, `message`, `details`, `fix` |
| `fix.action` | `switch_php` (a version already installed fits; `fix.version`), `install_php` (install `fix.version` first), `install_node` (managed servers), `install_language`, or `manual` |
| `suggested_php` | The PHP version to use, when the code pins one |
| `frameworks[]` | Framework names and versions found (Laravel 13.1.2, Next.js 16.0.0…) |
| `requirements_read_at` | When the code was last read (after each deploy) |

The code is read after each deploy, so a site that has never deployed has no answer yet. For a repository on GitHub you can see the same detection before creating the site: pick it in the New site form.

## Step 3: apply the fix
- `switch_php`: `PATCH /sites/SITE_ID` with `{"php_version":"8.4"}` (the site settings; see the Sites reference).
- `install_php`: `POST /servers/SERVER_ID/php/versions` with `{"version":"8.6"}` (Servers reference), then switch the site once it is installed.
- `manual`: needs a person.

## How it decides
- PHP: `composer.json`, `composer.lock` (every locked package's own requirement) and `.php-version`. Missing PHP extensions are reported when the server's modules are known.
- Node.js: `package.json` engines, `package-lock.json`, `.nvmrc`, `.node-version`. A package preferring a newer Node.js is a `warning`; the project's own pin is a `problem`.
- Other languages: `pyproject.toml`, `runtime.txt`, `go.mod`, `Gemfile`, `Cargo.toml`, `pom.xml`, `build.gradle`, `global.json`, `mix.exs`, `.tool-versions`.
- Docker sites are not checked: the image brings its own runtime.

> An AI assistant should read `status` and `fix` first, ask before installing anything on a server, and never install over an adopted server's runtimes: pfcloud answers `manual` there on purpose.
