← Back to Blog
April 2026

Nexa Skill Compiler:
From Prototype to Working Compiler

By Yipeng Ouyang · April 16, 2026

Setting Up the Workspace

April 3, 2026. The project — then called Nexa Skill Compiler (NSC) — began with a Rust workspace. Three crates: nexa-skill-core for the compilation pipeline, nexa-skill-cli for the command-line interface, and nexa-skill-templates for Askama-based code generation.

The technology choices were deliberate. pulldown-cmark for Markdown event-stream parsing. serde + serde_yaml for frontmatter extraction. miette for beautiful diagnostic rendering. askama for compile-time-validated Jinja2 templates. Each dependency was chosen for its alignment with the compiler's design philosophy: type safety, zero-cost abstraction, and compile-time guarantees.

Building the IR Layer

The heart of any compiler is its intermediate representation. We designed SkillIR — later renamed SkIR — as a strongly-typed struct with 25+ fields, organized into semantic categories:

  • Metadata & Routing: name, version, description
  • Interfaces & MCP: mcp_servers, input_schema, output_schema
  • Security & Control: hitl_required, permissions, security_level, anti_skill_constraints
  • Execution Logic: procedures, approaches, mode, few_shot_examples
  • AST Optimization Flags: requires_yaml_optimization, nested_data_depth

Every string field used Arc for zero-copy sharing across compilation phases and target emitters. This wasn't premature optimization — it was architectural necessity for a compiler that needed to process hundreds of skills with sub-10ms latency.

Design Decision: SkIR abstracts what a skill means, not how it's formatted. This is the key architectural property that enables O(m+n) complexity — m skills pass through the shared frontend once, and n emitters consume the same optimized IR.

Multi-Strategy Procedure Extraction

One of the hardest problems was parsing real-world SKILL.md files. Community skills use wildly different structures — some use ordered lists, others use heading hierarchies, still others use phase-based sections. A single parsing strategy would fail on most real inputs.

We implemented 6 extraction strategies with automatic routing based on SectionKind classification:

  • Heading-based: Extract steps from numbered headings
  • List-based: Parse ordered/unordered list items as steps
  • Phase-based: Treat sequential sections as execution phases
  • Mode-selector: Identify alternative approaches under a mode selector
  • Reference-based: Extract operations from reference sections
  • Body-segmentation: Fallback — treat entire body as a single procedure

Anti-Skill Injection

April 13. The security optimizer came together. Four anti-pattern rules, each with trigger keywords and injected constraints:

  • HTTP Safety: Detects HTTP/GET/POST/fetch → injects timeout and retry constraints
  • Loop Safety: Detects while/loop/repeat → injects max iteration limits
  • DB Safety: Detects DROP/DELETE/TRUNCATE → requires user confirmation
  • Parse Safety: Detects BeautifulSoup/HTML parse → prevents unsafe parsing patterns

The key insight: safety constraints should be a property of the compilation process, not of individual author diligence. By operating at the IR level, injected constraints survive format translation and appear consistently across all target frameworks.

First Experiments

By April 16, we had a working compiler. 206 unit tests passing. 32 of 34 real-world skills compiling successfully (2 correctly blocked by security validation). The first SkillsBench experiments showed promising results: compiled skills outperformed format-agnostic baselines across all four frameworks.

The project was ready for its final form. But first, it needed a name that would stick.