Skip to content

Manifest file (core.yml)

Want your project's settings in Git, next to your code? This RFC proposes a core.yml file in your repository that describes your project, and a core up command that makes Core match it.

We're thinking about building this and want your feedback first. See Send your feedback.


Idea

Today you set up a project and change its settings (PHP version, crons, databases) in the management interface or through the API. Your application code lives in Git; those settings don't.

With core.yml, you add a file named core.yml to your repository that describes your project. Your CI pipeline runs core up, and Core changes your project to match the file.

version: 1
workspace: acme
project: shop
template: PHP
environments:
  production:
    domain: shop.example.com
    php_version: "8.4"
    databases:
      - name: shop
        password: ${DATABASE_PASSWORD}
    crons:
      - name: cleanup
        command: php bin/cleanup.php
        schedule: "0 3 * * *"
  staging:
    domain: staging.shop.example.com
    php_version: "8.4"

Advantages

  1. Code and settings ship together. If your next release needs PHP 8.4, you change php_version in the same commit. The pipeline switches to PHP 8.4 before it deploys the code, so the new code never runs on the old version.
  2. One history for everything. Settings changes go through the same merge requests, reviews and git log as your code. To undo a change, you revert the commit.
  3. No clicking to set up. A new project, or a staging environment for an existing one, is created by its first pipeline run.

Questions

  1. Do these advantages matter to you? Which one most, and which not at all?
  2. Would you use core.yml? For which of your projects?
  3. If you wouldn't: what would stop you?
  4. Which settings would you want in the file first? The first version would cover the PHP or Node.js version, databases, crons and daemons.
  5. Which CI do you use: GitHub Actions, GitLab CI, or something else?

How it works

Running it

  • core up --environment production changes the project to match the file. It waits until the changes are live, and fails the pipeline if any change failed.
  • core up --dry-run shows what would change, without changing anything. Run it on pull or merge requests, so reviewers see what a settings change will do.
  • Running core up twice with the same file changes nothing the second time.
  • Nothing is deleted unless you ask. Things in your project that the file doesn't mention are listed in the output, and only deleted when you add --remove-orphans.
  • If the file has a mistake (a PHP version that isn't available, a name used twice), nothing changes at all.

Passwords

Passwords never go in the file. You refer to a secret in your CI, such as ${DATABASE_PASSWORD}, and core up fills in the value from your pipeline's environment variables, the same way docker compose does.

Templates

Some templates create things by themselves. For example, Laravel creates a database and a queue worker. These count as part of the file: core up doesn't create them a second time, and --remove-orphans doesn't delete them. To change one, add an entry with the same name to the file.

Changes in the management interface

The file decides. If someone changes the PHP version in the management interface, the next core up sets it back to the version in the file. A setting you leave out of an entry, such as a cron's timeout, gets Core's default, also when someone changed it in the management interface. Projects set up with core.yml show a notice about this in the management interface.

Environments

A project has a production and, if you want, a staging environment. Staging can only be created once production exists. As in the management interface today, a new staging environment starts as a copy of production.

Existing projects

Projects you already have can get a core.yml file too. The API returns all of a project's current settings, so you can give that output to an LLM and ask it to write the core.yml file for you.

Run core up --dry-run on the result. If it shows no changes, the file matches the project. When every project has a file, they all start from the same baseline, and differences between them show up in the files.

Examples

main deploys to production, develop to staging. Pull and merge requests show what would change in the environment of their target branch. CORE_API_KEY and DATABASE_PASSWORD are secrets in your CI.

GitHub Actions

.github/workflows/deploy.yml:

name: Deploy
on:
  push:
    branches: [main, develop]
  pull_request:

env:
  CORE_ENVIRONMENT: ${{ (github.base_ref || github.ref_name) == 'main' && 'production' || 'staging' }}
  CORE_API_KEY: ${{ secrets.CORE_API_KEY }}
  DATABASE_PASSWORD: ${{ secrets.DATABASE_PASSWORD }}

jobs:
  plan:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pipx run --spec python3-core-cli core up --environment "$CORE_ENVIRONMENT" --dry-run

  apply:
    if: github.event_name == 'push'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pipx run --spec python3-core-cli core up --environment "$CORE_ENVIRONMENT"

  deploy-code:
    needs: apply
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: ./deploy.sh  # your existing code deploy

GitLab CI

.gitlab-ci.yml:

workflow:
  rules:
    - if: $CI_COMMIT_BRANCH == "main" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "main"
      variables:
        CORE_ENVIRONMENT: production
    - if: $CI_COMMIT_BRANCH == "develop" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop"
      variables:
        CORE_ENVIRONMENT: staging

stages: [core, deploy]

.core:
  stage: core
  image: python:3.13
  before_script:
    - pip install python3-core-cli

plan:
  extends: .core
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
  script:
    - core up --environment "$CORE_ENVIRONMENT" --dry-run

apply:
  extends: .core
  rules:
    - if: $CI_PIPELINE_SOURCE == "push"
  script:
    - core up --environment "$CORE_ENVIRONMENT"

deploy-code:
  stage: deploy
  rules:
    - if: $CI_PIPELINE_SOURCE == "push"
  script:
    - ./deploy.sh  # your existing code deploy

Future additions

  • A ready-made GitHub Action and GitLab CI/CD component, so the examples above get shorter.

Names of commands, packages and fields may still change.