xuda-cli is the local development CLI for Xuda app projects.
It lets you:
- create and run a Xuda app locally
- author the app in friendly source files such as
App.xu,components/*.xu, andtables/*.json5 - compile those source files into runtime JSON docs
- keep the runtime docs in one canonical location:
node_modules/.project_data/ - optionally sync cloud project docs down into source files and push local changes back up
Quick Start
Create a new app:
npm create xuda-cli@latest my-app
cd my-app
npm install
npm run dev
Typical package.json scripts:
{
"scripts": {
"dev": "xuda-cli dev",
"sync": "xuda-cli sync"
}
}
Install common plugins with normal npm install:
npm install @xuda.io/xuda-framework-plugin-tailwind
npm install @xuda.io/xuda-dbs-plugin-xuda
There is no plugin subcommand in xuda-cli.
Commands
xuda-cli dev
xuda-cli sync
xuda-cli --help
xuda-cli dev
- loads your project from the current directory
- compiles source files into
node_modules/.project_data/ - serves the app locally
- watches
.xuand supported.json5files and regenerates runtime docs on save
xuda-cli sync
- requires
api_keyinxuda.config.js - downloads cloud docs into
node_modules/.project_data/ - creates missing local
.xuand.json5source files from those docs - recompiles local source back into
node_modules/.project_data/ - uploads changed docs back to the cloud
Mental Model
The app has three important layers:
index.htmlThis is the document shell. It owns the<head>, metadata, fonts, and the HTML node where your root app mounts.App.xuThis is the root Xuda screen. It is compiled as the program idapp.node_modules/.project_data/This is the generated runtime document set that the Xuda runtime reads.
If xuda.config.js uses:
module.exports = {
entry: 'index.html'
};
then index.html is served first, and App.xu is automatically mounted into #app unless you already mounted another component into that HTML entry.
If entry is omitted, xuda-cli defaults to app.
Recommended rule:
- keep
index.htmlas the page shell - keep
App.xuas the root Xuda screen - add feature screens under
components/
How xuda-cli Technology Works
xuda-cli is not just a file server. It is a source compiler, runtime packager, local app host, and optional cloud sync tool.
When you work on a Xuda app, the technology flow looks like this:
- Authoring layer You write human-friendly source files such as
App.xu,components/*.xu,data/get/*.xu, andtables/*.table.json5. - Compile layer
xuda-cliparses those source files and converts them into the JSON document model that the Xuda runtime already understands. - Runtime docs layer The compiled output is written to
node_modules/.project_data/. This is the canonical runtime doc folder used by the local app. - Runtime host layer
xuda-cli devserves yourindex.html, runtime assets, compiled component scripts, and the generated document set. - Browser/runtime execution layer The browser loads the Xuda runtime, mounts
App.xuor the configured entry program, and executes fields, actions, events, datasources, and panels. - Optional cloud sync layer If
api_keyis configured,xuda-cli synccan pull remote docs into the local project, create missing source files, and push changed docs back to the cloud.
Source-first philosophy
The intended developer experience is:
- source files are the place humans edit
node_modules/.project_data/is generated runtime output- the runtime reads generated docs
- sync can import older or remote docs into source files, but source remains the preferred authoring format
What gets compiled
xuda-cli compiles:
.xufiles into component or logic-unit docs.table.json5files into table docs.route.json5files into route docs.agent.json5files into AI agent docs
What stays runtime-facing
The local runtime still consumes the classic Xuda document shape:
progUiprogFieldsprogEventsprogDataSourcetableFieldstableIndexesrouteMenuagentConfig
That means xuda-cli gives you a friendlier source format without requiring a brand-new runtime protocol.
SSR and render profiles
xuda-cli supports:
ssr: 'none'ssr: 'first_page'ssr: 'full'
In practice:
nonenormal client renderingfirst_pagefirst-page SSR with client takeoverfullfuller SSR with hydration-friendly behavior
Plugin model
Plugins are standard npm dependencies, not copied folders and not special CLI subcommands.
Use plugins for:
- UI frameworks such as
@xuda.io/xuda-framework-plugin-tailwind - database behavior such as
@xuda.io/xuda-dbs-plugin-xuda
Why the project keeps both index.html and App.xu
They solve different problems:
index.htmldocument shell, metadata, fonts, mount elementApp.xuroot Xuda UI, fields, actions, panels, and app behavior
This separation keeps the app structure predictable and makes it easier to scale into multiple routed or panel-based screens.
Project Layout
This is the official source layout:
my-app/
package.json
xuda.config.js
index.html
App.xu
components/
**/*.xu
globals/
**/*.xu
data/
get/**/*.xu
set/**/*.xu
batch/**/*.xu
apis/
**/*.xu
scripts/
**/*.xu
alerts/
**/*.xu
tables/
**/*.table.json5
routes/
**/*.route.json5
ai-agents/
**/*.agent.json5
node_modules/
.project_data/
Rules:
App.xuis the reserved root app filecomponents/is for UI componentsglobals/is for shared state unitsdata/get/,data/set/, anddata/batch/are for logic unitstables/,routes/, andai-agents/are structured JSON5 resourcesnode_modules/.project_data/is generated runtime output, not your source of truth
What Lives in index.html
Use index.html for:
- the page title
- meta tags
- favicons
- fonts
- external scripts if you need them
- the root mount element
Minimal example:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Xuda App</title>
</head>
<body>
<main id="app"></main>
</body>
</html>
xuda.config.js
xuda.config.js controls entry, server, and sync-related settings.
Example:
module.exports = {
entry: 'index.html',
port: 3000,
ssr: 'none',
api_key: '',
build_id: ''
};
Supported fields:
entryThe app entry. Usuallyindex.html. Defaults toapp.portLocal dev port. Defaults to3000.ssrOne ofnone,first_page, orfull.api_keyOptional. Required fornpm run sync.build_idOptional remote build target. If provided, it requiresapi_key.
package.json
package.json is the source of app package metadata:
nameversiondescription
Minimal example:
{
"name": "my-app",
"version": "0.1.0",
"description": "Starter Xuda app",
"scripts": {
"dev": "xuda-cli dev",
"sync": "xuda-cli sync"
},
"dependencies": {
"@xuda.io/xuda-framework-plugin-tailwind": "latest",
"@xuda.io/xuda-dbs-plugin-xuda": "latest"
},
"devDependencies": {
"xuda-cli": "latest"
}
}
Source File Types
xuda-cli supports these authored source types:
| Location | File type | Xuda unit | | --- | --- | --- | | App.xu | .xu | root component | | components/**/*.xu | .xu | component | | globals/**/*.xu | .xu | globals | | data/get/**/*.xu | .xu | get_data | | data/set/**/*.xu | .xu | set_data | | data/batch/**/*.xu | .xu | batch | | apis/**/*.xu | .xu | api | | scripts/**/*.xu | .xu | javascript | | alerts/**/*.xu | .xu | alert | | tables/**/*.table.json5 | .json5 | table | | routes/**/*.route.json5 | .json5 | route | | ai-agents/**/*.agent.json5 | .json5 | ai_agent |
Xuda Building Blocks At A Glance
Each block exists for a different responsibility. A good Xuda app is usually clearer when each concern has its own unit instead of pushing everything into one giant component.
| Building block | Main responsibility | Best used for | | --- | --- | --- | | component | UI and interaction | screens, panels, forms, dashboards, reusable views | | globals | shared app state | signed-in user, campus, feature flags, shared filters | | get_data | reading data | list loads, record queries, reusable data fetches | | set_data | writing data | create, update, delete, persistence workflows | | batch | record-by-record processing | rebuild jobs, migration flows, recalculation | | api | response-oriented logic | API outputs, summaries, machine-readable endpoints | | javascript | custom JS logic | formatting, transformations, reusable computation | | alert | user messaging | toasts, success notices, warnings, error feedback | | table | data model definition | fields, indexes, database-facing schema metadata | | route | navigation model | menus, destinations, route planning | | ai_agent | assistant configuration | app-specific AI helpers and future agent workflows |
How to choose the right block
Use component when:
- the user sees it
- it owns UI state or user interactions
- it renders template markup
Use globals when:
- more than one screen needs the same state
- the value is app-wide rather than screen-local
Use get_data when:
- the main job is to read from a datasource
- you want loading logic to stay outside UI components
Use set_data when:
- the main job is to persist a change
- you want writes to have a named, reusable unit
Use batch when:
- you are processing many rows or records
- the workflow is iterative and not just a simple read/write
Use api when:
- the result should be shaped as a clean response
- the unit feels more like an endpoint than a screen
Use javascript when:
- you need custom code but do not want it scattered through actions
- the logic is reusable and named
Use alert when:
- the app needs consistent messaging
- a message should be reusable across multiple screens or workflows
Use table when:
- a datasource refers to real table-backed storage
- you need fields and indexes with a stable id
Use route when:
- the app has named destinations or menu structure
- you want a navigation model that is visible in source
Use ai_agent when:
- the app needs a configured assistant resource
- you want that assistant defined as a first-class app asset
.xu Blocks
xuda-cli reads .xu files as block-based source files.
Supported component blocks:
<meta lang="json5"><params lang="json5"><fields lang="json5"><actions lang="json5"><events lang="json5"><datasource lang="json5"><template><script><style><mount>
Supported non-UI logic blocks:
globals<meta>,<fields>,<events>, optional<datasource>get_data,set_data,batch<meta>,<params>,<fields>,<events>,<datasource>api<meta>,<params>,<fields>,<events>,<datasource>,<response>javascript<meta>,<params>,<code>alert<meta>,<params>,<alert>
Block rule:
- the object blocks are JSON5-style object literals
- unquoted keys are fine
- arrays and nested objects are fine
App.xudoes not need a<mount>block- ordinary components only need
<mount>when you want them mounted directly into an HTML file
Template Language
Inside <template>, xuda-cli gives you a friendly source format and compiles it into Xuda runtime markup.
Friendly tag aliases
<single-view>becomesxu-single-view<multi-view>becomesxu-multi-view<panel>becomesxu-panel
Friendly attributes
bind="field_v"becomesxu-bindif="@some_flag_v"becomesxu-exp:xu-renderfor="@items_v"becomesxu-exp:xu-forfor-key="name"becomesxu-for-keyfor-val="name"becomesxu-for-val:content="@title_v"becomesxu-exp:xu-content:rows_in="@rows_v"becomesxu-exp:rows_in@click="saveItem"becomesxu-on:click@click.stop="saveItem"becomesxu-on:clickwithstopPropagation@submit.prevent="saveItem"becomesxu-on:submitwithpreventDefault
Recommended rule:
- write explicit
<single-view>or<multi-view>wrappers even though the compiler can add a root wrapper for you
Example:
<template>
<single-view>
<section class="screen">
<input bind="search_v" placeholder="Search students">
<button @click="togglePanel">Toggle panel</button>
<div if="@show_panel_v">
<panel program="student_details" />
</div>
</section>
</single-view>
</template>
Component Example
component is the main UI building block in Xuda.
Use it for:
- full screens
- dashboards
- forms
- reusable panels
- feature views such as students, tasks, profiles, or settings
A component usually owns:
- visible layout
- local screen state
- UI-triggered workflows
- panel composition
- optional client-side mount logic and styles
Example components/StudentList.xu:
<meta lang="json5">
{
id: "student_list",
menuTitle: "Student List",
uiFramework: "@xuda.io/xuda-framework-plugin-tailwind"
}
</meta>
<fields lang="json5">
{
show_panel_v: { type: "boolean", value: false },
student_count_v: { type: "number", value: 3 }
}
</fields>
<actions lang="json5">
{
togglePanel: [
{ action: "update", name: { value: "@show_panel_v: !@show_panel_v" } }
]
}
</actions>
<template>
<single-view>
<section class="p-6 space-y-4">
<h1>Students</h1>
<p :content="'Count: ' + @student_count_v"></p>
<button class="rounded-full px-4 py-2 bg-sky-600 text-white" @click="togglePanel">
Toggle details
</button>
<div if="@show_panel_v">
<panel program="student_details" />
</div>
</section>
</single-view>
</template>
Optional direct HTML mount
If you want a component mounted directly into an HTML file, add a <mount> block:
<mount>
{
id: "marketing_hero",
file: "landing.html",
selector: "#hero"
}
</mount>
Rules:
App.xuis always the root app and does not need<mount>- components used only through
<panel program="...">do not need<mount> - for non-root components, the program id resolves in this order:
meta.idmount.id- file basename
Globals Example
globals is the shared-state building block.
Use it for:
- signed-in operator identity
- campus or tenant context
- theme preferences
- shared filters or flags used across multiple screens
Do not use globals for:
- page-specific transient UI state that only one component needs
- presentation concerns that belong inside a component
Example globals/SchoolGlobals.xu:
<meta lang="json5">
{
id: "school_globals",
menuTitle: "School Globals"
}
</meta>
<fields lang="json5">
{
campus_name_v: { type: "string", value: "Boston Campus" },
dark_mode_v: { type: "boolean", value: false }
}
</fields>
Use globals for shared state and app-wide values.
Datasource Format
Use the readable wrapper format inside <datasource lang="json5">.
none
<datasource lang="json5">
{
type: "none"
}
</datasource>
Table datasource
<datasource lang="json5">
{
type: "table",
table: "student_profiles_table",
filter: {
mode: "index",
activeIndex: "campus_idx",
indexes: {
campus_idx: {
campus: {
from: "@campus_in",
to: "@campus_in"
}
}
}
},
output: "students_out",
direction: "asc",
realtime: true,
limit: 25
}
</datasource>
Query datasource
<datasource lang="json5">
{
type: "table",
table: "student_tasks_table",
filter: {
mode: "query",
query: {
$and: [
{ status: "Open" },
{ campus: "Boston Campus" }
]
}
},
output: "tasks_out"
}
</datasource>
Array / JSON / CSV datasource
<datasource lang="json5">
{
type: "json",
source: {
url: "https://example.com/students.json"
},
output: "students_out"
}
</datasource>
Rules:
typecan benone,table,array,json, orcsv- for table sources, use
table,filter,sort,direction,realtime,limit,skip, andoutput - for array/json/csv, use
source.fieldorsource.url - if you need raw unsupported datasource keys, use:
<datasource lang="json5" mode="raw">
{
"dataSourceType": "table",
"dataSourceTableId": "student_profiles_table"
}
</datasource>
get_data Example
get_data is the read-focused building block.
Use it when:
- the unit's main purpose is loading data
- you want one reusable place for filters, limits, sorting, and output mapping
- a component should call a named loader instead of owning query details directly
Typical outputs:
- rows into an output field
- filtered subsets of a table
- external JSON / CSV / array-based data
Example data/get/LoadStudentClasses.xu:
<meta lang="json5">
{
id: "load_student_classes",
menuTitle: "Load Student Roster"
}
</meta>
<params lang="json5">
{
in: {
campus_in: "string"
},
out: {
students_out: "array"
}
}
</params>
<datasource lang="json5">
{
type: "table",
table: "student_profiles_table",
filter: {
mode: "index",
activeIndex: "campus_idx",
indexes: {
campus_idx: {
campus: {
from: "@campus_in",
to: "@campus_in"
}
}
}
},
output: "students_out",
direction: "asc",
realtime: true,
limit: 25
}
</datasource>
set_data Example
set_data is the write-focused building block.
Use it when:
- the unit's main purpose is to create, update, or delete records
- you want persistence to have a visible, testable home in source
- several screens might share the same write behavior
Typical uses:
- saving a profile
- deleting a row
- creating a new record
- updating status or workflow state
Example data/set/SaveStudentProfile.xu:
<meta lang="json5">
{
id: "save_student_profile",
menuTitle: "Save Student Profile",
crudMode: "U",
allowCreate: true
}
</meta>
<params lang="json5">
{
in: {
student_id_in: "string",
full_name_in: "string",
email_in: "string",
campus_in: "string"
}
}
</params>
<datasource lang="json5">
{
type: "table",
table: "student_profiles_table"
}
</datasource>
Use set_data units to represent write behavior clearly in source instead of hiding persistence inside a component.
batch Example
batch is the iterative processing building block.
Use it when:
- one action needs to process many rows
- a workflow should run
before_recordorafter_record - you are rebuilding, migrating, enriching, or recalculating data
Example data/batch/RebuildClassRoster.xu:
<meta lang="json5">
{
id: "rebuild_class_roster",
menuTitle: "Rebuild Class Roster"
}
</meta>
<events lang="json5">
{
before_record: [
{ action: "delay", name: { value: "1" } }
]
}
</events>
<datasource lang="json5">
{
type: "table",
table: "student_profiles_table",
output: "students_out"
}
</datasource>
api Example
api is the response-oriented building block.
Use it when:
- the result should be returned as a structured response
- the unit behaves more like an endpoint or service response than a screen
- you want a clean place to translate fields and datasource results into a JSON-style payload
An api unit often combines:
- params
- datasource
- optional events
- response serialization in
<response>
Example apis/StudentClassesApi.xu:
<meta lang="json5">
{
id: "student_classes_api",
menuTitle: "Student Classes API"
}
</meta>
<params lang="json5">
{
out: {
students_out: "array"
}
}
</params>
<datasource lang="json5">
{
type: "table",
table: "student_profiles_table",
output: "students_out"
}
</datasource>
<response>
({ ok: true, count: (@students_out || []).length, rows: @students_out })
</response>
javascript Example
javascript is the custom-code building block.
Use it when:
- an expression becomes too large or too reusable to leave inline
- a transformation deserves a name
- you want custom logic without hiding it in component actions
Good uses:
- string normalization
- custom scoring
- reusable formatting
- derived value computation
Example scripts/NormalizeStudentName.xu:
<meta lang="json5">
{
id: "normalize_student_name",
menuTitle: "Normalize Student Name"
}
</meta>
<params lang="json5">
{
in: {
raw_name_in: "string"
},
out: {
normalized_name_out: "string"
}
}
</params>
<code>
return (@raw_name_in || "")
.trim()
.toLowerCase()
.replace(/\b\w/g, (letter) => letter.toUpperCase());
</code>
alert Example
alert is the reusable messaging building block.
Use it when:
- a toast or feedback message should be consistent across the app
- several workflows need the same success or error message
- you want user messaging to live in its own source file instead of being embedded in UI logic
Example alerts/StudentSaved.xu:
<meta lang="json5">
{
id: "student_saved",
menuTitle: "Student Saved"
}
</meta>
<alert lang="json5">
{
alertDisplay: "toast",
alertType: "success",
alertTitle: "Student saved",
createLog: false
}
</alert>
Table Example
table is the data model building block.
Use it when:
- your app stores structured records
get_dataorset_dataunits target database-backed tables- you need indexes that match real query patterns
Tables usually define:
- field ids
- field types
- indexes
- stable resource ids used by datasource units
Example tables/student-profiles.table.json5:
{
id: "student_profiles_table",
menuTitle: "Student Profiles Table",
fields: [
{ field_id: "student_id", type: "string" },
{ field_id: "full_name", type: "string" },
{ field_id: "email", type: "string" },
{ field_id: "campus", type: "string" }
],
indexes: [
{ id: "campus_idx", name: "Campus", keys: ["campus"] }
]
}
Route Example
route is the navigation-structure building block.
Use it when:
- the app has named destinations
- you want menu structure to be explicit in source
- you want navigation to be modeled as an app asset, not just ad hoc button logic
Routes do not replace components. They describe how components and destinations are presented as a navigable app.
Example routes/app.route.json5:
{
id: "app_route",
menuTitle: "App Route",
menu: [
{ title: "Overview", prog: "app" },
{ title: "Students", prog: "student_list" },
{ title: "Profiles", prog: "profile_center" }
]
}
AI Agent Example
ai_agent is the assistant-resource building block.
Use it when:
- the app needs a defined AI helper
- agent configuration should live beside the rest of the app source
- you want AI capabilities to be visible as part of the app architecture
This is especially useful when an app has:
- a help assistant
- a scheduling assistant
- a support or triage assistant
- a future copiloting feature that should be modeled early
Example ai-agents/class-helper.agent.json5:
{
id: "class_helper",
menuTitle: "Class Helper",
config: {
provider: "openai",
model: "gpt-5"
}
}
Root App Example
Minimal App.xu:
<meta lang="json5">
{
menuTitle: "Hello Xuda",
uiFramework: "@xuda.io/xuda-framework-plugin-tailwind"
}
</meta>
<template>
<single-view>
<section class="min-h-screen grid place-items-center p-8 text-center">
<div class="space-y-4">
<img class="w-20 h-20 mx-auto rounded-2xl shadow-xl" src="/favicon.ico" alt="Xuda logo">
<h1>Hello from xuda-cli</h1>
<p>Start with App.xu, then add feature units under the typed folders.</p>
</div>
</section>
</single-view>
</template>
Client Script and Styles
Component <script> blocks are compiled into client-side mount modules.
Example:
<script>
export default function mount(ctx) {
console.log('mounted', ctx.mount.id);
}
</script>
If the default export returns a function, that function is used as a disposer on unload.
Component <style> blocks are collected into the generated component stylesheet served by the app.
Naming and Id Rules
Rules:
App.xualways compiles to program idapp- for other
.xufiles, the id resolves from: meta.idmount.id- file basename
- for structured resources, the id resolves from:
id_id- file basename
- duplicate ids are not allowed
Plugins
Install plugins as npm dependencies in the app project.
Typical setup:
npm install @xuda.io/xuda-framework-plugin-tailwind
npm install @xuda.io/xuda-dbs-plugin-xuda
Typical usage:
@xuda.io/xuda-framework-plugin-tailwindUse it throughuiFrameworkin component metadata@xuda.io/xuda-dbs-plugin-xudaUse it by authoringtable,get_data, andset_dataresources
Example:
<meta lang="json5">
{
uiFramework: "@xuda.io/xuda-framework-plugin-tailwind"
}
</meta>
Generated Runtime Docs
xuda-cli always compiles runtime docs into:
node_modules/.project_data/
Important rules:
- the runtime reads from
node_modules/.project_data/ - you author source in
.xuand.json5files, not in generated docs - saving a supported source file regenerates the matching runtime JSON docs
- legacy
project_data/or root.project_data/can still be imported during migration, but they are not the live runtime target
You should treat node_modules/.project_data/ as generated output.
Sync and Cloud Projects
If api_key exists in xuda.config.js, you can run:
npm run sync
sync does this:
- verifies the app exposes the required CPI methods
- verifies the current API key can use those methods
- downloads remote docs into
node_modules/.project_data/ - creates missing local source files from those docs
- recompiles local source back into
node_modules/.project_data/ - uploads changed docs back to the cloud
Required exposed CPI methods:
get_app_system_api_methodsget_app_api_keysget_project_docsupdate_app_info_doc_to_db_couch
Important sync rule:
- source import is non-destructive by default, so existing local source files are skipped instead of being overwritten
Recommended Workflow
For new apps:
- Create the app with
npm create xuda-cli@latest my-app - Install dependencies with
npm install - Keep
index.htmlsmall and use it only as the page shell - Build the actual app in
App.xu - Move feature screens into
components/ - Put shared state into
globals/ - Put reads and writes into
data/get/anddata/set/ - Put tables into
tables/ - Install plugins with npm instead of looking for a CLI plugin command
- Treat
node_modules/.project_data/as generated output
A Typical Xuda App Architecture
A practical Xuda app often looks like this:
App.xuroot shell, login state, high-level navigation, main panelscomponents/feature screens and reusable panelsglobals/shared identity, workspace, or preference statedata/get/named loaders for tables and filtered readsdata/set/named save/delete/update unitsdata/batch/background-style or iterative processingapis/app-facing or machine-facing responsesscripts/custom transformations and helpersalerts/reusable user feedbacktables/data shape and indexesroutes/destination map and menu structureai-agents/future-facing or current assistant definitions
If you keep each concern in the right block, the app is usually:
- easier to read
- easier to debug
- easier to reuse
- easier to sync with cloud docs later
Example App
For a full multi-screen sample, see the published example package:
xuda-studant-app-example
That example includes:
- login flow
- overview dashboard
- students screen
- tasks screen
- profiles screen
- route resource
- globals
- get_data
- set_data
- batch
- api
- javascript
- alert
- ai agent
- database-backed examples
- Tailwind-based styling
Troubleshooting
I can run the app, but I do not see app.json
Run npm run dev from the project root. xuda-cli writes generated runtime docs when it loads the project.
Do I need both index.html and App.xu?
Yes, usually.
index.htmlis the document shellApp.xuis the root Xuda UI
Can I remove App.xu and start from a component under components/?
You can build reusable screens under components/, but the recommended root is still App.xu.
Where should I put business logic?
Use dedicated source units:
get_datafor readsset_datafor writesbatchfor record iterationapifor API-style outputsjavascriptfor custom JS logicalertfor messaging/feedback
Summary
Use xuda-cli like this:
index.htmlfor the page shellApp.xufor the root app- typed folders for every Xuda building block
- npm-installed plugins
node_modules/.project_data/as the only live runtime doc foldernpm run devfor local developmentnpm run syncwhenapi_keyis configured and you want cloud sync