G · 01 guides

Guides / Getting Started

Getting Started

Aihu is a web meta-framework whose components are single-file components (SFCs) — .aihu files with a small set of macro blocks. The same component is a custom element for humans and a discoverable, governed surface for AI agents. This guide builds one from scratch.

Hello, world

After scaffolding a project, open src/pages/index.aihu. The smallest useful component declares reactive state and a template that reads it:

governedaihuaihu129 B
@state {
  let name = prop({ default: 'world' })
}

@template {
  <p>Hello, {name}!</p>
}

@route {
  path: "/",
  name: "home"
}

Three blocks, three jobs: @state owns reactivity, @template owns structure, @route registers the page. Everything else composes from here.

The @state block

@state is where reactive values live. It is ordinary TypeScript — you can import, declare helpers, and call the reactive intrinsics.

Props are the component's public, host-settable surface. Declare one with prop(); it is reactive, reflects to an attribute, and can be exposed to agents.

governedaihuaihu113 B
@state {
  let count = prop({
    default: 0,
    describe: 'The current tally',
    expose: 'read write',
  })
}

Local state that is not part of the public surface uses state():

governedaihuaihu36 B
@state {
  let open = state(false)
}

Reach for state() for private working values, and prop() when the value is part of the component's public, host-settable, agent-visible contract.

Derived values are lazy and memoized — declare them with derived():

governedaihuaihu88 B
@state {
  let count = prop({ default: 0 })
  const doubled = derived(() => count * 2)
}

Actions are named, agent-invocable operations. The wrapped form adds describe / expose metadata so an MCP agent can discover and call them:

governedaihuaihu212 B
@state {
  let count = prop({ default: 0 })

  const increment = action(() => { count++ })
  const reset = action(
    { describe: 'Reset the tally to zero', expose: 'read write' },
    () => { count = 0 },
  )
}

The @template block

@template describes the DOM with aihu's template grammar:

  • {expr} interpolates a reactive expression.
  • href={expr} binds an attribute reactively.
  • on:click={handler} attaches an event listener.
  • if / elseif / else and show handle conditionals.
  • each / key render keyed lists.
governedaihuaihu275 B
@template {
  <section class="counter">
    <output class="count">{count}</output>
    <div class="controls">
      <button on:click={decrement}>−</button>
      <button on:click={reset}>Reset</button>
      <button on:click={increment}>+</button>
    </div>
  </section>
}

The @route block

@route registers a component as a page. During build the Rust compiler emits a .route.json sidecar; the router assembles them into a fully static manifest — no filesystem scanning at runtime.

governedaihuaihu163 B
@route {
  path: "/",
  name: "home",
  layout: "docs",
  head: {
    title: "Home — my app",
    description: "Rendered to static HTML, hydrated on load."
  }
}

With output: 'static' every route without a loader is prerendered to a content-ful index.html carrying its own head, then hydrated into the live app on load — crawlers and agents read real content, humans get the SPA.

A complete example

Put together, the canonical counter is about forty lines, has an agent surface (all three actions are agent-callable), and pulls in nothing beyond the reactive intrinsics:

governedaihuaihu489 B
@state {
  let count = prop({ default: 0, describe: 'The tally', expose: 'read write' })

  const increment = action(() => { count++ })
  const decrement = action(() => { count-- })
  const reset = action(() => { count = 0 })
}

@template {
  <section class="counter">
    <h2>Count: {count}</h2>
    <div class="controls">
      <button on:click={decrement}>−</button>
      <button on:click={reset}>Reset</button>
      <button on:click={increment}>+</button>
    </div>
  </section>
}

Next steps

  • Reactivity — the signal, computed, and effect primitives behind prop and derived.
  • Authoring Components — the full reference for @state, @template, @style, and @agent.
  • Agent Discovery — how state and actions become an MCP-discoverable surface.