/docs / apps / examples

App Examples

Nebo apps are complete frontend applications built with any framework you choose. They are not HTML pages embedded in a chat window -- they are full applications that open in their own window, backed by an AI agent and an optional native sidecar binary. This page walks through real-world apps spanning vanilla HTML, HTMX, Vue 3, React 19, Solid.js, and SvelteKit -- from a 220-line minimal example to a 24-skill enterprise legal assistant.

Key insight: Every app in this guide uses @neboai/app-sdk for storage, identity, agent invocation, and external HTTP fetching. The frontend framework is entirely your choice -- Nebo does not impose one. Use React, Vue, Solid, Svelte, HTMX, or plain HTML.

Common Architecture

Every Nebo app follows the same directory convention regardless of which frontend framework it uses. The build system is a Makefile that orchestrates pnpm (frontend) and cargo (sidecar) into a final ui/ directory and a bin/ directory.

Standard directory structure

my-app/
+-- manifest.json          # App identity, window config, permissions
+-- agent.json             # Skills, workflows, tools, inputs
+-- AGENT.md               # Agent persona (system prompt)
+-- Makefile               # Orchestrates frontend + sidecar builds
+-- frontend/              # Any framework: React, Vue, Solid, Svelte, etc.
|   +-- package.json
|   +-- src/
|   +-- vite.config.ts
+-- sidecar/               # Optional Rust binary (gRPC over Unix socket)
|   +-- Cargo.toml
|   +-- src/
+-- skills/                # Bundled skill definitions (SKILL.md files)
+-- ui/                    # Build output (frontend static files)
|   +-- index.html
+-- bin/                   # Build output (sidecar binary)
    +-- my-app

manifest.json schema

The manifest declares the app's identity, window configuration, and required permissions. Every app has one.

{
  "id": "my-app",
  "name": "@nebo/agents/my-app",
  "version": "1.0.0",
  "description": "What the app does.",
  "type": "app",
  "permissions": [
    "storage:readwrite",
    "subagent:invoke",
    "network:outbound"
  ],
  "window": {
    "title": "My App",
    "width": 1200,
    "height": 800,
    "min_width": 600,
    "min_height": 500,
    "resizable": true
  }
}

agent.json schema

The agent configuration defines skills, workflows, sidecar tools, user-configurable inputs, and plugin dependencies. Simple apps may leave this mostly empty; enterprise apps can define dozens of skills and complex workflow DAGs.

{
  "skills": ["skills/my-skill-1", "skills/my-skill-2"],
  "inputs": [
    {
      "key": "setting_name",
      "label": "Setting Label",
      "type": "select",
      "options": [
        { "label": "Option A", "value": "a" },
        { "label": "Option B", "value": "b" }
      ],
      "default": "a",
      "required": false
    }
  ],
  "requires": {
    "plugins": ["plugin-slug-1", "plugin-slug-2"]
  },
  "tools": [
    {
      "name": "tool_name",
      "description": "What the tool does",
      "method": "GET",
      "path": "/api/endpoint"
    }
  ],
  "workflows": {
    "workflow-name": {
      "description": "What the workflow does",
      "trigger": { "type": "manual" },
      "activities": [...]
    }
  }
}

Build pattern

A typical Makefile builds the frontend and sidecar in parallel:

.PHONY: all build build-frontend build-sidecar dev clean

all: build

build: build-frontend build-sidecar

build-frontend:
	cd frontend && pnpm install && pnpm build
	@echo "Frontend built -> ui/"

build-sidecar:
	cd sidecar && cargo build --release
	mkdir -p bin
	cp sidecar/target/release/my-sidecar bin/my-app
	@echo "Sidecar built -> bin/my-app"

dev:
	@echo "Start sidecar: cd sidecar && cargo run"
	@echo "Start frontend: cd frontend && pnpm dev"

clean:
	rm -rf ui/ bin/
	cd sidecar && cargo clean
	cd frontend && rm -rf node_modules

Minimal Example: hello-app

The simplest possible Nebo app. A single HTML file with no build step, no framework, no sidecar. It demonstrates every SDK capability: identity, storage, agent invoke, external fetch, and embedded chat.

PropertyValue
FrontendVanilla HTML + JS
SidecarNone
Skills0
PermissionsNone (SDK features are always available)
Build stepNone -- serve ui/index.html directly

manifest.json

{
  "id": "hello-app",
  "name": "@nebo/agents/hello-app",
  "version": "1.0.0",
  "description": "A minimal Nebo app that demonstrates the SDK -- storage, agent invoke, and HTTP proxy.",
  "type": "app",
  "window": {
    "title": "Hello App",
    "width": 800,
    "height": 600,
    "min_width": 400,
    "min_height": 300,
    "resizable": true
  },
  "permissions": []
}

agent.json

The simplest possible agent configuration -- no skills, no workflows, no inputs:

{
  "workflows": {},
  "skills": [],
  "inputs": []
}

AGENT.md (persona)

# Hello App

You are the Hello App assistant. You help users understand how Nebo apps work.

When asked a question, respond concisely and helpfully. Explain SDK concepts
like storage, agent invoke, and HTTP proxy in simple terms.

## What You Know

- Nebo apps are agents with a face (UI) and optional sidecar (binary)
- The @nebo/app-sdk mirrors native browser APIs: fetch, WebSocket, localStorage
- Apps always pop out in their own window -- never inline
- Storage is key-value, persisted server-side, scoped to this app
- External HTTP requests are proxied through Nebo (zero CORS issues)

ui/index.html -- the complete app

This single file is the entire frontend. It loads the SDK via a script tag and uses five SDK capabilities. Study this file to understand the full SDK surface area.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="nebo-app-id" content="hello-app">
  <title>Hello App</title>
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body {
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
      background: #f8f9fa; color: #1a1a1a;
      display: flex; flex-direction: column; min-height: 100vh;
    }
    header {
      padding: 16px 24px; border-bottom: 1px solid #e5e7eb;
      background: white; display: flex; align-items: center; gap: 12px;
    }
    header h1 { font-size: 16px; font-weight: 600; }
    .layout { flex: 1; display: flex; min-height: 0; }
    .main { flex: 1; overflow-y: auto; padding: 24px; max-width: 640px; }
    .chat-panel { width: 380px; border-left: 1px solid #e5e7eb; }
    .card {
      background: white; border: 1px solid #e5e7eb; border-radius: 12px;
      padding: 20px; margin-bottom: 16px;
    }
    button {
      background: #0077a8; color: white; border: none; border-radius: 8px;
      padding: 8px 16px; font-size: 13px; cursor: pointer;
    }
    .response {
      background: #f0fdf4; border: 1px solid #86efac; border-radius: 8px;
      padding: 12px; font-size: 13px; margin-top: 12px; white-space: pre-wrap;
    }
    .response.error { background: #fef2f2; border-color: #fca5a5; }
  </style>
</head>
<body>
  <header>
    <h1 id="app-title">Hello App</h1>
  </header>

  <div class="layout">
    <div class="main">
      <div class="card">
        <h2>Identity</h2>
        <p>Fetch this app's agent profile from Nebo.</p>
        <button onclick="loadIdentity()">Load Identity</button>
        <div id="identity-result"></div>
      </div>

      <div class="card">
        <h2>Storage</h2>
        <p>Read and write key-value pairs persisted by Nebo.</p>
        <input type="text" id="kv-key" placeholder="Key">
        <input type="text" id="kv-value" placeholder="Value">
        <button onclick="saveKV()">Save</button>
        <button onclick="loadKV()">Load</button>
        <button onclick="listKV()">List All</button>
      </div>

      <div class="card">
        <h2>External Fetch</h2>
        <p>Fetch data from an external API through Nebo's CORS-free proxy.</p>
        <input type="text" id="fetch-url" value="https://httpbin.org/get">
        <button onclick="doFetch()">Fetch</button>
        <div id="fetch-result"></div>
      </div>

      <div class="card">
        <h2>Agent Invoke</h2>
        <p>Send a message to this app's agent via the SDK.</p>
        <input type="text" id="agent-input" placeholder="Ask the agent something...">
        <button onclick="askAgent()" id="agent-btn">Ask</button>
        <div id="agent-response"></div>
      </div>
    </div>

    <div class="chat-panel" id="chat-container"></div>
  </div>

  <script src="/sdk/nebo.global.js"></script>
  <script>
    const nebo = window.NeboAppSDK.nebo;

    // -- Embedded Chat --
    nebo.chat.mount(document.getElementById('chat-container'), {
      height: '100%',
      borderless: true,
      placeholder: 'Chat with Hello App...',
    });

    nebo.chat.onMessage(function(msg) {
      if (msg.type === 'nebo:response-complete') {
        console.log('[hello-app] Agent finished:', msg.text?.substring(0, 80));
      }
    });

    // -- Identity --
    window.loadIdentity = async function() {
      const me = await nebo.identity.get();
      document.getElementById('app-title').textContent = me.displayName || me.name;
    };

    // -- Storage --
    window.saveKV = async function() {
      const key = document.getElementById('kv-key').value;
      const value = document.getElementById('kv-value').value;
      if (!key) return;
      await nebo.storage.setItem(key, value);
    };

    window.loadKV = async function() {
      const key = document.getElementById('kv-key').value;
      if (!key) return;
      const value = await nebo.storage.getItem(key);
      alert(value !== null ? key + ' = ' + value : 'Key not found');
    };

    window.listKV = async function() {
      const keys = await nebo.storage.keys();
      const items = await Promise.all(keys.map(async function(k) {
        const v = await nebo.storage.getItem(k);
        return k + ': ' + v;
      }));
      alert(items.join('\n') || 'No items stored yet');
    };

    // -- Agent Invoke --
    window.askAgent = async function() {
      const input = document.getElementById('agent-input');
      const msg = input.value.trim();
      if (!msg) return;
      const result = await nebo.agents.invoke(msg);
      document.getElementById('agent-response').innerHTML =
        '<div class="response">' + (result.text || JSON.stringify(result)) + '</div>';
    };

    // -- External Fetch --
    window.doFetch = async function() {
      const url = document.getElementById('fetch-url').value;
      if (!url) return;
      const resp = await nebo.fetch(url);
      const data = await resp.json();
      document.getElementById('fetch-result').innerHTML =
        '<div class="response"><pre>' + JSON.stringify(data, null, 2) + '</pre></div>';
    };

    loadIdentity();
  </script>
</body>
</html>
Five SDK capabilities in one file: nebo.identity.get() for the agent's profile, nebo.storage for persistent key-value data, nebo.agents.invoke() for programmatic agent calls, nebo.fetch() for CORS-free external HTTP, and nebo.chat.mount() for an embedded chat panel. See App SDK for the full API reference.

HTMX Example: journal

A server-driven journaling app that uses HTMX instead of a JavaScript framework. The frontend is a single HTML file with no build step -- all interactivity comes from HTMX attributes that make requests to the Rust sidecar. The sidecar renders HTML partials and manages a SQLite database for journal entries.

PropertyValue
FrontendHTMX (zero JS framework)
SidecarRust (serves HTML partials over gRPC)
Permissionsstorage:readwrite, subagent:invoke
Build stepSidecar only (cargo build --release)

manifest.json

{
  "id": "journal",
  "name": "@nebo/agents/journal",
  "version": "1.0.0",
  "description": "AI-powered journal with reflection prompts. Built with HTMX + Rust sidecar -- zero JS framework.",
  "type": "app",
  "permissions": ["storage:readwrite", "subagent:invoke"],
  "window": {
    "title": "Journal",
    "width": 700,
    "height": 800,
    "min_width": 400,
    "min_height": 500,
    "resizable": true
  }
}

Architecture

The journal app demonstrates the zero-JavaScript-framework approach. HTMX sends requests to the sidecar, which returns HTML fragments that HTMX swaps into the page. The sidecar handles all data persistence in SQLite.

# Directory structure
journal/
+-- manifest.json
+-- agent.json
+-- AGENT.md
+-- Makefile
+-- sidecar/              # Rust sidecar (renders HTML partials)
|   +-- Cargo.toml
|   +-- src/
+-- ui/
|   +-- index.html        # HTMX frontend (no build step)
+-- bin/
    +-- journal           # Compiled sidecar binary

# Makefile -- note: no frontend build step
build: build-sidecar

build-sidecar:
	cd sidecar && cargo build --release
	mkdir -p bin
	cp sidecar/target/release/journal-sidecar bin/journal
	@echo "Frontend: ui/index.html (no build step -- HTMX)"

AGENT.md

# Journal Companion

You are a thoughtful journaling companion. You help users reflect on their day,
clarify their thinking, and build self-awareness.

## What You Do

1. Ask reflective questions that go deeper than surface-level
2. Notice patterns across entries (recurring themes, emotions, goals)
3. Offer gentle reframes when the user is stuck in negative loops
4. Celebrate progress -- even small wins

## Communication Style

- Warm but not saccharine
- Questions over advice
- Mirror the user's energy -- if they're brief, be brief
- Never judge what they write

Vue 3 Example: contacts

A full single-page application built with Vue 3, Vite, and TypeScript. The frontend compiles to static files in ui/, and a Rust sidecar manages the contact database. This is a typical setup for apps that need reactive UI patterns and a rich component library.

PropertyValue
FrontendVue 3.5 + Vite 6 + TypeScript
SidecarRust
Permissionsstorage:readwrite, subagent:invoke, network:outbound

manifest.json

{
  "id": "contacts",
  "name": "@nebo/agents/contacts",
  "version": "1.0.0",
  "description": "Smart contact manager with relationship intelligence. Built with Vue + Rust sidecar.",
  "type": "app",
  "permissions": ["storage:readwrite", "subagent:invoke", "network:outbound"],
  "window": {
    "title": "Contacts", "width": 960, "height": 700,
    "min_width": 480, "min_height": 400, "resizable": true
  }
}

frontend/package.json

{
  "name": "contacts-frontend",
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc -b && vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "@a2ui/lit": "^0.9.0",
    "@a2ui/web_core": "^0.9.0",
    "@neboai/app-sdk": "^0.1.0",
    "vue": "^3.5.0"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^5.0.0",
    "typescript": "^5.9.0",
    "vite": "^6.0.0",
    "vue-tsc": "^2.0.0"
  }
}
Note: The @a2ui/lit and @a2ui/web_core packages provide Nebo's shared component library. These are framework-agnostic web components that work with Vue, React, Solid, or any other framework.

React 19 Example: portfolio

An investment portfolio tracker built with React 19, Vite 6, and TypeScript. The Rust sidecar handles market data fetching and portfolio calculations.

manifest.json

{
  "id": "portfolio",
  "name": "@nebo/agents/portfolio",
  "version": "1.0.0",
  "description": "Investment portfolio tracker with AI analysis. Built with React + Rust sidecar.",
  "type": "app",
  "permissions": ["storage:readwrite", "subagent:invoke", "network:outbound"],
  "window": {
    "title": "Portfolio", "width": 1100, "height": 750,
    "min_width": 500, "min_height": 400, "resizable": true
  }
}

frontend/package.json

{
  "name": "portfolio-frontend",
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc -b && vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "@a2ui/react": "^0.9.0",
    "@a2ui/web_core": "^0.9.0",
    "@neboai/app-sdk": "^0.1.0",
    "react": "^19.0.0",
    "react-dom": "^19.0.0"
  },
  "devDependencies": {
    "@types/react": "^19.0.0",
    "@types/react-dom": "^19.0.0",
    "@vitejs/plugin-react": "^4.0.0",
    "typescript": "^5.9.0",
    "vite": "^6.0.0"
  }
}
React-specific bindings: Note the @a2ui/react package instead of @a2ui/lit. Nebo provides framework-specific wrappers for React that integrate with hooks and JSX patterns. The core SDK (@neboai/app-sdk) is the same across all frameworks.

Solid.js Example: dashboard

A business metrics dashboard built with Solid.js 1.9 and Vite. Solid.js compiles reactive primitives into vanilla DOM operations -- no virtual DOM -- making it ideal for data-heavy dashboards that need fast updates.

manifest.json

{
  "id": "dashboard",
  "name": "@nebo/agents/dashboard",
  "version": "1.0.0",
  "description": "Business metrics dashboard with AI insights. Built with Solid.js + Rust sidecar.",
  "type": "app",
  "permissions": ["storage:readwrite", "subagent:invoke", "network:outbound"],
  "window": {
    "title": "Dashboard", "width": 1200, "height": 800,
    "min_width": 600, "min_height": 450, "resizable": true
  }
}

frontend/package.json

{
  "name": "dashboard-frontend",
  "private": true,
  "version": "0.1.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "@a2ui/lit": "^0.9.0",
    "@a2ui/web_core": "^0.9.0",
    "@neboai/app-sdk": "^0.1.0",
    "solid-js": "^1.9.0"
  },
  "devDependencies": {
    "typescript": "^5.7.0",
    "vite": "^6.0.0",
    "vite-plugin-solid": "^2.11.0"
  }
}

SvelteKit Example: ads-manager

A Meta Ads management dashboard built with SvelteKit 2 and the static adapter. SvelteKit provides file-based routing, server-side rendering (compiled to static), and Svelte 5 runes for reactivity.

manifest.json

{
  "id": "ads-manager",
  "name": "@nebo/agents/ads-manager",
  "version": "1.0.0",
  "description": "Meta Ads management dashboard with AI-powered optimization.",
  "type": "app",
  "permissions": ["storage:readwrite", "subagent:invoke", "network:outbound"],
  "window": {
    "title": "Ads Manager", "width": 1280, "height": 900,
    "min_width": 768, "min_height": 500, "resizable": true
  }
}

frontend/package.json

{
  "name": "ads-manager-frontend",
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "vite dev",
    "build": "vite build",
    "preview": "vite preview",
    "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json"
  },
  "devDependencies": {
    "@sveltejs/adapter-static": "^3.0.0",
    "@sveltejs/kit": "^2.0.0",
    "@sveltejs/vite-plugin-svelte": "^4.0.0",
    "svelte": "^5.0.0",
    "svelte-check": "^4.0.0",
    "typescript": "^5.9.0",
    "vite": "^6.0.0"
  },
  "dependencies": {
    "@neboai/app-sdk": "^0.1.0"
  }
}
SvelteKit + static adapter: Since Nebo apps serve static files from ui/, SvelteKit must use @sveltejs/adapter-static to prerender all routes at build time. Runtime server-side rendering is handled by the Rust sidecar, not by SvelteKit's Node.js server.

Enterprise Example: brief

Brief is a full-stack AI-powered legal assistant. SvelteKit frontend with Tailwind 4, PDF/DOCX rendering libraries, a Rust sidecar with SQLite for document storage, 24 bundled skills, 8 automated workflows, and integration with Google Workspace and DocuSign via MCP plugins. This represents the upper end of what a Nebo app can be.

PropertyValue
FrontendSvelteKit 2 + Svelte 5 + Tailwind 4 + adapter-static
SidecarRust + SQLite
Skills24
Workflows8 (manual, event-driven, scheduled, watch triggers)
Sidecar tools60+ REST endpoints exposed as agent tools
Plugin dependenciesnebo-office, gws, docusign

frontend/package.json

{
  "name": "brief-frontend",
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "vite dev",
    "build": "vite build",
    "preview": "vite preview",
    "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json"
  },
  "devDependencies": {
    "@sveltejs/adapter-static": "^3.0.0",
    "@sveltejs/kit": "^2.0.0",
    "@sveltejs/vite-plugin-svelte": "^4.0.0",
    "@tailwindcss/vite": "^4.3.0",
    "svelte": "^5.0.0",
    "svelte-check": "^4.0.0",
    "tailwindcss": "^4.3.0",
    "typescript": "^5.9.0",
    "vite": "^6.0.0"
  },
  "dependencies": {
    "@a2ui/lit": "^0.9.0",
    "@a2ui/web_core": "^0.9.0",
    "@neboai/app-sdk": "^0.1.0",
    "docx-preview": "^0.3.7",
    "exceljs": "^4.4.0",
    "marked": "^18.0.3",
    "pdfjs-dist": "^4.10.38"
  }
}

Directory structure

brief/
+-- manifest.json
+-- agent.json               # 24 skills, 60+ tools, 8 workflows
+-- AGENT.md
+-- Makefile
+-- frontend/                # SvelteKit + Tailwind 4
|   +-- package.json
|   +-- src/
|   +-- vite.config.ts
+-- sidecar/                 # Rust + SQLite
|   +-- Cargo.toml
|   +-- src/
+-- proto/                   # Shared gRPC definitions
+-- skills/                  # 24 bundled SKILL.md files
|   +-- workspace-management/
|   +-- document-analysis/
|   +-- contract-summary/
|   +-- cp-checklist/
|   +-- docx-generation/
|   +-- nda-review/
|   +-- pipeline-orchestration/
|   +-- ... (17 more)
+-- docs/
+-- ui/                      # Build output
+-- bin/
    +-- brief

Skills (24 bundled)

Brief ships with a comprehensive set of legal analysis skills:

workspace-management          # Project/folder CRUD
document-analysis              # Document type identification
contract-summary               # Key terms extraction
cp-checklist                   # Conditions precedent tracking
tabular-extraction             # Structured data extraction
docx-generation                # Create DOCX from markdown
document-editing               # Tracked change suggestions
review                         # Tabular review orchestration
nda-review                     # NDA-specific analysis
vendor-agreement-review        # Vendor agreement analysis
saas-msa-review                # SaaS MSA analysis
amendment-history              # Amendment tracking
escalation-flagger             # Risk escalation
stakeholder-summary            # Executive summaries
renewal-tracker                # Contract renewal tracking
cold-start-interview           # New user onboarding
customize                      # User preference setup
matter-workspace               # Matter management
review-proposals               # Proposal review
contract-inbox-triage          # Email ingestion
docusign-envelope-handler      # DocuSign integration
quorum-extraction              # Multi-agent extraction
escalation-surface             # Escalation UI
pipeline-orchestration         # Batch processing

Workflows

Brief defines 8 workflows with different trigger types. See Workflows for trigger type documentation.

WorkflowTriggerDescription
contract-inboxwatch (Gmail)Watch inbox for contract attachments, auto-analyze
contract-reviewmanualFull contract review with summary + CP checklist
document-pipelineevent3-agent quorum extraction with consensus
document-triageeventAuto-analyze on upload
docusign-envelope-pollheartbeat (30m)Poll DocuSign for signed documents
folder-watchfolderWatch filesystem for new documents
morning-review-digestschedule (cron)Daily 8am digest of pending reviews
webhook-ingestevent (webhook)Ingest documents from external webhooks

User-configurable inputs

Brief lets users configure their experience through the inputs field in agent.json. These appear as settings in the app's configuration panel:

"inputs": [
  {
    "key": "default_model",
    "label": "Default LLM Model",
    "type": "select",
    "default": "claude-sonnet-4-6",
    "options": [
      { "label": "Claude Opus 4.6", "value": "claude-opus-4-6" },
      { "label": "Claude Sonnet 4.6", "value": "claude-sonnet-4-6" },
      { "label": "Claude Haiku 4.5", "value": "claude-haiku-4-5" }
    ]
  },
  {
    "key": "practice_area",
    "label": "Primary Practice Area",
    "type": "select",
    "default": "corporate",
    "options": [
      { "label": "Corporate / M&A", "value": "corporate" },
      { "label": "Banking & Finance", "value": "finance" },
      { "label": "Intellectual Property", "value": "ip" },
      { "label": "Litigation", "value": "litigation" },
      { "label": "General Practice", "value": "general" }
    ]
  }
]

Multi-Agent Example: small-business-suite

The largest app in the Nebo ecosystem. A complete small business command center with 31 skills, 12 MCP connector plugins, 18 workflows (scheduled, event-driven, and manual), and approval gates. Built with Solid.js for the frontend and Rust for the sidecar.

PropertyValue
FrontendSolid.js 1.9 + Vite 6
Skills31
Workflows18
Plugin dependencies12 MCP connectors
Permissionsstorage:readwrite, subagent:invoke, network:outbound, memory:read, mcp:invoke

Plugin dependencies (12 MCP connectors)

"requires": {
  "plugins": [
    "quickbooks",        // Accounting + invoicing
    "paypal",            // Payment processing
    "hubspot",           // CRM + sales pipeline
    "canva",             // Design + marketing assets
    "docusign",          // Contract signing
    "slack",             // Team communication
    "stripe",            // Payment processing
    "square",            // POS + payments
    "ms365",             // Microsoft Office suite
    "gmail",             // Email
    "google-calendar",   // Calendar
    "google-drive"       // File storage
  ]
}

Skills (31 bundled)

business-pulse               # Real-time business health
call-list                    # Daily prioritized call list
canva-creator                # Canva design generation
cash-flow-snapshot           # Cash flow analysis
close-month                  # Month-end closing
content-strategy             # Content planning
contract-review              # Contract analysis
crm-cleanup                  # CRM data hygiene
crm-maintenance              # Ongoing CRM upkeep
customer-pulse               # Customer health scoring
customer-pulse-check         # Customer check-in
friday-brief                 # End-of-week summary
handle-complaint             # Complaint resolution
invoice-chase                # Overdue invoice follow-up
job-post-builder             # Job listing creation
lead-triage                  # Lead scoring + routing
margin-analyzer              # Profit margin analysis
monday-brief                 # Start-of-week planning
month-end-prep               # Pre-close preparation
month-heads-up               # Monthly forecast
plan-payroll                 # Payroll preparation
price-check                  # Competitive pricing
quarterly-review             # Quarterly business review
review-contract              # Contract review (detailed)
run-campaign                 # Marketing campaign execution
sales-brief                  # Sales pipeline summary
smb-onboard                  # New business onboarding
smb-router                   # Intent routing
tax-prep                     # Tax preparation
tax-season-organizer         # Tax season planning
ticket-deflector             # Support ticket triage

Workflows (18)

# Scheduled workflows
morning-pulse                # Daily 7:30am business health check
monday-brief                 # Weekly Monday planning
friday-brief                 # Weekly Friday wrap-up
weekly-business-review       # Weekly performance review
payroll-check                # Bi-weekly payroll prep
invoice-chase-auto           # Daily overdue invoice follow-up
contract-deadline-scan       # Daily contract deadline check
quarterly-review             # Quarterly business analysis
month-end-close              # Monthly close process

# Manual workflows
run-campaign                 # Marketing campaign execution
tax-prep                     # Tax season preparation
crm-cleanup                  # CRM data maintenance
review-contract              # Contract review
hire                         # Hiring workflow

# Event-driven workflows
check-business               # On-demand business check
deal-won                     # Triggered on deal close
complaint-received           # Triggered on complaint
lead-qualified               # Triggered on lead qualification

Shared gRPC Protocol

All app sidecars implement the same gRPC service defined in proto/ui.proto. This protocol lets Nebo communicate with any sidecar -- regardless of implementation language -- through a Unix domain socket. See App Sidecar for the full architecture.

proto/common.proto

syntax = "proto3";

package apps.v0;

message HealthCheckRequest {}

message HealthCheckResponse {
  bool healthy = 1;
  string version = 2;
  string name = 3;
}

message SettingsMap {
  map<string, string> values = 1;
}

message Empty {}

proto/ui.proto

syntax = "proto3";

package apps.v0;

import "proto/common.proto";

service UIService {
  rpc HealthCheck(HealthCheckRequest) returns (HealthCheckResponse);
  rpc Configure(SettingsMap) returns (Empty);
  rpc HandleRequest(HttpRequest) returns (HttpResponse);
}

message HttpRequest {
  string method = 1;
  string path = 2;
  string query = 3;
  map<string, string> headers = 4;
  bytes body = 5;
}

message HttpResponse {
  int32 status_code = 1;
  map<string, string> headers = 2;
  bytes body = 3;
}

The UIService has three methods:

  • HealthCheck -- Nebo calls this on startup and periodically to verify the sidecar is running. Returns the sidecar's name and version.
  • Configure -- Passes user configuration (from agent.json inputs) to the sidecar at startup.
  • HandleRequest -- Proxies HTTP requests from the agent's tools to the sidecar. The agent defines tool endpoints in agent.json (e.g., GET /projects), and Nebo translates them into gRPC HandleRequest calls.
Communication path: Agent tool call --> Nebo translates to HttpRequest --> gRPC over Unix socket --> Sidecar processes --> HttpResponse --> Agent receives result. The frontend can also make requests to the sidecar through the SDK's fetch proxy.

SDK Integration Patterns

Every app uses @neboai/app-sdk regardless of framework. The SDK provides five core capabilities that mirror familiar browser APIs. See App SDK for the full reference.

Loading the SDK

In vanilla HTML, load via script tag. In framework apps, import the npm package:

<!-- Vanilla HTML: script tag -->
<script src="/sdk/nebo.global.js"></script>
<script>
  const nebo = window.NeboAppSDK.nebo;
</script>

// Framework apps: npm import
import { nebo } from '@neboai/app-sdk';

Identity

const me = await nebo.identity.get();
// { id, name, displayName, model, skills: [...] }

Storage

Persistent key-value storage scoped to the current app. Mirrors the localStorage API:

await nebo.storage.setItem('key', 'value');
const value = await nebo.storage.getItem('key');
const allKeys = await nebo.storage.keys();

Agent Invoke

const result = await nebo.agents.invoke('Analyze this document');
// { text: "The document contains..." }

Fetch (CORS-free HTTP proxy)

const resp = await nebo.fetch('https://api.example.com/data');
const data = await resp.json();

Chat Embed

nebo.chat.mount(document.getElementById('chat-container'), {
  height: '100%',
  borderless: true,
  placeholder: 'Ask a question...',
});

nebo.chat.onMessage(function(msg) {
  if (msg.type === 'nebo:response-complete') {
    console.log('Agent finished:', msg.text);
  }
});

Summary Table

All example apps at a glance. Every one of these is a complete, standalone frontend application -- not a widget or a page fragment.

AppFrontendSidecarSkillsComplexity
hello-appVanilla HTML/JSNone0Minimal
journalHTMXRust0Simple
contactsVue 3 + ViteRust0Standard
portfolioReact 19 + ViteRust0Standard
dashboardSolid.js 1.9 + ViteRust0Standard
ads-managerSvelteKit 2 + Svelte 5Rust0Standard
briefSvelteKit 2 + Tailwind 4Rust + SQLite24Enterprise
small-business-suiteSolid.js 1.9 + ViteRust31Enterprise
Choose your framework, not Nebo's. From a single HTML file with zero build tooling to a SvelteKit app with Tailwind 4 and PDF rendering -- the platform does not constrain your frontend choice. The only constant is @neboai/app-sdk, which works identically everywhere.

For more details on the underlying systems, see: Apps Overview for the app lifecycle, App SDK for the full SDK API reference, and App Sidecar for the gRPC sidecar architecture.