skills/devops/build-ci-migration-assistant/SKILL.md
Assists migrating a build or CI pipeline from one system to another — Jenkins to GitHub Actions, Travis to GitLab CI, Makefile to Bazel — preserving semantics and surfacing untranslatable constructs. Use when switching CI providers, when modernizing a legacy build, or when the user pastes a Jenkinsfile and asks for the GitHub Actions equivalent.
npx skillsauth add santosomar/general-secure-coding-agent-skills build-ci-migration-assistantInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Migrating CI is a translation problem with losses. Every CI system has the same core (stages, steps, artifacts, conditions) and each has idioms that don't translate cleanly. The job is to translate what maps, and flag what doesn't.
All CI systems implement these. Translate via the concept, not the syntax:
| Concept | Jenkins | GitHub Actions | GitLab CI | CircleCI |
| --------------------- | ----------------------------- | ----------------------------- | -------------------------- | ------------------------ |
| Pipeline file | Jenkinsfile | .github/workflows/*.yml | .gitlab-ci.yml | .circleci/config.yml |
| Unit of parallelism | stage / parallel | job | job (in stage) | job |
| Sequential grouping | stage | needs: | stage: | requires: |
| Reusable fragment | Shared library, load() | Composite action / reusable workflow | extends: / include: | Orb / command |
| Run on | agent { label } | runs-on: | tags: | executor: |
| Conditional | when { ... } | if: | rules: | when: (filter) |
| Env var | environment { } | env: | variables: | environment: |
| Secret | credentials() | ${{ secrets.X }} | CI/CD variables (masked) | Context |
| Artifact hand-off | stash/unstash, archiveArtifacts | upload-artifact / download-artifact | artifacts: | persist_to_workspace |
| Cache | Plugin-dependent | actions/cache | cache: | save_cache/restore_cache |
| Trigger | triggers { } / webhooks | on: | rules: / workflow: | triggers: (filters) |
Before writing any target syntax, draw the DAG: what runs, what depends on what, what runs in parallel. This is the invariant. Syntax changes; the graph doesn't.
┌─ lint ──┐
checkout ──▶├─ test ──┤──▶ build ──▶ deploy-staging ──▶ deploy-prod
└─ audit ─┘
For each node in the graph, map the source construct → concept → target construct. Most steps are just shell commands inside a wrapper — those translate 1:1.
Things that do not map cleanly — inventory and escalate:
| Source feature | Why it doesn't translate | What to do |
| ----------------------------------------------- | ------------------------------------------------- | --------------------------------------------- |
| Jenkins input step (human prompt mid-pipeline)| GHA/GitLab don't pause for input | Split into two workflows, use environment approvals |
| Jenkins Groovy shared libraries | Arbitrary code, not declarative | Rewrite as composite actions / scripts; may need refactoring |
| Self-hosted agent with local state | Cloud runners are ephemeral | Move state to a cache or artifact |
| Implicit workspace sharing between stages | GHA jobs get fresh filesystems | Explicit upload-artifact/download-artifact |
| Polling triggers (pollSCM) | Push-based systems don't poll | Use webhook triggers (on: push) — usually what you wanted anyway |
| Jenkins post { always/failure/success } | GHA has if: always() per step, not per stage block | Duplicate the post-step on each job with if: guards |
Source (Jenkinsfile):
pipeline {
agent any
stages {
stage('Test') {
steps { sh 'npm ci && npm test' }
}
stage('Build') {
when { branch 'main' }
steps {
sh 'npm run build'
archiveArtifacts artifacts: 'dist/**'
}
}
}
post {
failure { slackSend channel: '#ci', message: "Build failed: ${env.BUILD_URL}" }
}
}
DAG: Test → Build (main only), plus a failure notification.
Target (GitHub Actions):
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm test
build:
needs: test
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
notify-failure:
needs: [test, build]
if: failure()
runs-on: ubuntu-latest
steps:
- run: |
curl -X POST ${{ secrets.SLACK_WEBHOOK }} \
-d '{"text":"Build failed: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"}'
Flagged: The post { failure } became a separate job — Jenkins runs post in the same agent with the workspace intact; here it's a fresh runner. If the Slack message needed build artifacts, they'd have to be uploaded first. Also: npm ci runs twice now (once per job — fresh filesystems). Could consolidate test+build into one job, or cache node_modules.
stage is not always a job.## Dependency graph (extracted)
<ascii dag>
## Translated pipeline
<target file path>
<code block>
## Untranslated / degraded
| Source construct | Issue | Proposed workaround |
| ... | ... | ... |
## Verification plan
- Run both pipelines on the same commit; diff: <what to compare>
development
Extracts human-readable pseudocode from a verified formal artifact (Dafny, Lean, TLA+) while preserving the verified properties as annotations, so the proof-carrying logic can be reimplemented in a production language. Use when porting verified code to an unverified target, when documenting what a formal spec actually does, or when handing a verified algorithm to an implementer.
development
Translates natural-language or pseudocode descriptions of concurrent and distributed systems into TLA+ specifications ready for the TLC model checker. Identifies state variables, actions, type invariants, safety properties, and liveness properties from the description. Use when formalizing a protocol, when the user describes a distributed algorithm to verify, when designing a consensus or locking scheme, or when starting formal verification of a concurrent system.
testing
Reduces a TLA+ model so TLC can actually check it — shrinks constants, adds state constraints, abstracts data, or applies symmetry — when the state space is too large to enumerate. Use when TLC runs out of memory, when checking takes hours, or when a spec works at N=2 and you need confidence at larger scale.
development
TLA+-specific instance of model-guided repair — reads a TLC error trace, identifies the enabling condition that should have been false, strengthens the corresponding action, and maps the fix to source code. Use when TLC reports an invariant violation or deadlock and you have the code-to-TLA+ mapping from extraction.