hacifootprint
Get Started

Quick start

Author the graph, connect it to your running app, serve it to any LLM host — the first two steps run offline with no API key.

npm install hcifootprint

Three steps. The first two run offline with no API key.

1. Describe the app

Describe the app as the tree you already picture — pages, the containers inside them, and the actions inside those. Each action needs one sentence; that sentence is both your label and the tool description the LLM reads.

import {  } from 'hcifootprint';

const  = ('shop', {
  : {
    : {
      : {
        'search': { : 'Search dresses by name or color' },
        'add-to-cart': {
          : 'Add the open dress to the cart',
          : { : { : true } },
        },
      },
    },
    : {
      : {
        'confirm-order': {
          : { 'place-order': { : 'Place the order', : true } },
        },
      },
    },
  },
  : {
    : { : 'Buy a dress end to end', : ['add-to-cart', 'place-order'] },
  },
});

buildNavigationGraph validates and freezes the whole definition in one call — unknown goTo targets, guard-operator typos, ambiguous journey steps and contradictory guards all throw at build time, not at runtime. See The navigation graph.

If your app already owns a route table or a journey list, you don't have to re-type them: the graph grows from sources.

2. Connect it

Connect the graph to your running app through three ordinary wires. Components register what they have when they render; your existing functions bind by reference; the router owns the page.

const  = .();

// when the component that renders the catalog mounts:
const  = .('catalog', {
  : { 'search': () => .() }, // your own function, by reference
});
.('search', false); // grey a button out; group.unregister() on unmount

// your existing wires report reality:
.({ : true }); // store tap → guards re-evaluate
.('checkout');                     // router change → the cursor moves

Node paths are typed: registerActions('catalog.filtr-rail') is a compile error, not a silent no-op. Pages contributed by fromRoutes are part of that same typed union.

3. Serve it to the LLM

Serve the session as a fixed set of MCP-shaped tools. The tool list never changes; what's doable right now arrives inside each tool result.

const  = ();

const  = .();               // static tool array — one per journey + the four generics
const  = .('shop.journey.purchase', {}); // → { readySteps, judgment, youAreOn, ... }

The agent plans over journeys, sees only what's available at the current position, and acts through your own handlers — with the human able to approve high-effect steps. That's the whole integration: tools() + call() for any framework, or a real MCP server as a one-liner.

Where next

  • The three contextsread this next. Map, traversal and actions: the whole library in three questions, each with the same three parts.
  • The adoption ladder — start in read-only guide mode; nothing can touch your app.
  • Guards — read this before writing a state projector.
  • Demos — two runnable apps in this repo plus the dress-shop, none needing a key.

On this page