Metaprogramming Roadmap

Code that writes code. A unified approach to generating CLI commands, documentation, configurations, and policies from single sources of truth.

The Realization

You’re already metaprogramming - instinctively. This roadmap makes it intentional.

Current Metaprogramming (Already Doing)

Project Pattern What It Does

Antora attributes

Data → Docs

{ise-01-ip} renders in 255+ pages from one definition

Antora partials

Fragment → Full page

Single table partial, included in many pages

netapi CLI

Schema → Commands

ISE OpenAPI introspection → CLI commands

Jinja2 templates

Data + Template → Config

YAML variables → switch/firewall configs

dsec

Encrypted data → Environment

.env.age$ISE_USER, $ISE_PASS

Terraform

HCL → Infrastructure

Declarative specs → VMs, DNS, policies

Vision: One Truth, Infinite Outputs

                    ┌─────────────────┐
                    │   YAML Schema   │
                    │  (Single Truth) │
                    └────────┬────────┘
                             │
         ┌───────────────────┼───────────────────┐
         │                   │                   │
         ▼                   ▼                   ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│  CLI Commands   │ │  Documentation  │ │  Configurations │
│    (netapi)     │ │    (Antora)     │ │ (switches, FW)  │
└─────────────────┘ └─────────────────┘ └─────────────────┘
         │                   │                   │
         ▼                   ▼                   ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│  ISE Policies   │ │  Ansible Inv.   │ │  Terraform TF   │
└─────────────────┘ └─────────────────┘ └─────────────────┘

Phase 1: Infrastructure Schema

Goal: Single YAML file defines all infrastructure, generates everything else.

1.1 Schema Design

# infrastructure.yml - THE source of truth
domain: inside.domusdigitalis.dev

hosts:
  vault-01:
    ip: 10.50.1.60
    mac: "aa:bb:cc:dd:ee:f1"
    roles: [pki, ssh-ca, secrets]
    os: rocky-9
    location: kvm-01

  ise-01:
    ip: 10.50.1.20
    roles: [radius, admin, mnt, psn]
    os: ise-3.4

  k3s-master-01:
    ip: 10.50.1.120
    roles: [k3s-control-plane]
    os: rocky-9

vlans:
  mgmt:
    id: 100
    subnet: 10.50.1.0/24
    gateway: 10.50.1.1
  data:
    id: 10
    subnet: 10.50.10.0/24

1.2 Generators

Generator Input Output

gen-antora-attrs

infrastructure.yml

antora.yml attributes section

gen-ansible-inventory

infrastructure.yml

inventory.yml for Ansible

gen-dns-records

infrastructure.yml

BIND DNS zone record commands

gen-terraform-vars

infrastructure.yml

variables.tf definitions

gen-docs-tables

infrastructure.yml

AsciiDoc partials (IP tables, host lists)

1.3 Implementation

# domus-metagen/generators/antora.py
import yaml
from jinja2 import Template

def generate_antora_attributes(infra_file: str) -> str:
    """Generate Antora attributes from infrastructure schema."""
    with open(infra_file) as f:
        infra = yaml.safe_load(f)

    attrs = []
    for hostname, host in infra['hosts'].items():
        attrs.append(f"    {hostname}-ip: {host['ip']}")
        attrs.append(f"    {hostname}-hostname: {hostname}.{infra['domain']}")

    return "\n".join(attrs)

Phase 2: OpenAPI → CLI Generation

Goal: Auto-generate 100% of netapi commands from OpenAPI/Swagger specs.

2.1 Current State

netapi has ~60% ISE ERS coverage, manually written.

2.2 Target State

# Read OpenAPI spec, generate Click commands
from openapi_parser import parse

spec = parse("ise-ers-openapi.json")

for path, methods in spec.paths.items():
    for method, operation in methods.items():
        generate_click_command(
            name=operation.operation_id,
            method=method,
            path=path,
            params=operation.parameters,
            body=operation.request_body
        )

2.3 Benefits

  • 100% API coverage automatically

  • Self-documenting from OpenAPI descriptions

  • Version tracking - regenerate when API changes

  • Less code to maintain - generator, not commands

Phase 3: Policy as Code

Goal: Define ISE policies in YAML, generate API calls.

3.1 Policy Schema

# policies/linux-eaptls.yml
policy_set: Wired_802.1X_Closed

authorization_rules:
  - name: Linux-AD-Auth-Full-Access
    rank: 1
    conditions:
      - type: certificate
        attribute: Subject-CN
        matches: "*.inside.domusdigitalis.dev"
      - type: ad_group
        name: GRP-Linux-Computers
    result:
      profile: Linux-Full-Access
      dacl: DACL-Linux-AD-Auth

  - name: Linux-Onboarding
    rank: 2
    conditions:
      - type: authentication_method
        equals: MAB
    result:
      profile: Linux-Onboarding
      dacl: DACL-Linux-Onboard

dacls:
  DACL-Linux-AD-Auth:
    rules:
      - permit tcp any host {ad-dc-ip} eq 88
      - permit tcp any host {ad-dc-ip} eq 389
      - permit udp any host {ad-dc-ip} eq 53
      - deny ip any any

3.2 Generator

# Generate ISE API calls from policy YAML
domus-metagen policy apply policies/linux-eaptls.yml

# Output:
# Creating dACL: DACL-Linux-AD-Auth
# netapi ise ers dacl-create --name DACL-Linux-AD-Auth --content "permit tcp..."
# Creating authorization rule: Linux-AD-Auth-Full-Access
# netapi ise policy authz-rule-create --policy-set Wired_802.1X_Closed ...

Phase 4: Executable Documentation

Goal: Runbooks contain code that can be extracted and run.

4.1 Tagged Code Blocks

// In runbook.adoc
[source,bash,tag=verify-ise-sessions]

netapi ise mnt sessions | jq '.[] | {mac, status, policy}'


4.2 Extractor

# Extract tagged code blocks from AsciiDoc
def extract_runnable_blocks(adoc_file: str) -> dict:
    blocks = {}
    for block in parse_code_blocks(adoc_file):
        if block.tag:
            blocks[block.tag] = block.content
    return blocks

# Usage
blocks = extract_runnable_blocks("k3s-deployment.adoc")
run(blocks["verify-ise-sessions"])

4.3 Runbook CLI

# Run a specific step from a runbook
domus-run infra-ops::runbooks/k3s-deployment.adoc --step verify-cilium

# List available steps
domus-run infra-ops::runbooks/k3s-deployment.adoc --list

Phase 5: The Meta-Platform

Goal: domus-metagen - unified generator toolkit.

5.1 Project Structure

domus-metagen/
├── schemas/
│   ├── infrastructure.yml      # Host/network definitions
│   ├── policies/               # ISE policy definitions
│   └── services/               # Service configurations
├── generators/
│   ├── antora.py               # Generate Antora attributes
│   ├── ansible.py              # Generate Ansible inventory
│   ├── terraform.py            # Generate Terraform vars
│   ├── dns.py                  # Generate DNS records
│   ├── cli.py                  # Generate netapi commands
│   └── policy.py               # Generate ISE policies
├── templates/
│   ├── antora.yml.j2
│   ├── inventory.yml.j2
│   └── partial-table.adoc.j2
└── cli.py                      # Main CLI entry point

5.2 Usage

# Generate everything from schema
domus-metagen generate all

# Generate specific outputs
domus-metagen generate antora-attrs
domus-metagen generate ansible-inventory
domus-metagen generate dns-records

# Apply policies
domus-metagen policy apply policies/linux-eaptls.yml

# Validate schema
domus-metagen validate schemas/infrastructure.yml

Diagnostic Commands Reference

Commands used for metaprogramming-style debugging:

# Print specific line range with numbers
awk 'NR>=950 && NR<=970 {print NR": "$0}' file.adoc

# Find patterns in backticks
grep -n '`[^`]*|[^`]*`' file.adoc

# Extract all code blocks from AsciiDoc
awk '/^\[source,bash\]/,/^----$/' runbook.adoc

# Generate attribute list from grep
grep -h "^    [a-z-]*-ip:" */antora.yml | sort -u

# Count patterns across repos
for repo in domus-*/; do
  echo "=== $repo ==="
  grep -c "xref:" "$repo/docs"/**/*.adoc 2>/dev/null | awk -F: '{sum+=$2} END {print sum}'
done

Reading List

  • The Pragmatic Programmer - "Don’t Repeat Yourself" principle

  • Structure and Interpretation of Computer Programs - Lisp metaprogramming

  • Metaprogramming Ruby - Even if not Ruby, concepts transfer

  • Domain-Specific Languages by Martin Fowler