Files
metin-launcher/docs/metin-release-cli-plan.md
2026-04-14 18:30:43 +02:00

12 KiB

metin-release-cli plan

Plan for a release orchestration toolchain that stays outside NewERP and lets the ERP module act only as the control plane.

Goal

Build two components:

  • metin-release-cli as the real operator and automation entry point
  • metin-release-mcp as a thin MCP wrapper over the CLI

The ERP module should not own manifest generation, signing, blob publishing, or launcher packaging logic. It should call the CLI through a stable contract and store release metadata, status, logs, and audit trail.

Why this split

Current release concerns already live across multiple repos and runtimes:

  • metin-launcher consumes signed manifest.json + blob storage
  • m2dev-client already has make-manifest.py and sign-manifest.py
  • m2pack-secure owns .m2p build, verify, diff, and runtime-key export
  • launcher self-update currently depends on Velopack packaging, which is still Windows-host constrained

Putting that logic into NewERP would duplicate the release path and make the ERP module too heavy. The CLI should own the workflow. ERP should orchestrate it.

Design principles

  • CLI first. Every real operation must be runnable without MCP.
  • JSON first. Every non-interactive CLI command must support machine-readable output.
  • Thin wrapper. MCP must call CLI commands, parse JSON, and return it. No duplicated business logic.
  • Explicit state. Releases move through named stages and emit durable logs.
  • Secret isolation. Signing keys and content keys stay on the release machine or in a secret store, never in ERP DB.
  • Linux-first. Manifest build, signing, blob publish, and .m2p validation must run on Linux. Windows-only launcher packaging remains a separate step.

Scope

metin-release-cli should cover:

  • create and validate a release workspace
  • build or import a release manifest
  • sign the manifest
  • diff against the currently published release
  • upload missing blobs to the update storage
  • archive historical manifests
  • promote a release to current
  • verify the public endpoint after publish
  • optionally record release metadata in ERP through HTTP API
  • optionally manage .m2p release artifacts and runtime-key export
  • optionally run launcher publish as a separate command

metin-release-mcp should cover:

  • expose the same operations as MCP tools
  • map tool input to CLI flags
  • read CLI JSON output
  • pass through logs, status, and errors in structured form

Non-goals

  • No manifest generation inside ERP PHP code
  • No signing inside ERP
  • No heavy artifact proxying through ERP uploads for multi-GB releases
  • No duplicated publish logic in MCP
  • No attempt to hide Windows constraints for Velopack launcher packaging

Canonical release path

For the current launcher contract, the canonical asset release path is:

  1. obtain a prepared client root on Linux
  2. generate manifest.json
  3. sign manifest.json
  4. compute which content-addressed blobs are missing remotely
  5. upload missing blobs
  6. upload archived manifest under manifests/<version>.json
  7. upload archived signature under manifests/<version>.json.sig
  8. switch top-level manifest.json and manifest.json.sig
  9. verify the public endpoint
  10. report final release metadata to ERP

For launcher self-update, the path is separate:

  1. build win-x64 launcher package on Windows-capable host
  2. publish Velopack feed into /launcher/
  3. optionally annotate the same release in ERP

Proposed architecture

1. metin-release-cli

Suggested implementation language:

  • Python is the pragmatic default because the current manifest tooling already exists in Python
  • shell scripts may wrap platform-specific steps, but the primary interface should be one CLI executable with stable subcommands

Suggested internal modules:

  • workspace
    • resolve source roots, temp dirs, release output dirs
  • manifest
    • call or absorb make-manifest.py
  • signing
    • call or absorb sign-manifest.py
  • storage
    • remote existence checks
    • blob upload
    • manifest archive upload
    • current manifest promotion
  • verify
    • verify local artifacts
    • verify public HTTP endpoint
  • erp
    • create/update release records in ERP
  • m2pack
    • optional integration with m2pack-secure
  • launcher
    • optional launcher publish integration

2. metin-release-mcp

Suggested shape:

  • one MCP server process
  • each tool maps 1:1 to one CLI subcommand
  • wrapper only:
    • validates tool input
    • spawns CLI
    • parses JSON stdout
    • returns structured result
    • forwards stderr as diagnostic text

No release decision logic should live here.

Release state model

The CLI should emit explicit states the ERP module can mirror:

  • draft
  • scanning
  • manifest_built
  • signed
  • uploading_blobs
  • uploaded
  • promoting
  • published
  • verifying
  • verified
  • failed
  • rolled_back

Each state transition should include:

  • release_id if known in ERP
  • version
  • started_at
  • finished_at
  • duration_ms
  • step
  • status
  • message
  • log_path if available

CLI command set

Suggested commands:

Release lifecycle

  • metin-release release init
    • create local workspace metadata for a new version
  • metin-release release inspect
    • inspect source root, file counts, launcher presence, total bytes
  • metin-release release build-manifest
    • generate canonical manifest.json
  • metin-release release sign
    • sign manifest.json
  • metin-release release diff-remote
    • compare manifest blobs against remote storage
  • metin-release release upload-blobs
    • upload only missing blobs
  • metin-release release upload-manifest-archive
    • upload manifests/<version>.json and .sig
  • metin-release release promote
    • switch current manifest.json and .sig
  • metin-release release verify-public
    • fetch public manifest, signature, and optional blob samples
  • metin-release release publish
    • composite command executing the full asset publish flow
  • metin-release release rollback
    • promote a historical manifest back to current

ERP sync

  • metin-release erp create-release
  • metin-release erp update-release
  • metin-release erp append-log
  • metin-release erp mark-status

m2pack integration

  • metin-release m2pack build
  • metin-release m2pack verify
  • metin-release m2pack diff
  • metin-release m2pack export-runtime-key

Launcher integration

  • metin-release launcher publish
    • separate path because of Windows packaging constraints

JSON contract

Every automation-facing command should support:

--json

Success output shape:

{
  "ok": true,
  "command": "release publish",
  "version": "2026.04.14-1",
  "status": "published",
  "artifacts": {
    "manifest_path": "/abs/path/manifest.json",
    "signature_path": "/abs/path/manifest.json.sig"
  },
  "stats": {
    "file_count": 123,
    "blob_count": 9,
    "uploaded_blob_count": 3,
    "uploaded_bytes": 1048576
  },
  "remote": {
    "manifest_url": "https://updates.jakubkadlec.dev/manifest.json"
  },
  "erp": {
    "release_id": 42
  }
}

Failure output shape:

{
  "ok": false,
  "command": "release publish",
  "version": "2026.04.14-1",
  "status": "failed",
  "error": {
    "code": "blob_upload_failed",
    "message": "Failed to upload one or more blobs"
  }
}

Exit code rules:

  • 0 success
  • 1 operator or validation error
  • 2 remote or network error
  • 3 signing or integrity error
  • 4 ERP sync error

ERP integration contract

The ERP module should integrate with the CLI at the orchestration layer only.

Recommended boundary:

  • ERP creates a draft release record
  • ERP stores operator intent, notes, target channel, and visibility
  • ERP triggers the CLI through a worker, SSH command, queue job, or agent
  • CLI performs release operations
  • CLI pushes structured status updates back to ERP
  • ERP renders the timeline, logs, artifacts, and rollback actions

Recommended ERP-owned data:

  • release version
  • notes
  • previous release reference
  • publish status
  • operator identity
  • started/finished timestamps
  • manifest metadata
  • remote verification status
  • launcher publish status
  • pointers to logs and artifacts

CLI-owned data:

  • actual manifest generation
  • signing
  • file hashing
  • blob deduplication
  • upload semantics
  • runtime-key export
  • launcher packaging invocation

Remote storage contract

For the current launcher path, the CLI should treat this as canonical:

  • /var/www/updates.jakubkadlec.dev/files/<hash-prefix>/<sha256>
  • /var/www/updates.jakubkadlec.dev/manifests/<version>.json
  • /var/www/updates.jakubkadlec.dev/manifests/<version>.json.sig
  • /var/www/updates.jakubkadlec.dev/manifest.json
  • /var/www/updates.jakubkadlec.dev/manifest.json.sig
  • /var/www/updates.jakubkadlec.dev/launcher/*

Promotion safety rule:

  • upload immutable blobs first
  • upload archived versioned manifest second
  • replace current manifest last

Secrets and security

  • launcher manifest signing key remains outside ERP
  • .m2p master keys remain outside ERP
  • CLI reads secrets from:
    • fixed secure file paths
    • environment variables
    • secret manager integration later
  • CLI must redact secrets from logs and JSON output

Never return:

  • raw private keys
  • runtime master keys
  • decrypted secret material

Linux and Wine posture

Supported on Linux now:

  • client tree scan
  • manifest build
  • manifest signing
  • blob upload and promotion
  • .m2p build and verification
  • Wine-based smoke validation if needed

Not fully Linux-native yet:

  • Velopack packaging for win-x64 launcher release

Implication:

  • asset release commands should be Linux-first
  • launcher publish should remain an explicit separate command and may require a Windows runner or Windows host until the toolchain changes

MCP tool set

Suggested MCP tools:

  • release_init
  • release_inspect
  • release_build_manifest
  • release_sign
  • release_diff_remote
  • release_upload_blobs
  • release_promote
  • release_verify_public
  • release_publish
  • release_rollback
  • erp_create_release
  • erp_update_release
  • m2pack_build
  • m2pack_verify
  • m2pack_diff
  • m2pack_export_runtime_key
  • launcher_publish

Each tool should document the exact CLI command it runs.

Phase 1. Asset release CLI

Build first:

  • release inspect
  • release build-manifest
  • release sign
  • release diff-remote
  • release upload-blobs
  • release promote
  • release verify-public
  • release publish

This is the minimum path ERP needs for the current launcher contract.

Phase 2. ERP sync

Build second:

  • erp create-release
  • erp update-release
  • CLI status callbacks or polling contract

This lets the ERP module focus on UI, permissions, and audit trail.

Phase 3. MCP wrapper

Build third:

  • expose the Phase 1 and 2 CLI commands as MCP tools
  • no new logic

Phase 4. m2pack path

Build fourth:

  • m2pack build
  • m2pack verify
  • m2pack diff
  • m2pack export-runtime-key

Only after the signed-manifest release path is stable.

Phase 5. Launcher release path

Build fifth:

  • launcher publish
  • Windows-capable execution environment
  • optional ERP annotation

Open decisions

  • Whether the CLI should directly push status to ERP or ERP should poll CLI job results
  • Whether release workspaces are local-only or persisted on a shared release host
  • Whether .m2p artifacts become part of the same release object now or later
  • Whether launcher release should be represented as:
    • separate release type
    • or a child job under the same release

Recommendation

Start with:

  • one Linux-first metin-release-cli
  • one thin metin-release-mcp
  • ERP module consuming only CLI results and statuses

Do not start by embedding release logic in ERP. That will create a second source of truth and make later .m2p and launcher evolution harder.