Skip to content

block/madrigal

Madrigal

A config-driven, pluggable knowledge compiler. Madrigal transforms structured knowledge (markdown files with frontmatter) into normalized, schema-aware output formats - JSON bundles, AI skill files, rule sets, and more.

Inspired by Style Dictionary, Madrigal applies the same "define once, compile everywhere" philosophy to knowledge bases, research repositories, coding guidelines, design systems, and organizational rules. Consumers own the domain vocabulary; Madrigal owns reliable parsing, normalization, linting, and compilation.

Quick Start

npm install @anarchitecture/madrigal

Create a madrigal.config.yaml:

sources:
  - "knowledge/**/*.md"

schema:
  preserveUnknownFrontmatter: true
  id:
    field: id
    strategy: path
  kind:
    field: type
    default: record
    byPath:
      "knowledge/studies/**": study
  title:
    field: title
  relationships:
    wikilinks: true

kinds:
  study:
    required: [title, methodology, research_period, source_url]
  theme: {}

vocabularies:
  durability:
    values: [evergreen, timebound]

platforms:
  json-export:
    format: json-bundle

Create a knowledge file at knowledge/studies/checkout-trust.md:

---
title: Checkout Trust Study
type: study
methodology: Interviews
research_period: Q1
source_url: https://example.com/research
durability: evergreen
tags:
  - onboarding
---

Participants connected onboarding clarity to [[Trust Signals]].

Build programmatically:

import { build } from '@anarchitecture/madrigal';

const result = await build();

for (const output of result.results) {
  console.log(`${output.platform}: ${output.unitCount} units`);
  console.log(output.output);
}

Concepts

Knowledge Units

The atomic unit. Each .md file with frontmatter becomes a normalized KnowledgeUnit with an id, title, body, kind, tags, source path, raw frontmatter, normalized attributes, extracted relationships, and provenance tracking. Optional rule-oriented fields such as domain, brand, system, and enforcement are preserved when present.

Schema

Consumer-owned mapping rules that tell Madrigal how to read a knowledge base: where IDs, titles, kinds, and relationships come from, how path-based fallback should work, and whether unknown frontmatter should be preserved.

Kinds

Consumer-defined structural types (for example study, theme, competitor, or rule). Kinds can declare required fields for linting and strict validation.

Vocabularies

Consumer-owned controlled terms and aliases. Madrigal can canonicalize configured fields in attributes while preserving the raw parsed value in frontmatter.

Domains

Optional logical groupings of knowledge (e.g., accessibility, typography, layout). Defined in config and validated at load time when present.

Brands

Organizational units that can inherit from each other. A brand can include other brands/groups, and brand-specific knowledge overrides globals with the same id.

Enforcement

Optional rule-oriented strength: must, should, may, context, or deprecated. Existing severity frontmatter is still accepted as a legacy alias for rule-focused workflows.

Formats

Output compilers that transform knowledge units into specific formats. Four built-in formats are included:

Format Description
json-bundle Searchable JSON with metadata
skill-md Markdown skill file for AI agents
ai-rules-md Rule file for AI coding assistants
mesh-domain AI app-info mesh domain format

Platforms

Named build targets in config. Each platform specifies a format and optional grouping (brand, domain, or system).

Configuration Reference

# Glob patterns for knowledge source files
sources:
  - "knowledge/**/*.md"

# Schema mapping and normalization
schema:
  preserveUnknownFrontmatter: true
  id:
    field: id              # Explicit frontmatter ID field
    strategy: path         # path | filename
  kind:
    field: type            # Frontmatter field used as the unit kind
    default: record
    byPath:
      "knowledge/studies/**": study
  title:
    field: title
  relationships:
    wikilinks: true        # Extract [[Target]] and [[Target|Label]]

# Kind definitions and required fields
kinds:
  <name>:
    required:
      - title

# Controlled vocabularies and aliases
vocabularies:
  <field>:
    values:
      - canonical-value
    aliases:
      old-value: canonical-value

# Domain definitions
domains:
  <name>:
    description: "..."

# Brand definitions
brands:
  <name>:
    systems:        # Optional: associated design systems
      - web
    include:        # Optional: inherit from other brands
      - global

# Build targets
platforms:
  <name>:
    format: json-bundle    # Required: registered format name
    groupBy: brand         # Optional: brand | domain | system
    destination: out/      # Optional: output path

Knowledge File Format

---
title: Record Title          # Field name is configurable
id: custom-id                # Optional, generated from path by default
type: study                  # Field name is configurable
source_url: https://example.com/source
durability: evergreen        # Consumer-owned attribute
enforcement: should          # Optional for rule-oriented records
tags:
  - research
---

Markdown body content here, including optional [[Wiki Links]].

Plugin System

Custom Formats

import { defaultRegistry, type Format } from '@anarchitecture/madrigal';

const myFormat: Format = {
  name: 'custom-html',
  extension: '.html',
  compile(units, options) {
    return `<html>...</html>`;
  },
};

defaultRegistry.register(myFormat);

Custom Preprocessors

Preprocessors transform knowledge units after loading but before compilation:

import { defaultPreprocessorRegistry, type Preprocessor } from '@anarchitecture/madrigal';

const enricher: Preprocessor = {
  name: 'tag-enricher',
  async process(units, config) {
    return units.map(u => ({
      ...u,
      tags: [...u.tags, 'enriched'],
    }));
  },
};

defaultPreprocessorRegistry.register(enricher);

Adapter Interfaces

Madrigal exports StorageAdapter and SearchAdapter interfaces for implementing custom backends (databases, vector stores, etc.).

API

build(options?)

Run the full pipeline: load config, load knowledge, run preprocessors, compile all platforms.

loadConfig(path?)

Load and parse a madrigal.config.yaml file.

loadKnowledge(options)

Load knowledge units from markdown files matching source globs.

resolveForBrand(options)

Resolve knowledge units for a specific brand, applying inheritance and severity overrides.

validateConfig(config, formatNames?)

Validate a configuration object.

serveMcp(options?)

Start a stdio MCP server that exposes five tools for querying the knowledge base: search_knowledge, get_knowledge_unit, list_knowledge_units, get_brand_rules, review_content.

import { serveMcp } from '@anarchitecture/madrigal';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';

const baseDir = dirname(fileURLToPath(import.meta.url));

// Single bundle
await serveMcp({ baseDir, bundlePath: 'publish/to-artifactory/knowledge.json' });

// Multiple bundles merged into one index (for aggregator repos)
await serveMcp({
  baseDir,
  bundlePath: 'publish/to-artifactory/knowledge.json',
  bundlePaths: [
    resolve(baseDir, '../other-repo/publish/to-artifactory/knowledge.json'),
  ],
});

Save this as mcp-server.js at the repo root and register it in your MCP client config.

Skills Convention

Repos that use Madrigal should own their agent skills alongside their knowledge. Skills live in skills/{skill-name}/SKILL.md — always a named subdirectory, never at the repo root. This mirrors the local install path (~/.claude/skills/{name}/SKILL.md) so publishing is mechanical.

Single-skill repo:

skills/
  my-knowledge-base/
    SKILL.md

Multi-skill repo (e.g. one skill per brand or design system):

skills/
  arcade/
    SKILL.md
  market/
    SKILL.md

Skill files reference the MCP tools (search_knowledge, etc.) with domain-specific routing instructions. The repo team owns the skill — it is not generated by Madrigal.

To install a skill locally for development:

mkdir -p ~/.claude/skills/{skill-name}/
ln -sf "$(pwd)/skills/{skill-name}/SKILL.md" ~/.claude/skills/{skill-name}/SKILL.md

Release Workflow

Madrigal uses Changesets for versioning.

For a release-bearing change, run:

pnpm changeset

After the change lands on main, the Version Packages GitHub Actions workflow creates a version PR when changesets are pending. Merging to main does not publish Madrigal.

To publish a GitHub Release tarball, merge the version PR and push a matching tag:

VERSION=$(node -e "console.log(JSON.parse(require('fs').readFileSync('package.json', 'utf8')).version)")
git tag "anarchitecture-madrigal@$VERSION"
git push origin "anarchitecture-madrigal@$VERSION"

The Publish tarball to GitHub Release workflow can also be run manually with the package version from package.json.

Manual release commands are also available:

pnpm version-packages
pnpm release

Project Resources

Resource Description
CODEOWNERS Project lead(s)
GOVERNANCE.md Project governance
LICENSE Apache License, Version 2.0

About

design x ai orchestration

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors