Copy-paste-ready integrations for running Forge gates in CI.
Status of native fail flags.
forge certify --fail-under N— shipped. Exits 1 when score < N.forge wire --fail-on-violations— shipped (Lane G1). Exits 1 when any upward-import violation is found.Roadmap items still pending:
- Lane G2 — published
atomadictech/forge-actionGitHub Action.- Lane G5 — signed certificate output.
Until those land, the recipes below pair the native flags with a small
python -cfallback for fields the CLI doesn't yet gate on.
.github/workflows/forge-certify.yml:
name: forge-certify
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
certify:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install Forge
run: |
pip install atomadic-forge # PyPI (preferred)
# Or pin to the exact release you are validating:
# pip install "atomadic-forge==<release-version>"
# Or install from a tagged git ref:
# pip install "git+https://github.com/atomadictech/atomadic-forge@v<release-tag>"
# Or vendor wheels: pip install --no-index --find-links wheels/ atomadic-forge
- name: Wire scan (upward-import discipline)
run: |
# Native gate (Lane G1): non-zero exit on any violation.
forge wire src/your_package --fail-on-violations --json > wire.json
- name: Certify (gate at score >= 75)
run: |
# Native gate: --fail-under exits 1 below the threshold.
forge certify . --package your_package --fail-under 75 --json > certify.json
python -c "import json; r=json.load(open('certify.json')); \
print(f\"forge certify score: {r.get('total_score', r.get('score', 0))}/100\")"
- name: Upload reports
if: always()
uses: actions/upload-artifact@v4
with:
name: forge-reports
path: |
wire.json
certify.json
.atomadic-forge/What this does:
forge wire --jsonis parsed forverdict == "PASS". Anything else fails the job.forge certify --jsonis parsed fortotal_score. Below 75 fails the job. Adjust the threshold to match your team's policy.- Both reports plus the full
.atomadic-forge/provenance directory are uploaded as build artifacts so reviewers can inspect them on the PR.
.gitlab-ci.yml:
stages:
- certify
forge-certify:
stage: certify
image: python:3.11-slim
timeout: 10 minutes
before_script:
- pip install atomadic-forge
script:
- forge wire src/your_package --fail-on-violations --json > wire.json
- forge certify . --package your_package --fail-under 75 --json > certify.json
- |
python -c "import json,sys; r=json.load(open('certify.json')); \
s=r.get('total_score',0); \
print(f'forge certify score: {s}/100'); \
sys.exit(0 if s >= 75 else 1)"
artifacts:
when: always
expire_in: 1 week
paths:
- wire.json
- certify.json
- .atomadic-forge/
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCHSame shape as the Actions workflow: install, wire, certify, fail on threshold, upload artifacts.
For local-developer guard rails, expose Forge as a pre-commit hook.
Forge ships a pre-commit-hooks.yaml you can publish from this
repo. The shape is:
.pre-commit-hooks.yaml (in this repo):
- id: forge-wire
name: forge wire (upward-import discipline)
description: Scan src/ for upward imports; fails the hook on any violation.
entry: forge wire
language: system
pass_filenames: false
args: [src, --fail-on-violations]
stages: [pre-commit, pre-push]
- id: forge-certify
name: forge certify (architecture conformance)
description: Score architecture conformance; fails below the threshold.
entry: forge certify
language: system
pass_filenames: false
args: [., --fail-under, "75"]
stages: [pre-push]Then in the consuming repo's .pre-commit-config.yaml:
repos:
- repo: https://github.com/atomadictech/atomadic-forge
rev: <release-tag>
hooks:
- id: forge-wire
- id: forge-certifyThe first file lives in this repo (Forge); the second is what your
users add to their repo. Run pre-commit install once and the gates
fire on every commit / push.
Replace <release-tag> with the exact Forge release you want the hook
consumer to install. Avoid copying stale historical pins forward.
Note:
forge certifyis heavier thanforge wire. The hook above runswireon every commit andcertifyonly on push, which is the right tradeoff for most teams. Adjust thestages:list if your workflow differs.
If you author MCP tools, recipes, or schema versions on a fork of
Forge, the canonical surface.json artifact at the repo root must
stay synchronized with the in-code registries. The
surface-drift.yml workflow gates this:
.github/workflows/surface-drift.yml:
name: surface-drift
on:
pull_request:
paths:
- "src/atomadic_forge/a0_qk_constants/**"
- "src/atomadic_forge/a1_at_functions/mcp_protocol.py"
- "src/atomadic_forge/a3_og_features/recipe_*.py"
- "src/atomadic_forge/a3_og_features/surface_export.py"
- "surface.json"
jobs:
surface-drift:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- run: pip install -e ".[dev]"
- name: Surface drift check
run: forge surface checkOn drift: the job exits 1 with a one-line fix-up command:
forge surface emit --out surface.json && git add surface.jsonThe generated_at_utc timestamp is excluded from the comparison so
re-emitting on unchanged inputs always passes.
For consumer projects (sites, badge workers, agent platforms), fetch
surface.json directly from the GitHub raw URL or pin to a release
tag — never hand-maintain a tool/recipe map locally.
The forge verify response now includes a wisdom_capture_prompt
field when trust thresholds are met (≥3 lineage events, ≥1.0 score
delta, or ≥5-minute session). For long-running CI runs that produce
real lessons, you can wire this into a post-merge job:
- name: Verify + capture wisdom (post-merge only)
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
run: |
forge verify --json > verify.json
PROMPT=$(python -c "import json; r=json.load(open('verify.json')); print(r.get('wisdom_capture_prompt', {}).get('next_command', ''))")
if [ -n "$PROMPT" ]; then
echo "Captured wisdom: $PROMPT"
eval "$PROMPT"
git add .atomadic-forge/wisdom.jsonl
git commit -m "wisdom: capture from CI run ${{ github.sha }}" || true
git push origin main || true
fiThis is opt-in. Most consumer CI runs don't generate enough novel signal to justify a wisdom record (the threshold gate exists exactly to suppress noise). Use it on the Forge repo itself or on long-lived systems where institutional memory survives team rotation.
- Lane G1 — ✅ shipped.
forge certify --fail-under Nandforge wire --fail-on-violationsare now the canonical CI gates. Earlierpython -cworkarounds for these specific gates can be removed; the recipes above already use the native flags. The currentpython -cworkaround is intentionally explicit so the semantics survive the migration. - Lane G2 —
atomadictech/forge-actionGitHub Action. Once published, the GitHub Actions workflow above becomesuses: atomadictech/forge-action@v1. - Lane G5 — cryptographically signed certify reports. The schema is finalized; signing is not yet wired. Today, treat the JSON as authoritative-but-unsigned.
When those land, this page will be updated and the manual recipes will be marked legacy (not deleted — a few teams will want to keep the unsigned, dependency-free path).