Aller au contenu

Syntax reference

This page is the canonical reference for mecapy.yml v1. Each section maps one-to-one to a Pydantic model in mecapy_api.services.manifest_v1_models, which is the source of truth.

version: "1"

Frozen at "1". Any other value is rejected. A future v2 format will keep the same key and bump the literal — your existing manifests stay valid as long as MecaPy keeps the v1 parser around.

package:
name: bolt-sizing # required
version: 0.1.0 # required, semver
description: | # optional
One-line summary; multi-line allowed.
author: Jane Doe # optional
license: MIT # optional
visibility: private # optional, default "private"
tags: [bolts, mechanics] # optional
resources: # optional, see below
tier: nano
FieldTypeDefaultNotes
namestringPackage identifier. Kebab-case recommended.
versionstringStrict semver: MAJOR.MINOR.PATCH (optional pre-release tag).
descriptionstringnullFree text.
authorstringnullFree text.
licensestringnullSPDX identifier (MIT, Apache-2.0, …).
visibilityenum"private"private / internal / public. See visibility.
tagslist[string]nullFor search/categorisation in the package list.
resourcesobjectnullDefault resources every function inherits — see below.

The block is a discriminated union on kind. Each kind has its own required fields:

runtime:
kind: python # mode A — managed
version: "3.12" # required, "3.10" | "3.11" | "3.12"
requirements: false # optional, install repo-root requirements.txt at build
runtime:
kind: dockerfile # mode B — build custom
dockerfile: Dockerfile # required, path relative to repo root
context: . # optional, default "."
runtime:
kind: image # mode C — pre-built
image: ghcr.io/me/x:1.4 # required, full registry reference with tag

Per-kind details and trade-offs: runtime modes.

A non-empty dict. Each entry has the same shape but two mutually exclusive top fields depending on the runtime mode:

functions:
my_function:
# ── Mode A only ──
handler: pkg.module:function # required in mode A
# ── Modes B/C only ──
entrypoint: ["python", "/run.py", "x"] # required in modes B/C, list[str], non-empty
# ── Common ──
description: |
Free-text description.
inputs:
diameter: { type: Length, required: true, description: "..." }
load: { type: Force }
outputs:
stress: { type: Stress }
resources:
tier: nano
timeout: 120
testcases: tests/static_support.json # optional path to JSON test cases
FieldTypeRequiredNotes
handlerstringmode A onlymodule:function. Module-level functions only — see handlers.
entrypointlist[string]modes B/C onlyargv list, non-empty. The container runs entrypoint[0] entrypoint[1] ....
descriptionstringnoFree text.
inputsobjectnoTyped input ports. See typed I/O.
outputsobjectnoTyped output ports.
resourcesobjectnoPer-function override of package.resources.
testcasesstringnoPath (relative to repo root) of a JSON file with test cases — read at deploy when quality.validation_testcases.on_deployment is true.

handler and entrypoint are mutually exclusive at the model level (can’t have both, must have one). The cross-check against runtime.kind happens after parsing — mode A requires handler, modes B/C require entrypoint.

In mode A you can leave inputs: / outputs: out entirely — MecaPy introspects the handler’s signature and infers them from type hints. You only declare them when you want to override or document. In modes B/C they are mandatory because there’s no Python signature to read.

Two ways to declare resources, mutually exclusive within the same block:

resources:
tier: nano # one of: nano, micro, small, medium, large
timeout: 60 # optional, overrides the tier's timeout
TierCPUMemory (MiB)Timeout (s)
nano151260
micro11024120
small (default)22048300
medium24096600
large481921800

large is the platform hard cap. Asking for more in cpu, memory_mb, or timeout (below) raises a validation error.

resources:
cpu: 2
memory_mb: 1500
timeout: 90

cpu and memory_mb may both appear, neither, or just one — but neither can coexist with tier: in the same block.

package.resources sets the default. Each function may override with its own resources: block. The merge follows three rules:

  1. If the function declares tier:, it fully selects CPU/memory from that tier — package-level cpu/memory_mb are dropped.
  2. If the function declares cpu: and/or memory_mb:, those become authoritative for the fields they cover; the other explicit field, when missing, is inherited from the package (unless package was tier-mode, in which case the function must provide both).
  3. timeout: is independently overridable at any level.

Missing both blocks falls back to the platform default (tier: small).

A free-form dict. Today’s only consumer is testcase gating:

quality:
validation_testcases:
on_deployment: true # run testcases at deploy time
fail_on_error: false # block deploy on test failure (default false)

When on_deployment: true, the deploy route loads each function’s testcases: JSON file and runs the cases. Per-function status is surfaced in the deploy response. With fail_on_error: true, a failing case turns the deploy into a 4xx; otherwise the deploy completes and the failed cases are reported as warnings.

The block is intentionally untyped at the model level so new sub-keys can land without bumping the manifest format. Anything outside validation_testcases is currently ignored.

The parser runs in this order — knowing the order helps when reading error messages:

  1. YAML load — syntax errors here come from pyyaml.
  2. Pydantic schema — type-checks every field per the model.
  3. Discriminated runtime resolutionruntime.kind selects which sub-model parses the rest of the runtime block.
  4. handler XOR entrypoint — function-level model validator.
  5. Cross-check runtime.kind ↔ per-function field — manifest-level validator (validate_manifest_modes).
  6. Resources caps — every resources: block must respect large-tier limits.
  7. Typed I/O resolution — every type: is looked up in the type catalog; unknown types fail.
  8. Mode A signature introspection (deploy-time only) — the handler is imported and its signature read for type-hint-based schemas.

Errors in steps 1–7 are returned synchronously as 4xx by the deploy route. Step 8 errors fall back to a permissive {"type": "object"} schema with a warning logged server-side rather than failing the deploy outright.