How the Maru app works
We built the Maru app, a desktop app, for our UIST paper. It uses the SDK for everything about IA rules and adds the rest: model calls, layouts, and storage. It has two parts: an IA Rule Module that builds and keeps your rules, and a generation pipeline that uses them to make each interface.

IA Rule Module
| Component | What it does |
|---|---|
| Extractor | Reads each query and saves the IA rules it states, such as "affordable means under $1,800". |
| Edit Analyzer | Turns UI interactions into rule changes. Dragging a card, sorting, or removing a field updates the layout and its rules right away, without a new generation. |
| Rule Storage | Keeps user-initiated rules and system-scaffolded rules (the starting Partition and Hierarchy taken from the first interface). You see and edit them in the IA panel; removing a rule archives it. |
| Rule Retriever | Before each generation, picks the rules that apply to this request. See Persistence and its boundaries. |
Generation pipeline
| Component | What it does |
|---|---|
| Data Manager | Collects items from open tabs and web search, and gives each a stable ID so rules still point to the right item after renames. |
| Layout Engine | Plans the layout from the query and the Partition and Hierarchy rules, then fills it using all four rule types. Design patterns from the research codebook serve as examples. |
| UI Renderer | Turns the plan into interactive components. Because the plan is data, the same answer can be shown as another layout without calling the model again. |
After each response, Maru records which rules shaped it. This history drives how rules are ranked over time.
Where it lives in the code
| Part | Code |
|---|---|
| Extractor | src/main/ia/extraction.ts (extractIAFromMessage) |
| Edit Analyzer | stores/iaStore.ts (applyLayoutIAEvent) → SDK applyLayoutEvent |
| Scaffolded rules | stores/send/rule-scaffold.ts, stores/send/plan-persistence.ts |
| Rule Storage | SDK IAPersistence |
| Rule Retriever | src/main/ia/retrieval.ts (retrieveRules) with SDK rule-retrieval |
| Data Manager | stores/send/data-acquire.ts with SDK DataStorePersistence |
| Layout Engine | stores/send/layout-plan.ts (planLayout), codebook in data/codebook/codebook.csv |
| UI Renderer | DynamicBlock and components/blocks/ |
| Recording applied rules | stores/send/attribution.ts (fireAttribution) |
Renderer paths are under src/renderer/src/; the SDK is packages/maru-sdk/. The whole pipeline runs from executeChatLLM in stores/send/chat-mode.ts. Layouts only emit events; all IA logic stays in the SDK or the IA modules.