gitaiflow / Deployment / gitaiflow MCP Deployment
DocsgitaiflowDeploymentgitaiflow MCP Deployment

gitaiflow MCP Deployment

This document is the operational reference for releasing gitaiflow AOT binaries and the Claude Desktop MCPB extension.

16 min readApplies to v1.1.3Added in 1.1.3
On this page ▾
  1. 1. Purpose
  2. 2. Release Architecture
  3. 3. Release Artifacts
  4. 4. Release Signing
  5. 5. Signing Key Storage
  6. Signing key present
  7. Signing key absent
  8. Final flow
  9. Important property
  10. 7.1 Installer metadata
  11. 7.2 Installer binaries
  12. 7.3 Installer entrypoints
  13. 7.4 Generated manifest
  14. Commands
  15. Why this order matters
  16. Step 1 — Rotate the key
  17. Step 2 — Verify the key
  18. Step 3 — Rebuild AOT
  19. Step 4 — Rebuild MCPB
  20. Step 5 — Sign the AOT release
  21. Step 6 — Generate the manifest
  22. Step 7 — Synchronize to R2
  23. Keep
  24. Do not add unless needed
  25. Normal release
  26. Key-rotation release
  27. SHA256SUMS.sig exists but verification fails
  28. MCPB rejects a newly released AOT binary
  29. R2 sync reports signing was skipped
  30. latest.txt appears stale
  31. Build
  32. Build macOS arm64 MCPB
  33. Rotate signing key
  34. Verify signing key
  35. Sign a release
  36. Generate manifest
  37. Synchronize to R2

Deployment, signing, key rotation, build, and R2 synchronization guide for the gitaiflow MCP extension and AOT releases.

1. Purpose

It covers:

  • AOT release builds
  • MCPB builds
  • Ed25519 release signing
  • Embedded public-key trust
  • Signing-key rotation
  • Signature verification
  • R2 synchronization
  • Cache behavior for mutable release metadata
  • Normal releases
  • Releases involving signing-key rotation
  • Local/test synchronization
  • Recommended release safeguards
  • Common failure modes and recovery

The release process is intentionally split into build, signing, manifest generation, and R2 synchronization steps so each stage can be inspected independently.


2. Release Architecture

gitaiflow has two related release artifacts:

  1. AOT binary

    • Built with the gitaiflow AOT build process.
    • Published under installers/AOT/<version>/.
    • Protected by SHA256SUMS and SHA256SUMS.sig.
  2. MCPB extension

    • Built for Claude Desktop.
    • Published under installers/MCP/<version>/.
    • The MCP server contains the public key used to verify trusted AOT releases.

The trust relationship is:

text
                    Release Signing Key
                           │
                     Ed25519 private key
                           │
                           ▼
                    SHA256SUMS.sig
                           │
                           │ verifies
                           ▼
                     SHA256SUMS
                           │
                           │ hashes
                           ▼
                     AOT binaries
                           ▲
                           │
                     trusted by
                           │
                           │ embedded public key
                           │
                    ┌──────┴──────┐
                    │             │
                 install.sh   MCP binary.py

The private signing key is never committed to the repository.

The public key is intentionally embedded in the release verification code:

  • scripts/install/install.sh
  • mcp_server/binary.py

Both must contain the same public key.


3. Release Artifacts

An AOT release has the following general structure:

text
installers/
└── AOT/
    └── v1.1.3/
        ├── gitaiflow-darwin-arm64
        ├── gitaiflow-linux-amd64
        ├── gitaiflow-linux-arm64
        ├── gitaiflow-windows-amd64.exe
        ├── SHA256SUMS
        └── SHA256SUMS.sig

The MCP release has a structure similar to:

text
installers/
└── MCP/
    └── v1.1.3/
        └── gitaiflow-mcp-1.1.3-darwin-arm64.mcpb

The current MCP build process produces the MCPB from the MCP server and associated packaged resources. The build output is validated as an MCPB before being written to the installer directory.


4. Release Signing

gitaiflow uses Ed25519 signing for release integrity.

The signing process produces:

text
SHA256SUMS
SHA256SUMS.sig

SHA256SUMS contains SHA-256 hashes for the AOT binaries.

SHA256SUMS.sig is the Ed25519 signature over the checksum file.

The verification chain is therefore:

text
AOT binary
    │
    ▼
SHA-256
    │
    ▼
SHA256SUMS
    │
    ▼
Ed25519 signature
    │
    ▼
SHA256SUMS.sig
    │
    ▼
Embedded trusted public key

A valid signature establishes that the checksum manifest was signed by the trusted release key. The checksum manifest then establishes the expected hash of each binary.


5. Signing Key Storage

The private signing key is kept outside the repository.

On the development machine, the current workflow uses macOS Keychain storage with:

text
Service:
gitaiflow-release-signing-key

Account:
$USER

The private key must not be committed to Git.

When a key is generated by the rotation script, the script writes the new private key outside the repository and explicitly requires the operator to move it into secure secret storage and remove the temporary copy.

The rotation script also records public-key/timestamp information in:

text
scripts/release/KEY_ROTATIONS.log

No secret material should be logged.


6. gitai_r2.sh Signing Decision Flow

The R2 synchronization script supports two operating modes.

Signing key present

When GITAIFLOW_SIGNING_KEY_FILE is available, gitai_r2.sh inspects AOT release directories.

For every release:

  • If SHA256SUMS.sig is absent:
    • sign the release
    • verify the resulting signature
  • If SHA256SUMS.sig already exists:
    • verify the existing signature
    • do not automatically replace or re-sign it
  • If verification fails:
    • stop the release process

Signing key absent

Without a signing key, the script operates in local/test mode.

It warns that release signing was skipped.

This is useful for local development and testing, but an unsigned release must not be promoted as a production release.

Final flow

Important property

An existing signature is verified, not blindly trusted merely because the file exists.

This avoids the following unsafe situation:

text
SHA256SUMS.sig exists
        │
        ▼
assume valid
        │
        ▼
upload release

Instead:

text
SHA256SUMS.sig exists
        │
        ▼
verify against SHA256SUMS + trusted key
        │
        ├── valid ──► upload
        │
        └── invalid ─► stop

7. R2 Synchronization

gitai_r2.sh separates R2 synchronization into several categories.

7.1 Installer metadata

The following files are treated as mutable release metadata:

text
SHA256SUMS
SHA256SUMS.sig
latest.txt

They are uploaded with:

text
Cache-Control: no-store, must-revalidate

This is intentional.

These files can change at the same URL, particularly:

text
latest.txt
SHA256SUMS
SHA256SUMS.sig

Caching them aggressively could result in a client receiving an inconsistent combination of release metadata and binaries.

7.2 Installer binaries

AOT and MCP binaries are synchronized separately.

The mutable metadata files are excluded from the binary transfer.

The synchronization also excludes common local filesystem artifacts such as:

text
.DS_Store
Thumbs.db
desktop.ini

7.3 Installer entrypoints

The R2 sync includes the installer entrypoints:

text
install.sh
install-mcp.sh
install.ps1
install-mcp.ps1

7.4 Generated manifest

The gitaiflow manifest is synchronized separately after the installer artifacts.

The general R2 flow is:


8. Why Metadata Uses no-store

The release system overwrites stable URLs such as:

text
latest.txt
SHA256SUMS
SHA256SUMS.sig

A stale edge cache can create a dangerous mismatch:

text
latest.txt
    │
    ▼
v1.1.3
    │
    ▼
SHA256SUMS from v1.1.2   ← stale cache

or:

text
SHA256SUMS
    │
    ▼
new release

SHA256SUMS.sig
    │
    ▼
old release signature

Using:

text
Cache-Control: no-store, must-revalidate

for mutable metadata reduces this class of cache inconsistency.

Release binaries can remain cacheable because versioned binary paths are effectively immutable:

text
installers/AOT/v1.1.3/gitaiflow-darwin-arm64

A future release should use a new versioned path:

text
installers/AOT/v1.1.4/gitaiflow-darwin-arm64

9. Normal Release Flow

A normal release does not rotate the signing key.

The recommended high-level order is:

text
Build AOT
   │
   ▼
Build MCPB
   │
   ▼
Sign AOT release
   │
   ▼
Generate manifest
   │
   ▼
Verify / sign through R2 sync
   │
   ▼
Sync to R2

Commands

bash
# Build the AOT release
make build

# Build the MCPB for macOS arm64
make mcp-build-mac-arm64

# Generate the gitaiflow R2 manifest
python3 scripts/r2/generate_gitai_manifest.py

# Synchronize the release to R2
./scripts/r2/gitai_r2.sh

If signing is being performed explicitly before synchronization:

bash
./scripts/release/sign_release.sh v1.1.3

python3 scripts/r2/generate_gitai_manifest.py

./scripts/r2/gitai_r2.sh

The explicit signing step is useful when the release operator wants the signature generation to be visible and independently verifiable before the R2 synchronization.

When GITAIFLOW_SIGNING_KEY_FILE is configured, gitai_r2.sh can also sign an AOT release when its signature is missing.


10. Key Verification Before Release

Before signing a release, verify that the signing key and embedded public key agree.

bash
./scripts/release/verify_release_signing_key.sh

The expected relationship is:

text
Private key
    │
    ▼
derive public key
    │
    ▼
compare
    │
    ├── matches ──► release can be signed
    │
    └── mismatch ─► stop

A successful verification should show that the derived key and embedded binary.py public key match.

The same trust material is also embedded in install.sh.


11. Signing an AOT Release Manually

To explicitly sign a release:

bash
./scripts/release/sign_release.sh v1.1.3

This generates:

text
installers/AOT/v1.1.3/SHA256SUMS
installers/AOT/v1.1.3/SHA256SUMS.sig

The checksum manifest covers the AOT binaries, for example:

text
gitaiflow-darwin-arm64
gitaiflow-linux-amd64
gitaiflow-linux-arm64
gitaiflow-windows-amd64.exe

Both files must be available to the R2 synchronization process.


12. Signing Through gitai_r2.sh

The R2 script supports:

bash
GITAIFLOW_SIGNING_KEY_FILE

When this is set, the script can sign AOT releases that do not already have signatures.

Conceptually:

bash
export GITAIFLOW_SIGNING_KEY_FILE="/secure/path/release-signing.key.b64"

./scripts/r2/gitai_r2.sh

The script should not automatically re-sign an existing release merely because a signing key is available.

That is important for release reproducibility.

A release already signed by the trusted release key should remain signed by that key.


13. Signing-Key Rotation

Signing-key rotation is a special release operation.

The most important rule is:

The MCPB must be rebuilt after the public key is rotated and before an AOT release is signed with the new private key.

The correct order is:

text
ROTATE SIGNING KEY
        │
        ▼
VERIFY EMBEDDED PUBLIC KEY
        │
        ▼
REBUILD AOT + MCPB
        │
        ▼
SIGN AOT RELEASE
        │
        ▼
GENERATE MANIFEST
        │
        ▼
SYNC TO R2

Why this order matters

The MCP server contains the trusted public key.

If the MCPB was built before key rotation:

text
Old MCPB
  │
  └── trusts OLD public key

New AOT release
  │
  └── signed with NEW private key

The old MCPB may reject the new AOT release.

Therefore:

text
New signing key
      │
      ├── new install.sh trust
      │
      ├── new mcp_server/binary.py trust
      │
      └── new AOT signatures

must be released consistently.


14. Key-Rotation Commands

Step 1 — Rotate the key

bash
./scripts/release/rotate_signing_key.sh

The rotation script:

  • generates a new Ed25519 keypair
  • updates the embedded public key in install.sh
  • updates the embedded public key in mcp_server/binary.py
  • verifies that both files contain the same public key
  • writes the new private key outside the repository
  • records public-key/timestamp information in KEY_ROTATIONS.log

The script itself requires the operator to move the new private key into secure secret storage and delete the temporary local copy.

Step 2 — Verify the key

bash
./scripts/release/verify_release_signing_key.sh

Do not proceed if the derived key and embedded public key do not match.

Step 3 — Rebuild AOT

bash
make build

Step 4 — Rebuild MCPB

bash
make mcp-build-mac-arm64

This step is mandatory after rotation because the MCPB must contain the newly trusted public key.

Step 5 — Sign the AOT release

bash
./scripts/release/sign_release.sh v1.1.3

Step 6 — Generate the manifest

bash
python3 scripts/r2/generate_gitai_manifest.py

Step 7 — Synchronize to R2

bash
./scripts/r2/gitai_r2.sh

15. Complete Key-Rotation Release

The complete sequence can therefore be run as:

bash
# Rotate
./scripts/release/rotate_signing_key.sh

# Verify new public key is correctly embedded
./scripts/release/verify_release_signing_key.sh

# Rebuild AOT
make build

# Rebuild MCPB AFTER rotation
make mcp-build-mac-arm64

# Sign release using the new private key
./scripts/release/sign_release.sh v1.1.3

# Generate R2 manifest
python3 scripts/r2/generate_gitai_manifest.py

# Sync to R2
./scripts/r2/gitai_r2.sh

16. Key-Rotation Safety Rule

Never perform this sequence:

text
Build MCPB
    │
    ▼
Rotate signing key
    │
    ▼
Sign AOT with new key
    │
    ▼
Publish

That creates a potentially incompatible release:

text
MCPB
 └── old public key

AOT
 └── new signature

Instead:

text
Rotate
   │
   ▼
Update trusted public key
   │
   ▼
Rebuild MCPB
   │
   ▼
Sign AOT
   │
   ▼
Publish both

17. Existing Installed Versions After Rotation

Rotating the signing key does not invalidate an already-installed AOT executable merely because the key changed.

The existing binary can continue to run.

The compatibility concern is the verification path used when obtaining or upgrading to a newly signed release.

In particular, an older MCPB containing only the old public key may not accept a newly signed AOT release.

This is why the new MCPB must be released as part of the key-rotation transition.


18. Future Key Rotation Strategy

The current release does not require dual-key verification.

For a future rotation where a large population of older MCPB installations must be supported, a migration strategy can be considered:

text
Phase 1
───────
MCP trusts OLD + NEW

        ↓

Phase 2
───────
Release new MCPB

        ↓

Phase 3
───────
Sign new AOT releases with NEW

        ↓

Phase 4
───────
Allow migration window

        ↓

Phase 5
───────
Remove OLD trust

This is a future migration strategy, not a requirement for the current release process.

Do not introduce dual-key complexity unless an actual key rotation requires it.


19. Local / Test R2 Synchronization

The R2 script deliberately supports local/test usage without a signing key.

If:

bash
GITAIFLOW_SIGNING_KEY_FILE

is not configured, the script warns that signing is skipped.

This is useful when testing:

  • R2 paths
  • installer synchronization
  • manifest generation
  • cache behavior
  • MCP distribution
  • local release workflows

The warning should be treated as a production safety boundary.

text
No signing key
      │
      ▼
Local / test mode
      │
      ▼
Warning
      │
      ▼
Sync may proceed

Do not treat an unsigned synchronization as a production release.


20. Recommended Release Policy

The current architecture should remain intentionally simple.

Keep

  • Ed25519 release signing
  • public key embedded in install.sh
  • public key embedded in mcp_server/binary.py
  • explicit key verification
  • SHA256SUMS
  • SHA256SUMS.sig
  • optional signing through GITAIFLOW_SIGNING_KEY_FILE
  • existing-signature verification
  • no automatic re-signing of valid existing releases
  • no-store metadata headers
  • versioned immutable binary paths
  • separate AOT and MCPB build steps
  • explicit MCPB rebuild after key rotation

Do not add unless needed

  • mandatory signing for every local R2 sync
  • automatic re-signing after key rotation
  • dual-key verification without a migration requirement
  • unnecessary changes to the existing Makefile release workflow

The Makefile remains the preferred high-level entry point for builds.

The individual scripts remain available when an operator needs to inspect or repeat a specific release stage.


21. Recommended Release Checklist

Normal release

  • Update version
  • Build AOT
  • Build MCPB
  • Verify release signing key
  • Sign AOT release
  • Confirm SHA256SUMS exists
  • Confirm SHA256SUMS.sig exists
  • Verify signature
  • Generate R2 manifest
  • Run gitai_r2.sh
  • Confirm R2 metadata is current
  • Confirm versioned binaries are present
  • Test installer
  • Test MCPB in Claude Desktop

Key-rotation release

  • Rotate signing key
  • Secure the new private key
  • Remove temporary private-key material
  • Verify embedded public key
  • Rebuild AOT
  • Rebuild MCPB after rotation
  • Sign AOT with the new key
  • Verify signature
  • Generate manifest
  • Sync to R2
  • Test installer verification
  • Test MCPB AOT verification
  • Test MCP tools from Claude Desktop

22. Troubleshooting

SHA256SUMS.sig exists but verification fails

Do not overwrite it automatically.

Stop the release and determine why the signature does not match.

Possible causes include:

  • wrong signing key
  • modified SHA256SUMS
  • stale signature
  • release artifacts changed after signing
  • embedded public key mismatch

Correct sequence:

text
Invalid signature
       │
       ▼
STOP
       │
       ▼
Inspect release
       │
       ▼
Determine cause
       │
       ▼
Regenerate/re-sign intentionally

MCPB rejects a newly released AOT binary

First check whether the signing key was rotated.

If yes, verify:

bash
./scripts/release/verify_release_signing_key.sh

Then confirm that the MCPB was rebuilt after the rotation.

The common incorrect sequence is:

text
MCPB built
    ↓
key rotated
    ↓
AOT signed
    ↓
MCPB not rebuilt

The correct sequence is:

text
key rotated
    ↓
MCPB rebuilt
    ↓
AOT signed
    ↓
publish

R2 sync reports signing was skipped

A warning similar to:

text
Warning: GITAIFLOW_SIGNING_KEY_FILE not set -- skipping release signing.

means the R2 script did not have access to the private signing key.

It does not necessarily mean the release has no signature.

If sign_release.sh was already run and produced:

text
SHA256SUMS.sig

the R2 script can upload that existing signature.

For production releases, verify the signature independently before publishing.


latest.txt appears stale

Remember that latest.txt is mutable release metadata.

The R2 synchronization intentionally uploads it with:

text
Cache-Control: no-store, must-revalidate

Verify:

  1. the local latest version
  2. the generated/uploaded latest.txt
  3. the R2 object
  4. the release directory
  5. the checksum/signature metadata

Avoid treating cached metadata as proof that the local release was not uploaded.


23. Operational Command Reference

Build

bash
make build

Build macOS arm64 MCPB

bash
make mcp-build-mac-arm64

Rotate signing key

bash
./scripts/release/rotate_signing_key.sh

Verify signing key

bash
./scripts/release/verify_release_signing_key.sh

Sign a release

bash
./scripts/release/sign_release.sh v1.1.3

Generate manifest

bash
python3 scripts/r2/generate_gitai_manifest.py

Synchronize to R2

bash
./scripts/r2/gitai_r2.sh

24. Normal Release Diagram


25. Key-Rotation Release Diagram


26. End-to-End Deployment Model


27. Final Release Principle

The release system follows one simple trust model:

text
BUILD
  ↓
HASH
  ↓
SIGN
  ↓
VERIFY
  ↓
PUBLISH

And for key rotation:

text
ROTATE
  ↓
UPDATE TRUST
  ↓
REBUILD MCPB
  ↓
REBUILD AOT
  ↓
SIGN
  ↓
VERIFY
  ↓
PUBLISH

The most important invariant is:

The public key embedded in the released verification code must match the private key used to sign the AOT release.

For the MCP release specifically:

After rotating the signing key, rebuild the MCPB before signing and publishing the AOT release with the new key.

This keeps the AOT installer, MCP server, release signatures, and R2 artifacts aligned.