andreapollastri/cipi-api
An API layer for Cipi, the open-source Laravel server control panel. It exposes REST endpoints for managing servers, sites, databases, and deployments, so you can automate provisioning and administration from external apps and scripts.
Install and configure
composer require the package, then publish its config so config/cipi.php exists — that file holds the API base URL, token and the ability list (yml-view, yml-manage are new in 1.35.0).cipi api token create, where you choose abilities.cipi self-update (runs migration 5.6.4). If you skip this, the four new routes answer 503 while every 1.34.0 route keeps working — so a green test suite elsewhere doesn't prove yml is available.cipi yml plan --json / cipi yml auto status --json and the sudoers entries (/etc/sudoers.d/cipi-api) for cipi yml plan|apply|auto. If those sudoers lines are missing, the endpoints fail at the CLI layer, not in your app.Where to look first
config/cipi.php — confirm yml-view / yml-manage are in the ability map before writing any code.info.version 1.35.0) — new cipi.yml tag, four paths, schemas YmlPlanResponse, YmlAutoResponse, JobResultAppYmlApply. Generate or refresh your client from it rather than hand-rolling payloads.CipiCliService::ALLOWED_COMMANDS — yml plan, yml apply, yml auto are whitelisted there; this is the list that gates anything tunnelled through the CLI service.First use case (10 minutes)
Read the plan for an app you already deploy, read-only, no side effects:
$plan = Cipi::get("/api/apps/{$app}/yml"); // GET /api/apps/{name}/yml
// file, auto, valid{errors,warnings}, changes[], blockers[], notes, in_sync
Render changes (each has kind + summary) and blockers in a dashboard, and skip everything when in_sync is true. This is the single most useful call in the release: it tells you what a deploy would change and whether apply would refuse, before anything is queued.
Plan → confirm → apply (the default workflow)
Treat GET /api/apps/{name}/yml as the preview and POST /api/apps/{name}/yml/apply as the mutation. Persist the plan, show changes/blockers to a human (or a policy check in CI), then queue the apply. Because plan is synchronous and read-only, it is safe to call on page loads, in health checks, and from agents.
Outcome-first job handling
apply returns an async job app-yml-apply. The result carries outcome (applied | unchanged | partial | blocked | invalid | no-file), plus applied, failed, failures, blockers, errors. Critically, the last four outcomes end the job as failed while still carrying the result. So:
failed to an exception/alert. Branch on outcome.switch on outcome with explicit handling: blocked/invalid → surface blockers/errors to the author; no-file → nothing to do (file was null); partial → some resources applied, failures lists the rest; unchanged → success, no diff.Auto-apply as a deliberate opt-in
POST /api/apps/{name}/yml/auto/enable and …/disable are synchronous and idempotent, returning {app, auto, sudoers, file}. Use them behind an explicit confirmation step in your UI/CLI — enabling means anyone who can commit to the repo controls that app's server configuration. Practical guardrails:
yml-manage) or a specific role, and log who flipped it.sudoers in the response to confirm the server-side plumbing is actually in place.apply path for hotfix flows.Token and ability scoping
yml-view/yml-manage — mint new ones at rollout time.yml-view token for dashboards, admin panels and MCP read tools; a yml-manage token for the deploy pipeline and the apply/auto routes.apply and both auto endpoints require yml-manage; the plan endpoint needs only yml-view.CI/CD integration
Two viable shapes:
blockers is non-empty or in_sync is false.plan → assert no blockers → apply (job) → poll until terminal → assert outcome in applied|unchanged. Keep the polling inside your pipeline step, with the yml-manage token scoped to a single environment.Agents and MCP
MCP server 1.5.0 exposes 76 tools on a single tools/list page, including AppYmlShow (read-only), AppYmlApply (job) and AppYmlAuto (enabled). Pattern: let the agent call AppYmlShow freely to reason about drift, and require an explicit human confirmation before AppYmlApply/AppYmlAuto. Because the tool list still fits one page, you can load it eagerly without pagination handling.
Job result enrichment
1.35.0 fills a missing parsed app key in job results from the job's parameters. If you persist job results keyed by app, you can now rely on result.app being present even when the CLI text didn't echo it — handy for correlating the app-yml-apply job back to the request without a lookup table.
failed as "no payload". Check for a result object before throwing.valid.errors (parse/semantic problems), blockers (apply refuses while any is listed), failures (per-resource failures after a partial apply) and the job-level errors mean different things and drive different UX.file: null is normal. The plan reads the cipi.yml of the live release; a fresh app or one deployed before the file was added will return null and apply will report no-file. Don't treat it as a bug.auto in the response is the truth; sudoers tells you about the server-side grant./etc/sudoers.d/cipi-api was hand-edited or the migration didn't run, yml plan *, yml apply *, yml auto * lines may be missing and the API will fail confusingly. Verify with the CLI on the host.cipi yml plan <app> --json on the server is byte-for-byte what the endpoint reports. When the API response surprises you, run the CLI and compare — it collapses the whole client/server question in one step.CipiCliService only survives if it's in ALLOWED_COMMANDS; the release added the three yml verbs, so wrappers you wrote around them need no change, but new verbs do.config/cipi.php for abilities/endpoints, CipiCliService::ALLOWED_COMMANDS for CLI surface, and the OpenAPI doc for generating typed DTOs (YmlPlanResponse, YmlAutoResponse, JobResultAppYmlApply) instead of hand-mapping arrays.yml-manage token out of anything a repo contributor can read.How can I help you explore Laravel packages today?