Skip to content

Latest commit

 

History

707 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Axonyx Framework

Axonyx is a Rust-first web framework and language layer for building low-JavaScript sites, docs, and future CMS-style applications with .ax files, Cargo-native tooling, and Foundry UI.

Status: public beta loop.

Axonyx can already scaffold apps, render .ax pages, build static output, serve route-aware local previews, import Foundry UI from axonyx-ui, and publish deployable sites. It is not yet a full replacement for React, Next.js, or mature CMS platforms. The next runtime work is tracked in the GitHub issues and Wiki.

Current builds emit framework inspection artifacts under dist/_ax, including the Melt graph, content manifests, and state manifests when .ax files declare state signals.

What Works Today

  • JSX-like .asx authoring in app/**/page.asx and app/**/layout.asx
  • nested app routes
  • dynamic route params and query context
  • route boundaries through app/not-found.asx and app/error.asx
  • route-local loader.ax and actions.ax draft support
  • first action patch response contract through application/ax-patch+json
  • backend-oriented .ax files for loaders, actions, routes, and jobs
  • static builds through cargo ax build
  • route-aware dev/start server through cargo ax run dev and cargo ax run start
  • strict project diagnostics through cargo ax doctor --deny-warnings
  • early typed data checks for type Post, List<Post>, and <Each> field access
  • first state bridge contracts through stable SignalId, data-ax-signal, and typed patch events
  • first Melt state manifest for .ax state declarations
  • reusable Foundry UI imports through @axonyx/ui/...
  • generated apps consuming published crates from crates.io

Packages

This repository contains the public CLI packages:

  • create-axonyx - project scaffolding CLI, similar in spirit to create-next-app
  • cargo-axonyx - Cargo helper CLI exposed as cargo ax ...

Generated apps consume the runtime and UI packages through crates.io by default:

[dependencies]
axonyx-runtime = "0.1.14"
axonyx-ui = "0.0.48"

Quick Start

Install the public CLI tools:

cargo install create-axonyx
cargo install cargo-axonyx

Create and run a site:

create-axonyx my-site --yes --template site
cd my-site
cargo ax run dev

The default dev/start server uses the Tokio transport. The older standard library transport remains available as a fallback while the production path matures:

cargo ax run dev --transport std

For hosted starts, use the normal start command:

cargo ax run start --host 0.0.0.0 --port 3000

The legacy --production-server flag still selects Tokio for older deploy scripts, but it is no longer required. The Tokio path installs a Ctrl+C shutdown listener and a short connection drain window so hosted starts and local previews can stop cleanly.

For Render-style deployment checks:

cargo ax doctor --deploy render

The Render check recommends the same Tokio-backed start command so local smoke and hosted deploys exercise the same server path. It also reports the recommended health-check path: /__axonyx/health.

Production preview exposes a stable health probe for hosted platforms and load balancers:

GET /__axonyx/health

Request reads default to a short production-safe timeout and can be tuned per app:

[server]
request_timeout_seconds = 2
shutdown_grace_seconds = 5
max_connections = 1024

This is intentionally a runtime choice, not an authoring burden: .ax pages, loaders, actions, and state patches keep the same shape while Axonyx chooses the transport layer underneath.

The Tokio server path also exposes the first SSE probe:

cargo ax run dev
# open /__axonyx/events

This is the first axonyx-server-net step toward live patch streams, CMS event feeds, and worker/build notifications.

Check and build:

cargo ax doctor --deny-warnings
cargo ax build --clean

Available templates today:

  • site - the default static product/company site
  • blog - a Markdown content collection with prerendered article routes
  • docs - a static documentation shell with Getting Started, Components, Reference, and Examples
  • minimal - the full-stack playground with loaders, actions, API routes, jobs, and database examples

The three static templates intentionally have different information architectures, route trees, and output contracts. All of them build without a database or application backend and include Aegis route/link checks.

From this repository, contributors can also run the scaffold locally:

cargo run -p create-axonyx -- my-site --yes --template site

App Authoring Model

Recommended authoring path today:

  • JSX-like .asx files in app/**/page.asx and app/**/layout.asx
  • nested app routes with route-local loader.ax and actions.ax when needed
  • imports from local app components via @/components/...
  • imports from Axonyx UI packages via @axonyx/ui/...

Example route tree:

app/
  layout.asx
  page.asx
  docs/
    page.asx
  components/
    page.asx
  blog/
    [slug]/
      page.asx
      loader.ax

Legacy indentation-first .ax syntax still exists for compatibility and reference work, but new examples and new framework authoring should prefer the JSX-like .asx direction.

Typed data is available in the JSX-like path:

page Blog() {

type Post {
  title: String
  slug: String
  summary?: String
}

data posts: List<Post> = loadPosts()

return ASX {
<Each items={posts} as="post">
  <Card title={post.title} />
</Each>
}
}

Route-local query functions can live next to the page:

query loadPosts() -> Post[] {
  data posts = db.posts.all()
  return posts
}

cargo ax check reports axonyx-type diagnostics when a typed page accesses a missing field such as post.summary. Use post?.summary when a missing field is intentional and should render as an empty string. Use summary?: String in the type when the field is part of the schema but optional.

Early UI state authoring is also available in JSX-like .asx:

page Settings() {

state theme = "silver"
state count: Number = 0

return ASX {
<select bind:value={theme}>
  <option value="silver">Silver</option>
  <option value="bronze">Bronze</option>
  <option value="gold">Gold</option>
</select>

<span bind:text={theme}>{theme}</span>
<input bind:value={count} />
}
}

Axonyx lowers this into stable data-ax-signal / data-ax-bind metadata and injects the small state bridge only when a page uses signal bindings. The browser bridge exposes window.__axonyx.state with get, set, subscribe, applyPatch, and snapshot.

The first Melt state manifest lives in axonyx-core::state::build_state_manifest. It extracts top-level .ax state declarations into stable signal records with id, key, name, scope, ty, and initial. Framework reports now assign route-aware scopes such as app:language:1, layout:docs:sidebarOpen:1, and page:settings:filter:1, while the runtime still keeps legacy root:* signal keys compatible during the transition.

State declarations can be authored with explicit ownership:

app state language: String = "sr"
layout state sidebarOpen: Bool = false
page state filter: String = ""

Use app state for app-wide concerns like language or theme, layout state for shared route shell state, and page state for local route state. Action patch responses resolve short authoring names like patch theme = ... through the route manifest before sending browser patches, so the client receives the stable scoped signal key.

Use ActionForm to target route actions without manually wiring Axonyx transport fields:

<ActionForm name="SetTheme">
  <select name="theme">
    <option value="silver">Silver</option>
    <option value="gold">Gold</option>
  </select>
  <ActionStatus state="pending">Saving theme...</ActionStatus>
  <ActionStatus state="complete">Theme saved.</ActionStatus>
  <ActionStatus state="error">Theme could not be saved.</ActionStatus>
  <Button type="submit">Apply</Button>
</ActionForm>

It renders a regular form pointed at /__axonyx/action and includes the internal patch marker automatically. ActionStatus renders a status message that is shown from the form lifecycle state managed by the small action runtime. Route actions coerce declared input: fields before execution: string stays text, bool accepts browser checkbox-style values such as on, and integer fields such as i64 / u64 must parse successfully or the action fails with a clear runtime error. Optional action inputs use ?, for example summary?: string; missing optional fields become Null, while missing required non-boolean fields fail before the action body runs. Inputs can also define literal defaults, such as language?: string = "sr" or count: i64 = 0.

Common Commands

From an app root:

cargo ax doctor
cargo ax check
cargo ax migrate asx --dry-run
cargo ax g component ThemeSwitcher
cargo ax g island CommandPalette
cargo ax g page settings/profile
cargo ax contracts
cargo ax schema pull ./sample-posts.json --name Post
cargo ax actions
cargo ax content
cargo ax state
cargo ax build
cargo ax run dev
cargo ax test

Axonyx 0.2 uses .asx for pages, layouts, boundaries, and UI components while keeping .ax for loaders, actions, API routes, domain code, and jobs. Existing projects can preview and apply the mechanical migration with:

cargo ax migrate asx --dry-run
cargo ax migrate asx

cargo ax schema pull accepts sample JSON as a draft, but it can also read a typed envelope from an endpoint or file. When the source includes schema, Axonyx uses that contract instead of guessing from null values:

{
  "type": "List<Post>",
  "schema": {
    "Post": {
      "title": "String",
      "summary": "Optional<String>"
    }
  },
  "data": []
}

Use strict doctor mode in CI:

cargo ax doctor --deny-warnings

cargo ax test is reserved for Aegis, the future Rust-first QA runner for component, route, and browser checks. In the current beta it is a preview placeholder only; use cargo ax check, cargo ax doctor --deny-warnings, and cargo ax build --clean for real validation today.

Use JSON output for editor tooling:

cargo ax doctor --format json
cargo ax routes --format json
cargo ax actions --format json
cargo ax state --format json
cargo ax contracts --format json

cargo ax contracts is the stable, versioned application contract surface for tools. Contract V1 combines named .ax types, structured component props, page data bindings, loader/action signatures, API routes, and scopes without exposing the full internal Melt graph. Write it explicitly with:

cargo ax contracts --format json --out public/axonyx-contracts.json

Every production build also emits the same schema at dist/_ax/contracts/manifest.json. Missing type annotations remain visible as unknown/empty metadata unless a direct route-local loader call provides a declared return contract. For example, data posts = loadPosts() inherits List<Post> from app/posts/loader.ax when loadPosts returns Post[]. Explicit page types are checked against that loader contract, and mismatches fail cargo ax check instead of silently changing the public manifest. When no route-local loader matches, a uniquely named shared query under app/** can provide the same type contract. Route-local loaders take priority; ambiguous shared query names fail diagnostics rather than depending on file system traversal order.

UI package tooling uses the same structured prop shape. With axonyx-ui installed, cargo ax registry --format json parses each registry component and adds its props contract (name, ty, required, and default) without changing the existing cargo ax add copy/install path.

Build

cargo ax build scans backend-oriented .ax sources:

  • app/**/loader.ax
  • app/**/actions.ax
  • routes/**/*.ax
  • jobs/**/*.ax

and regenerates:

src/generated/backend.rs

It also renders static page routes from app/**/page.asx into:

dist/
  index.html
  docs/index.html
  components/index.html
  ...

Use a clean static output build when preparing deploy artifacts:

cargo ax build --clean

To choose another output directory:

cargo ax build --out-dir public-build --clean

Dynamic page routes are skipped unless they are listed in Axonyx.toml:

[prerender]
routes = [
  { route = "/blog/:slug", params = [{ slug = "hello-axonyx" }, { slug = "foundry-ui" }] },
]

That renders:

dist/blog/hello-axonyx/index.html
dist/blog/foundry-ui/index.html

Local Dev Server

Run the route-aware server:

cargo ax run dev

For a production-style process without dev live reload:

cargo ax run start --host 0.0.0.0 --port 3000

Inspect the route tree:

cargo ax routes

This lists app/**/page.asx page routes, routes/**/*.ax backend routes, dynamic params, nested layout count, and route-local loader.ax / actions.ax files.

Inspect route-local action contracts:

cargo ax actions
cargo ax actions --format json
cargo ax actions --route /posts
cargo ax actions --name CreatePost
cargo ax actions --name CreatePost --schema

This reports each app/**/actions.ax action, its route, and declared input: fields with type, optional marker, and default value. It is the first small DX step toward Axonyx endpoint/schema discovery without making developers guess form contracts.

Inspect content collections:

cargo ax content
cargo ax content --format json

Configure early Melt-time content indexing in Axonyx.toml:

[content.collections.docs]
path = "content/docs"
extensions = ["md", "mdx"]

This indexes matching files into a content manifest today. Later runtime work can use the same manifest for docs, blog, and CMS routing. During cargo ax build, configured collections are written to:

dist/_ax/content/manifest.json

Route loaders can read configured content collections in preview/build:

query loadDocs() -> Doc[] {
  data docs = Content.Collection("docs")
    order slug asc
  return docs
}

Markdown entries expose path, slug, extension, bytes, body, and simple frontmatter fields such as title or description.

Adding Modules

Add a docs module into an existing app:

cargo ax add docs

Add the Foundry UI package when needed:

cargo ax add ui

cargo ax add cms and cargo ax add blockbit are reserved for the future Blockbit CMS module. CMS stays outside framework core; Axonyx core provides the runtime primitives that Blockbit will build on.

Today, cargo ax add ui and the site / docs templates use the published axonyx-ui Cargo package by default.

Runtime Source Options

Generated apps can target:

  • the published crates.io package, axonyx-runtime = "0.1.14"
  • a local Cargo path dependency into a checked-out runtime workspace
  • the standalone Git repo at https://github.com/vladanPro/axonyx-runtime

Use --runtime-source path only when contributing to Axonyx itself from the framework workspace.

Use --runtime-source git when testing an unreleased runtime branch:

cargo run -p create-axonyx -- my-app --yes --runtime-source git

Framework Development

When working on this monorepo itself:

git submodule update --init --recursive
cargo test

Run the core loop smoke test from the framework repo root:

powershell -ExecutionPolicy Bypass -File scripts/smoke-core-loop.ps1 -Template site

The smoke test creates a temporary app, uses the local framework and local axonyx-ui when available, then runs:

cargo ax check
cargo ax doctor --deny-warnings
cargo ax build --clean

It passes only if the app has no strict doctor warnings/errors and dist/index.html is generated.

Design Direction

Axonyx should stay Rust-first and compiler-assisted, not a React clone.

The preferred runtime direction is:

compile .ax
  -> static HTML with stable node ids
  -> dependency graph
  -> small runtime patcher

State and binding are separate concepts:

global/state = storage model
hard/soft = binding model

Preferred mental model:

Soft = snapshot
Hard = live handle

The server/runtime can be async internally, but Axonyx authoring should stay structured and declarative. Developers should place work into loader, action, signal, <Await>, and job instead of hand-orchestrating promise timing.

See Structured Async In Axonyx.

Roadmap

The next framework spine is tracked as Axonyx Runtime Core / The Melt.

Primary GitHub issues:

Architecture references:

Docs

The structured docs index lives in:

docs/README.md

Recommended reading order:

  • docs/overview.md
  • docs/ax-v2-authoring.md
  • docs/architecture/structured-async.md
  • docs/templates.md
  • docs/backend-authoring.md
  • docs/release-runbook.md

Drafts and lower-level architecture notes should live in docs/, not in the top-level README.

Links

Repo Layout

crates/
  cargo-axonyx/
  create-axonyx/
vendor/
  axonyx-runtime/
docs/

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages