Axiom Graph Engine
The axiom module is Spry’s core engine that transforms markdown documents into executable, queryable graphs. Think of it as the translator between your markdown runbooks and Spry’s execution system—it reads your markdown structure and converts it into a network of interconnected nodes that can be analyzed, filtered, and executed.
What Problem Does Axiom Solve?
Section titled “What Problem Does Axiom Solve?”When you write a runbook in markdown, you’re creating:
- Hierarchical structure (headings and sections)
- Executable code blocks (tasks)
- Dependencies between tasks
- Metadata and configuration
Axiom takes all of this and creates a directed graph where:
- Every element (heading, code block, paragraph) becomes a node
- Relationships (containment, dependencies) become edges
- The entire document becomes queryable and executable
This graph representation enables Spry to:
- Execute tasks in the correct order based on dependencies
- Filter and select specific parts of your runbook
- Generate different views (tree, runbook, custom)
- Validate document structure and rules
Directory Structure
Section titled “Directory Structure”lib/axiom/├── edge/ # Graph edge rules - define how nodes connect│ └── rule/ # Individual classification rules├── fixture/ # Test fixtures for development├── io/ # Input/output handling for resources├── mdast/ # Markdown Abstract Syntax Tree utilities├── projection/ # Different views of the same graph├── remark/ # Remark plugin integration for parsing├── text-ui/ # Terminal/CLI interfaces├── web-ui/ # Web-based interfaces├── graph.ts # Core graph data structures└── mod.ts # Public module exportsCore Concepts
Section titled “Core Concepts”1. Graph Structure
Section titled “1. Graph Structure”At its heart, axiom represents your markdown as a directed graph:
Markdown Document:# Deploy Application## Prerequisites```bash task setupnpm install```## Deploy```bash task deploy --depends setupnpm run deploy```
Becomes Graph:┌─────────────────┐│ Deploy App (h1) │└────────┬────────┘ │ contained-in ┌────┴────┬────────────┐ │ │ │┌───▼────┐ ┌──▼────┐ ┌───▼────┐│ Prereq │ │ setup │ │ deploy ││ (h2) │ │ task │ │ task │└────────┘ └───────┘ └───┬────┘ │ depends └────────→ setupKey Types:
interface GraphNode { id: string; // Unique identifier type: string; // 'heading', 'code', 'paragraph', etc. data: unknown; // Node-specific data edges: GraphEdge[]; // Outgoing connections}
interface GraphEdge { type: string; // 'contained-in', 'depends', etc. target: string; // Target node ID}Building a graph:
import { buildGraph } from "./graph.ts";
const markdownSource = `# My Runbook## Task 1\`\`\`bash task1echo "First task"\`\`\``;
const graph = await buildGraph(markdownSource);// graph now contains nodes and edges representing the document2. Edge Rules
Section titled “2. Edge Rules”Edge rules are the intelligence that determines how nodes connect. Each rule examines the document and creates specific types of edges.
| Rule | Purpose | Example |
|---|---|---|
contained-in-heading | Creates parent-child relationships based on heading hierarchy | H2 is contained in H1 |
contained-in-section | Groups content within sections | Code blocks belong to their section |
frontmatter-classification | Parses YAML frontmatter at document top | Extracts metadata, tags, config |
node-dependency | Resolves --depends flags in tasks | task2 --depends task1 creates edge |
nodes-classification | Classifies nodes by type | Marks code blocks as ‘task’ vs ‘content’ |
governance | Validates document structure | Ensures required sections exist |
section-frontmatter | Parses section-level metadata | Configuration per section |
Example of how rules work:
---project: my-app---
# Setup```bash install --depends check-envnpm install```
# Deploy```bash deploy --depends installnpm run deploy```Rules create:
- frontmatter-classification: Extracts
project: my-app - contained-in-heading: Links tasks to their headings
- nodes-classification: Marks code blocks as tasks
- node-dependency: Creates edges:
install → check-env,deploy → install
3. Projections
Section titled “3. Projections”A projection is a specific view or representation of the graph optimized for different purposes. The same graph can be projected multiple ways.
| Projection | Purpose | Use Case |
|---|---|---|
runbook | Task execution view with dependencies | Running tasks in correct order |
tree | Hierarchical tree structure | Displaying document outline |
flexible | Customizable projection | Building custom views/filters |
tree-text | Text-based tree rendering | CLI display of structure |
Example: Runbook Projection
Section titled “Example: Runbook Projection”import { runbookProjection } from "./projection/runbook.ts";
const tasks = runbookProjection(graph);
// tasks is now an array of executable task objectsfor (const task of tasks) { console.log(`Task: ${task.identity}`); console.log(` Dependencies: ${task.dependencies.join(", ")}`); console.log(` Command: ${task.command}`);}
// Output:// Task: install// Dependencies: check-env// Command: npm install// Task: deploy// Dependencies: install// Command: npm run deployExample: Tree Projection
Section titled “Example: Tree Projection”import { treeProjection } from "./projection/tree.ts";
const tree = treeProjection(graph);
// Render as hierarchical structure// Setup// └─ install [task]// Deploy// └─ deploy [task]Module Organization
Section titled “Module Organization”Core Files
Section titled “Core Files”graph.ts
Section titled “graph.ts”The foundation of axiom. Defines the graph data structure and provides the main buildGraph() function that orchestrates the entire parsing pipeline.
Key exports:
buildGraph(markdown: string): Promise<Graph>- Graph and Node type definitions
- Edge type definitions
mod.ts
Section titled “mod.ts”Public API exports. This is what other modules import from axiom.
Subdirectories
Section titled “Subdirectories”edge/rule/
Section titled “edge/rule/”Contains individual rule implementations. Each file is a self-contained rule that knows how to create one type of edge.
| File | What It Does |
|---|---|
contained-in-heading.ts | Links content to their parent headings (H2 under H1, H3 under H2) |
contained-in-section.ts | Groups all content within document sections |
frontmatter-classification.ts | Extracts and parses YAML frontmatter at document start |
governance.ts | Validates document structure meets requirements |
node-dependency.ts | Parses --depends flags and creates dependency edges |
nodes-classification.ts | Determines node types (task, content, metadata) |
section-frontmatter.ts | Handles section-specific metadata blocks |
section-semantic-id.ts | Generates human-readable IDs for sections |
selected-nodes-classification.ts | Filters nodes based on classification criteria |
mdast/
Section titled “mdast/”Utilities for working with Markdown Abstract Syntax Trees (MDAST). These are helper functions that extract information from AST nodes.
| File | Purpose |
|---|---|
code-frontmatter.ts | Extracts frontmatter from code block info strings |
data-bag.ts | Provides metadata storage for nodes |
node-content.ts | Gets textual content from any node type |
node-issues.ts | Tracks validation issues and warnings |
node-src-text.ts | Retrieves original source text |
statistics.ts | Calculates document statistics (word count, task count) |
projection/
Section titled “projection/”Different ways to view and traverse the graph.
| File | Creates |
|---|---|
runbook.ts | Execution-ready task list with dependency order |
tree.ts | Generic hierarchical tree structure |
tree-text.ts | ASCII/Unicode text rendering of trees |
flexible.ts | Base for custom projection implementations |
remark/
Section titled “remark/”Integration with the Remark markdown processor. These are plugins that run during parsing.
| File | Handles |
|---|---|
code-directive-candidates.ts | Identifies code blocks that are directives |
doc-frontmatter.ts | Processes document-level frontmatter |
import-placeholders-generator.ts | Creates placeholders for external imports |
import-specs-resolver.ts | Resolves and loads external markdown files |
node-decorator.ts | Adds metadata and IDs to nodes during parsing |
spawnable-code-candidates.ts | Marks code blocks that can be executed |
text-ui/
Section titled “text-ui/”Command-line interfaces for interacting with graphs.
| File | Provides |
|---|---|
cli.ts | Axiom graph viewer CLI tool |
runbook.ts | Main runbook execution CLI |
Input/output abstractions for reading resources.
Complete Usage Examples
Section titled “Complete Usage Examples”Example 1: Building and Querying a Graph
Section titled “Example 1: Building and Querying a Graph”import { MarkdownDoc } from "../markdown/fluent-doc.ts";import { buildGraph } from "./graph.ts";import { visit } from "unist-util-visit";
// Create markdown programmaticallyconst doc = new MarkdownDoc();doc.h1("Database Migration");doc.h2("Backup");doc.codeTag("bash backup --descr 'Backup database'")` pg_dump mydb > backup.sql`;doc.h2("Migrate");doc.codeTag("bash migrate --depends backup")` ./run-migrations.sh`;
// Build the graphconst graph = await buildGraph(doc.write());
// Query: Find all tasksconst tasks: string[] = [];visit(graph.ast, "code", (node) => { if (node.meta?.includes("task")) { tasks.push(node.lang + " task"); }});
console.log("Found tasks:", tasks);// Output: Found tasks: ['bash task', 'bash task']Example 2: Executing Tasks in Dependency Order
Section titled “Example 2: Executing Tasks in Dependency Order”import { buildGraph } from "./graph.ts";import { runbookProjection } from "./projection/runbook.ts";import { executionPlan } from "../universal/task.ts";
const markdown = `# Deployment Pipeline
\`\`\`bash buildnpm run build\`\`\`
\`\`\`bash test --depends buildnpm test\`\`\`
\`\`\`bash deploy --depends test./deploy.sh\`\`\``;
// Build graphconst graph = await buildGraph(markdown);
// Get task projectionconst tasks = runbookProjection(graph);
// Generate execution plan (topological sort by dependencies)const plan = executionPlan(tasks);
// Execute in orderfor (const task of plan) { console.log(`Executing: ${task.identity}`); // await executeTasks([task], state);}
// Output:// Executing: build// Executing: test// Executing: deployExample 3: Filtering Tasks with CQL
Section titled “Example 3: Filtering Tasks with CQL”import { buildGraph } from "./graph.ts";import { runbookProjection } from "./projection/runbook.ts";import { compileCqlMini } from "../markdown/notebook/cql.ts";
const graph = await buildGraph(myMarkdown);const tasks = runbookProjection(graph);
// Create filter: only bash tasks with tag "deploy"const filter = compileCqlMini("lang=bash AND tag=deploy");const deployTasks = filter(tasks);
console.log("Deploy tasks:", deployTasks.map(t => t.identity));Integration with Other Modules
Section titled “Integration with Other Modules”With markdown/
Section titled “With markdown/”Axiom uses markdown utilities for parsing and querying:
import { compileCqlMini } from "../markdown/notebook/cql.ts";
const filter = compileCqlMini("lang=python");const pythonTasks = filter(tasks);With task/
Section titled “With task/”Task execution leverages axiom’s dependency graph:
import { executeTasks } from "../task/mod.ts";import { executionPlan } from "../universal/task.ts";
const plan = executionPlan(runbookTasks);await executeTasks(plan, executionState);With sqlpage/
Section titled “With sqlpage/”Web interfaces can render axiom graphs:
import { SqlPagePlaybook } from "../sqlpage/playbook.ts";
const playbook = SqlPagePlaybook.instance(project);const webFiles = playbook.sqlPageFiles({ mdSources: ["Spryfile.md"]});With interpolate/
Section titled “With interpolate/”Template interpolation works with axiom’s parsed structure:
import { runbookProjection } from "./projection/runbook.ts";
const tasks = runbookProjection(graph);// Tasks contain interpolated values from environmentTesting
Section titled “Testing”# Run all axiom testsdeno test lib/axiom/
# Run specific component testsdeno test lib/axiom/graph_test.tsdeno test lib/axiom/projection/
# Run with coveragedeno test --coverage=coverage/ lib/axiom/deno coverage coverage/Key Takeaways
Section titled “Key Takeaways”- Axiom is a transformer: Markdown → Graph → Executable structure
- Rules define relationships: Edge rules create the intelligence in the graph
- Projections enable flexibility: One graph, many views for different purposes
- Integration is key: Axiom connects markdown authoring to task execution