Skip to content

About

code generators

Resources

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

 

History

546 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ontogen CI License: MIT

A build-time code generator for ontology-driven Rust applications. Define your entities with annotated structs and Ontogen generates the full stack: persistence layer, CRUD store with lifecycle hooks, API forwarding, server transports (HTTP/IPC/MCP), and client libraries.

How It Works

Ontogen runs as a library in your build.rs. It parses #[ontology(...)] annotations on your structs and generates code through a pipeline of independent generators, each producing typed intermediate representations that downstream generators can optionally consume:

parse_schema -> SchemaOutput
    |-- gen_docs        -> ()                 (data-model reference + JSON Schema)
    |-- gen_seaorm      -> SeaOrmOutput       ---.
    |-- gen_markdown_io -> MarkdownIoOutput   ---+--> StoreConfig.backend
    |-- gen_dtos        -> ()                    |
    `-- gen_store       -> StoreOutput        <--'
        `-- gen_api     -> ApiOutput
            |-- gen_servers -> ServersOutput  (Rust transports: Axum / Tauri IPC / MCP)
            `-- gen_clients -> ()             (TS bindings, HTTP / IPC clients, admin registry)

Each generator is a standalone function. You can run the full pipeline or pick individual stages. Upstream outputs are optional enrichment, not hard requirements -- with one exception: gen_store needs a Backend to know what to emit CRUD against, and Backend::Markdown carries the MarkdownIoOutput that gen_markdown_io returned.

Quick Example

Define an entity:

#[derive(OntologyEntity)]
#[ontology(entity, table = "tasks", directory = "tasks")]
pub struct Task {
    #[ontology(id)]
    pub id: String,
    pub name: String,
    pub description: Option<String>,

    #[ontology(relation(belongs_to, target = "Agent"))]
    pub assignee_id: Option<String>,

    #[ontology(relation(many_to_many, target = "Requirement"))]
    pub fulfills: Vec<String>,
}

Wire it in build.rs:

use ontogen::*;

fn main() {
    let schema = parse_schema(&SchemaConfig {
        schema_dir: "src/schema".into(),
    }).unwrap();

    let seaorm = gen_seaorm(&schema.entities, &SeaOrmConfig {
        entity_output: "src/persistence/entities/generated".into(),
        conversion_output: "src/persistence/conversions/generated".into(),
        skip_conversions: vec![],
    }).unwrap();

    let _store = gen_store(&schema, &StoreConfig {
        output_dir: "src/store/generated".into(),
        hooks_dir: Some("src/store/hooks".into()),
        schema_module_path: DEFAULT_SCHEMA_MODULE_PATH.into(),
        backend: Backend::Seaorm(Some(seaorm)),
        wikilink_policy: None,
        id_strategy: IdStrategy::Provided,
    }).unwrap();

    // ... continue with gen_api, gen_servers, gen_clients as needed
}

Or drive the same stages through the Pipeline builder, which threads each output into the next and applies the defaults for you:

ontogen::Pipeline::new("src/schema")
    .seaorm("src/persistence/entities/generated", "src/persistence/conversions/generated")
    .store("src/store/generated", Some::<std::path::PathBuf>("src/store/hooks".into()))
    .store_id_strategy(ontogen::IdStrategy::Provided)
    .api("src/api/v1/generated", "AppState")
    .build()
    .expect("ontogen pipeline failed");

One cargo build generates your SeaORM entities, CRUD store methods, lifecycle hook stubs, API forwarding functions, and transport handlers. Add a new entity to your schema and rebuild -- everything updates automatically.

Key Features

  • Layered pipeline with typed intermediate representations between each stage
  • Independent generators that can run alone or be chained for richer output
  • Two store backends, chosen with one config field: SeaORM/SQL, or a vault of markdown files (ADR 0001). Everything above the store is byte-identical between them.
  • SeaORM persistence including entity models, junction tables, and model conversions
  • Markdown persistence where records are .md files with YAML frontmatter -- editable in any editor, diffable in git, navigable in Obsidian -- with hand edits preserved across generated writes. The vault is an OKF bundle, with optional generated index.md files and generated provenance stamps (guide)
  • Store generation with CRUD methods, update structs, and relation population
  • Lifecycle hooks scaffolded once per entity, never overwritten -- you own the hook files
  • API layer that merges generated CRUD with hand-written custom endpoints
  • Server transports for Axum HTTP (a JSON:API 1.1 server), Tauri IPC, and MCP (Model Context Protocol)
  • Client generation for TypeScript and admin registries, with a build-time AST walker that emits the full reachable type closure -- no side-car binary, no extra compilation
  • Docs generation -- a data-model.md reference and JSON Schema (draft 2020-12) per entity, so the schema ships as a published spec

The HTTP Wire

The generated Axum server speaks JSON:API 1.1 (application/vnd.api+json). Entities are resource objects; lists take filter[…], sort, include and, when paginated, page[offset]/page[limit]; relations are relationships with their own endpoints; hand-written ops send and answer meta-only documents (meta.args, meta.result); and every error is an errors[] document with a status and a code. Tauri IPC and MCP keep flat payloads, and the generated TypeScript transport flattens the HTTP documents back into the same plain types, so calling code is identical on both transports.

The normative rules are in the wire contract and the server transports guide. Each example has a page of real requests and responses: iron-log, iron-log-md, notes-kb and tasks-tracker.

Example Projects

Four runnable examples live under examples/:

Example Backend What it shows
iron-log SeaORM The full pipeline end to end: 4 entities to a Tauri + Nuxt app with a generated TypeScript client
iron-log-md Markdown iron-log's exact schema on the markdown backend -- diff -r the generated api/v1 trees to watch the byte-identical invariant hold
tasks-tracker Markdown A planning vault over HTTP and the generated MCP tool registry
notes-kb Markdown Wikilinked notes served as a graph
cd examples/iron-log/src-tauri
cargo build

That generates 36 files across all layers -- 23 Rust modules under generated/, 5 DTOs, 5 hook stubs, and 3 TypeScript files -- from 4 schema entity files.

Documentation

The full documentation site is built from site/ -- start with Getting Started, then the guides.

In-repo:

Project Status

Ontogen is functional and in active development. The full pipeline ships -- schema parsing through client generation, on both store backends. See docs/planning/tasks/README.md for the current backlog and docs/roadmap.md for the capability tiers.

License

This project is licensed under MIT.

About

code generators

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

Generated from sksizer/rust-template