# Config versions

Shipshape has two configuration formats. The same binary runs both.

1.x is the recommended format

The 1.x pipeline (collect / analyse / output) is used in production and is the recommended format for new configurations. The 0.x checks: format is fully supported and continues to run without changes.

Not sure if 1.x covers everything you need? Check the gaps matrix to see how each 0.x check is reproduced in 1.x, and the roadmap to see what's coming.

# Which format should I use?

  • Starting a new configuration — use 1.x.
  • Running an existing 0.x config — it still runs as-is. Migrate to 1.x when convenient; there is no forced migration.
  • Relying on a check that isn't ported yet — check the gaps matrix. If the 1.x equivalent isn't there yet, keep using the 0.x check until it lands.

# How the binary picks a format

The deciding key is collect:. When Shipshape reads a config file it tries to parse it as a 1.x config first: if a non-empty top-level collect: block is present, the file is treated as 1.x and the pipeline runner is used. Otherwise the file is treated as 0.x and the checks runner is used.

`collect:` is the only key that selects 1.x

connections:, analyse: and output: do not on their own make a file 1.x. A file containing only analyse: (or only output:) falls through to the 0.x runner, which finds no checks: block and runs zero checks — exiting 0 as though everything passed.

Those three keys matter only once a run is already 1.x, where they are used to reject a 0.x file passed alongside a 1.x one (see Mixing formats below). An empty collect: block does not count either — it must contain at least one fact.

The distinguishing key is the top-level block name:

# 0.x — identified by the top-level "checks:" key
checks:
  file:
    - name: Illegal files
      path: web
      disallowed-pattern: '^(adminer|phpmyadmin|bigdump)?\.php$'
# 1.x — identified by a non-empty top-level "collect:" key
collect:
  disallowed-php-scripts:
    file:lookup:
      path: web
      pattern: '^(adminer|phpmyadmin|bigdump)?\.php$'

analyse:
  disallowed-php-scripts-found:
    not:empty:
      description: 'Disallowed php scripts found'
      input: disallowed-php-scripts
      severity: high

If a single file contains both a checks: key and a non-empty collect: key, the 1.x runner takes precedence and the checks: block is ignored.

# Mixing formats across files

Passing a 0.x file and a 1.x file to the same run with -f is an error, not a merge:

$ shipshape run . -f pipeline.yml -f legacy-checks.yml
config file "legacy-checks.yml" is not v2-compatible but was provided
alongside a v2 config; mixing v1 and v2 config files is not supported

Once any file in the run declares a non-empty collect:, every other file must contain at least one of connections, collect, analyse or output. A file with none of them is reported rather than silently discarded. Run the two formats as separate invocations instead.

# Format overview

0.x 1.x
Top-level key checks: collect: (the deciding key)
Config struct Config ConfigV2
Runner RunConfig RunV2
Model One check per concern — collection, evaluation, and optional remediation bundled together Composable pipeline — collect data with one plugin, analyse it with another
Status Fully supported Recommended

# What's the difference?

A 0.x check is a single, opinionated unit: it knows how to collect the data it needs, evaluate it, and (for some checks) fix problems it finds. A 1.x config separates those steps — a collect plugin gathers raw data, an analyse plugin evaluates it. This makes the pieces reusable and composable, at the cost of needing more explicit wiring.

The gaps matrix shows which 0.x checks have a full 1.x equivalent today, and the 0.x config guide documents the checks: format in full.

# The 1.x way: compose, don't port

0.x gave you one dedicated check type per task. 1.x takes a different approach: a small set of general-purpose collect and analyse plugins that you wire together to achieve the same outcome. You won't find a one-to-one replacement plugin for each 0.x check — instead you compose the same handful of building blocks (for example command + allowed:list, or file:read + yaml:key + equals) in different ways. The building blocks are reusable across many checks, so learning a few covers a lot of ground.

The gaps matrix is the recipe catalogue: for each 0.x check it shows the plugin chain that reproduces it in 1.x.