GitHub Actions with Mentiko: CI/CD for Agent Chains
Mentiko Team
Your agent chain definitions are JSON files. They live in a git repo. They get reviewed in PRs. But if you're merging chain changes without validation, you're one typo away from a broken pipeline in production.
GitHub Actions lets you treat chain definitions like application code: lint them, test them, and deploy them automatically. Here's how to set that up with Mentiko.
What to validate
A chain definition can fail in several ways that aren't obvious until runtime:
- Malformed JSON (missing comma, unclosed bracket)
- Invalid event references (agent triggers on an event nobody emits)
- Circular dependencies (agent A triggers B, B triggers A)
- Missing variables (prompt references
{API_KEY}but no variable is defined) - Workspace configuration errors (referencing a Docker image that doesn't exist)
Catching these at PR time instead of runtime saves you from deploying chains that will fail on their first run.
Basic chain validation workflow
Create .github/workflows/chain-validation.yml:
name: Validate Chain Definitions
on:
pull_request:
paths:
- 'chains/**/*.json'
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Mentiko CLI
run: |
curl -fsSL https://mentiko.com/install.sh | bash
echo "$HOME/.mentiko/bin" >> $GITHUB_PATH
- name: Validate JSON syntax
run: |
for file in chains/**/*.json; do
echo "Validating $file..."
python3 -m json.tool "$file" > /dev/null
done
- name: Validate chain definitions
run: |
for file in chains/**/*.json; do
mentiko validate "$file"
done
- name: Check event graph
run: mentiko graph --check chains/
The workflow runs on every PR that touches files in the chains/ directory. Three validation stages:
- JSON syntax check -- catches structural errors before Mentiko even parses the file.
mentiko validate-- checks the chain definition against the schema. Validates agent names, trigger/emit declarations, retry configs, workspace references.mentiko graph --check-- builds the event dependency graph across all chains and checks for orphaned events, circular dependencies, and unreachable agents.
If any step fails, the PR gets a red check. The author fixes the issue before merging.
Dry-run testing
Validation catches structural problems. Dry runs catch logic problems. A dry run walks through the chain execution without actually calling any LLM providers -- it simulates the event flow and verifies that agents trigger in the expected order.
Add a dry-run job to your workflow:
dry-run:
runs-on: ubuntu-latest
needs: validate
steps:
- uses: actions/checkout@v4
- name: Install Mentiko CLI
run: |
curl -fsSL https://mentiko.com/install.sh | bash
echo "$HOME/.mentiko/bin" >> $GITHUB_PATH
- name: Dry run changed chains
run: |
# Get list of changed chain files
CHANGED=$(git diff --name-only origin/main -- 'chains/**/*.json')
for file in $CHANGED; do
echo "Dry running $file..."
mentiko run --dry-run "$file" \
--var TOPIC="test-input" \
--timeout 30s
done
The dry run validates the event flow without spending tokens. It confirms that:
- The chain starts correctly from
chain:start - Each agent's triggers resolve to events that actually get emitted
- The chain reaches
chain:complete(or a defined terminal state) - Timeout settings are respected
- Variable interpolation works with test values
The needs: validate dependency ensures dry runs only execute after basic validation passes.
Auto-deploy on merge
Once a chain change is validated and reviewed, deploy it automatically when the PR merges to main.
Create .github/workflows/deploy-chains.yml:
name: Deploy Chain Definitions
on:
push:
branches: [main]
paths:
- 'chains/**/*.json'
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy to Mentiko instance
env:
MENTIKO_HOST: ${{ secrets.MENTIKO_HOST }}
MENTIKO_API_KEY: ${{ secrets.MENTIKO_API_KEY }}
run: |
# Get changed files in this push
CHANGED=$(git diff --name-only HEAD~1 -- 'chains/**/*.json')
for file in $CHANGED; do
chain_name=$(basename "$file" .json)
echo "Deploying $chain_name..."
mentiko deploy "$file" \
--host "$MENTIKO_HOST" \
--api-key "$MENTIKO_API_KEY"
done
- name: Verify deployment
env:
MENTIKO_HOST: ${{ secrets.MENTIKO_HOST }}
MENTIKO_API_KEY: ${{ secrets.MENTIKO_API_KEY }}
run: |
CHANGED=$(git diff --name-only HEAD~1 -- 'chains/**/*.json')
for file in $CHANGED; do
chain_name=$(basename "$file" .json)
mentiko status "$chain_name" \
--host "$MENTIKO_HOST" \
--api-key "$MENTIKO_API_KEY"
done
Two GitHub secrets are required:
MENTIKO_HOST-- your Mentiko instance URL (e.g.,https://mentiko.yourcompany.comor a LAN IP like192.168.68.172:8082)MENTIKO_API_KEY-- an API key generated from your Mentiko dashboard with deploy permissions
The deploy step pushes updated chain definitions to your running instance. The verify step confirms each deployed chain is active and healthy.
Environment-specific chains
Production and staging often need different configurations -- different models, different retry thresholds, different variable values. Handle this with environment-specific overrides:
chains/
content-pipeline.json # base definition
overrides/
staging.content-pipeline.json # staging overrides
prod.content-pipeline.json # production overrides
The override files contain only the fields that differ:
{
"overrides": {
"agents.researcher.workspace": "docker-staging",
"agents.drafter.retry.max_attempts": 1,
"variables.MODEL": "gpt-4o-mini"
}
}
Your deploy workflow applies the right overrides per environment:
- name: Deploy with environment overrides
run: |
ENV="${{ github.ref == 'refs/heads/main' && 'prod' || 'staging' }}"
for file in chains/*.json; do
chain_name=$(basename "$file" .json)
override="chains/overrides/${ENV}.${chain_name}.json"
if [ -f "$override" ]; then
mentiko deploy "$file" --override "$override" \
--host "$MENTIKO_HOST" --api-key "$MENTIKO_API_KEY"
else
mentiko deploy "$file" \
--host "$MENTIKO_HOST" --api-key "$MENTIKO_API_KEY"
fi
done
The base chain definition stays identical across environments. Only the overrides change. This means your staging chain is structurally identical to production -- just with safer parameters for testing.
Scheduled chain health checks
Beyond deployment, use GitHub Actions to periodically verify your chains are healthy:
name: Chain Health Check
on:
schedule:
- cron: '0 */6 * * *' # Every 6 hours
jobs:
health-check:
runs-on: ubuntu-latest
steps:
- name: Check chain status
env:
MENTIKO_HOST: ${{ secrets.MENTIKO_HOST }}
MENTIKO_API_KEY: ${{ secrets.MENTIKO_API_KEY }}
run: |
mentiko health --host "$MENTIKO_HOST" \
--api-key "$MENTIKO_API_KEY" \
--format json > health.json
# Fail if any chain has error status
if jq -e '.chains[] | select(.status == "error")' health.json > /dev/null 2>&1; then
echo "Unhealthy chains detected:"
jq '.chains[] | select(.status == "error")' health.json
exit 1
fi
echo "All chains healthy."
A cron-scheduled workflow checks your Mentiko instance every 6 hours. If any chain is in an error state, the workflow fails and GitHub sends a notification. It's a lightweight monitoring layer that doesn't require any additional infrastructure.
PR comments with chain diff
For extra visibility during code review, add a step that posts a human-readable chain diff as a PR comment:
- name: Post chain diff
if: github.event_name == 'pull_request'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
DIFF=$(mentiko diff --base origin/main --head HEAD chains/)
if [ -n "$DIFF" ]; then
gh pr comment ${{ github.event.pull_request.number }} \
--body "### Chain Changes
$DIFF"
fi
mentiko diff produces a structured comparison: added agents, removed events, changed prompts, modified retry configs. Reviewers see exactly what changed in the chain without parsing raw JSON diffs.
What this gives you
With validation, dry runs, auto-deploy, and health checks in place, your chain management workflow looks like this:
- Developer creates a branch and modifies a chain definition
- PR triggers validation and dry-run tests
- Team reviews the PR with chain diff context
- PR merges, deploy workflow pushes to production
- Health check runs every 6 hours to verify chains stay healthy
The chain JSON is the source of truth. Git history shows every change. GitHub Actions ensures nothing broken reaches production. Your Mentiko instance always reflects what's in main.
Start with the validation workflow -- it catches the most common issues. Add dry runs and auto-deploy as your chain count grows. For more on versioning chain definitions, see Agent Chain Versioning with Git.
Get new posts in your inbox
No spam. Unsubscribe anytime.