levelrail-cli import), the HTTP API (POST /api/v1/imports/plan) and the MCP server (plan_import).
A plan is a preview only. Deploying it uses the existing create, build and compose endpoints; there is no separate deploy path.
What you can paste
Classification is automatic. The web UI shows a “Looks like” hint while you type, and the server’s decision is final.
Repository detection
For a repo URL the plan reads a small, fixed set of files over HTTPS from the host’s raw-file endpoint (GitHub, GitLab including subgroups, Bitbucket, Gitea and similar). Nothing is cloned to disk and nothing from the repo is executed. Private repos cannot be read this way; connect them through a git provider first. Detection order:- A compose file (
docker-compose.yml,docker-compose.yaml,compose.yaml,compose.yml) whose services are all prebuilt images is planned as a compose deploy. A compose file that builds from source falls through to the next step with a warning. - A root
Dockerfileis planned as a Dockerfile build. The port comes fromEXPOSE. - Manifest files (
package.json,go.mod,requirements.txt,pyproject.toml,Pipfile,pom.xml,build.gradle,index.html) pick a Railpack build or a static site, with framework defaults for the port and a health check path guess (Next.js, Nuxt, NestJS, Express, Django, FastAPI, Flask, Spring and others). - If nothing matches and the repo is on a public host, Railpack’s own provider detection is tried.
Outbound requests use the same SSRF guard as webhooks: loopback, private and link-local addresses are refused unless
APP_NOTIFY_ALLOW_PRIVATE_NETWORKS=true. Only http and https repo URLs are accepted.
Environment variables
For repos the plan scans.env.example, .env.sample, .env.template, env.example, .env.dist, compose environment: sections and Dockerfile ENV. Each variable is reported as:
- required: the value is empty or a placeholder such as
changeme,your_..._here,<...>or${VAR}. Deploy is blocked until it has a value. - has default: a real-looking default exists.
- secret: the name contains
SECRET,TOKEN,PASSWORD,KEYand similar, or the value is a URL with credentials.
-e NAME=value in a docker run command that looks secret is treated as required so you re-enter it.
Docker run flags
Supported:-p/--publish (host and container ports, optional IP and protocol), -e/--env, -v/--volume (named volumes and bind mounts), --restart, --name, -m/--memory, --cpus, --entrypoint, the image and its command, and --network (only noted). The command is tokenized (quotes, backslash escapes, backslash-newline continuations) and never run through a shell.
Some inputs need care:
- A host bind mount (
-v /srv/data:/data) is flagged “needs root approval”, because only root may create one. - Mounting
/var/run/docker.sockis flagged, since it gives the container control of the host. -e NAMEwith no value takes its value from your shell in Docker; enter it in the plan instead.--env-filecannot be read from here; paste its variables into the env table.- Only the first
-pport is routed through the ingress; other published ports stay on the host.
Run an import
- UI
- CLI
- API
Open New app, paste into “Import anything” (or upload a compose file or Dockerfile), and choose Preview plan. The plan shows the source, the build method with its reason, an editable app name and container port, an env table with Required and Secret indicators and inline value inputs, volumes, a domain suggestion and warnings. Deploy stays disabled until every required variable has a value. Deploying a repo opens the live build log. The template, image, git and compose cards below the input remain available.