botui/PROMPT.md
Rodrigo Rodriguez (Pragmatismo) e3b5929b99 fix(slides): remove duplicate cacheElements/bindEvents functions causing null error
The duplicate functions at lines 455-486 were redefining cacheElements and
bindEvents with wrong element IDs (kebab-case vs camelCase in HTML).
This caused 'Cannot read properties of null' error on slides app init.
2026-01-12 14:05:06 -03:00

24 KiB

BotUI Development Prompt Guide

Version: 6.1.0
Purpose: LLM context for BotUI development


ZERO TOLERANCE POLICY

This project has the strictest code quality requirements possible.

EVERY SINGLE WARNING MUST BE FIXED. NO EXCEPTIONS.


ABSOLUTE PROHIBITIONS

❌ NEVER use #![allow()] or #[allow()] in source code to silence warnings
❌ NEVER use _ prefix for unused variables - DELETE the variable or USE it
❌ NEVER use .unwrap() - use ? or proper error handling
❌ NEVER use .expect() - use ? or proper error handling  
❌ NEVER use panic!() or unreachable!() - handle all cases
❌ NEVER use todo!() or unimplemented!() - write real code
❌ NEVER leave unused imports - DELETE them
❌ NEVER leave dead code - DELETE it or IMPLEMENT it
❌ NEVER use approximate constants (3.14159) - use std::f64::consts::PI
❌ NEVER silence clippy in code - FIX THE CODE or configure in Cargo.toml
❌ NEVER add comments explaining what code does - code must be self-documenting
❌ NEVER use CDN links - all assets must be local

CARGO.TOML LINT EXCEPTIONS

When a clippy lint has technical false positives that cannot be fixed in code, disable it in Cargo.toml with a comment explaining why:

[lints.clippy]
# Disabled: has false positives for functions with mut self, heap types (Vec, String)
missing_const_for_fn = "allow"
# Disabled: Tauri commands require owned types (Window) that cannot be passed by reference
needless_pass_by_value = "allow"
# Disabled: transitive dependencies we cannot control
multiple_crate_versions = "allow"

Approved exceptions:

  • missing_const_for_fn - false positives for mut self, heap types
  • needless_pass_by_value - Tauri/framework requirements
  • multiple_crate_versions - transitive dependencies
  • future_not_send - when async traits require non-Send futures

MANDATORY CODE PATTERNS

Error Handling - Use ? Operator

// ❌ WRONG
let value = something.unwrap();
let value = something.expect("msg");

// ✅ CORRECT
let value = something?;
let value = something.ok_or_else(|| Error::NotFound)?;

Self Usage in Impl Blocks

// ❌ WRONG
impl MyStruct {
    fn new() -> MyStruct { MyStruct { } }
}

// ✅ CORRECT
impl MyStruct {
    fn new() -> Self { Self { } }
}

Format Strings - Inline Variables

// ❌ WRONG
format!("Hello {}", name)

// ✅ CORRECT
format!("Hello {name}")

Display vs ToString

// ❌ WRONG
impl ToString for MyType { }

// ✅ CORRECT
impl std::fmt::Display for MyType { }

Derive Eq with PartialEq

// ❌ WRONG
#[derive(PartialEq)]
struct MyStruct { }

// ✅ CORRECT
#[derive(PartialEq, Eq)]
struct MyStruct { }

Weekly Maintenance - EVERY MONDAY

Package Review Checklist

Every Monday, review the following:

  1. Dependency Updates

    cargo outdated
    cargo audit
    
  2. Package Consolidation Opportunities

    • Check if new crates can replace custom code
    • Look for crates that combine multiple dependencies
    • Review Cargo.toml for redundant dependencies
  3. Code Reduction Candidates

    • Custom implementations that now have crate equivalents
    • Boilerplate that can be replaced with derive macros
    • Manual serialization that serde can handle
  4. Frontend Asset Updates

    # Check vendor libs in ui/suite/js/vendor/
    # Compare with latest versions of htmx, gsap, etc.
    

Packages to Watch

Area Potential Packages Purpose
HTTP Client reqwest Consolidate HTTP handling
Templates askama Efficient HTML templates
Animations gsap Replace CSS animations

Version Management - CRITICAL

Current version is 6.1.0 - DO NOT CHANGE without explicit approval!

Rules

  1. Version is 6.1.0 across ALL workspace crates
  2. NEVER change version without explicit user approval
  3. BotUI does not have migrations - all migrations are in botserver/
  4. All workspace crates share version 6.1.0

Official Icons - MANDATORY

NEVER generate icons with LLM. ALWAYS use official SVG icons from:

ui/suite/assets/icons/
├── gb-logo.svg        # Main GB logo
├── gb-bot.svg         # Bot/assistant
├── gb-analytics.svg   # Analytics app
├── gb-calendar.svg    # Calendar app
├── gb-chat.svg        # Chat app
├── gb-compliance.svg  # Compliance/security
├── gb-designer.svg    # Workflow designer
├── gb-drive.svg       # File storage
├── gb-mail.svg        # Email
├── gb-meet.svg        # Video meetings
├── gb-paper.svg       # Documents
├── gb-research.svg    # Research/search
├── gb-sources.svg     # Knowledge sources
└── gb-tasks.svg       # Task management

Usage in HTML

<!-- Inline SVG (preferred for styling) -->
<img src="/assets/icons/gb-chat.svg" alt="Chat" class="icon">

<!-- With CSS currentColor -->
<svg class="icon" style="color: var(--primary);">
  <use href="/assets/icons/gb-chat.svg#icon"></use>
</svg>

Icon Style Guidelines

  • All icons use stroke="currentColor" for theming
  • ViewBox: 0 0 24 24
  • Stroke width: 1.5
  • Rounded caps and joins
  • Consistent with GB brand identity

DO NOT:

  • Generate new icons with AI/LLM
  • Use emoji or unicode symbols as icons
  • Use external icon libraries (FontAwesome, etc.)
  • Create inline SVG content in templates

Project Overview

BotUI is a dual-mode UI application built in Rust that runs as either a desktop app (Tauri) or web server (Axum). All business logic is in botserver - BotUI is purely presentation + HTTP bridge.

Workspace Position

botui/         # THIS PROJECT - Web/Desktop UI
botserver/     # Main server (business logic)
botlib/        # Shared library (consumed here)
botapp/        # Desktop wrapper (consumes botui)
botbook/       # Documentation

LLM Workflow Strategy

Two Types of LLM Work

  1. Execution Mode (Fazer)

    • Pre-annotate phrases and send for execution
    • Focus on automation freedom
    • Less concerned with code details
    • Primary concern: Is the LLM destroying something?
    • Trust but verify output doesn't break existing functionality
  2. Review Mode (Conferir)

    • Read generated code with full attention
    • Line-by-line verification
    • Check for correctness, security, performance
    • Validate against requirements

LLM Fallback Strategy (After 3 attempts / 10 minutes)

  1. DeepSeek-V3-0324 (good architect, reliable)
  2. gpt-5-chat (slower but thorough)
  3. gpt-oss-120b (final validation)
  4. Claude Web (for complex debugging, unit tests, UI)

Code Generation Rules

CRITICAL REQUIREMENTS

- BotUI = Presentation + HTTP bridge ONLY
- All business logic goes in botserver
- No code duplication between layers
- Feature gates eliminate unused code paths
- Zero warnings - feature gating prevents dead code
- NO DEAD CODE - implement real functionality, never use _ for unused
- All JS/CSS must be local (no CDN)

HTMX-First Frontend

- Use HTMX to minimize JavaScript at maximum
- Delegate ALL logic to Rust server
- Server returns HTML fragments, not JSON
- Use hx-get, hx-post, hx-target, hx-swap attributes
- WebSocket via htmx-ws extension for real-time
- NO custom JavaScript where HTMX can handle it

JavaScript Usage Guidelines

JS is ONLY acceptable when HTMX cannot handle the requirement:

Use Case Solution
Data fetching HTMX hx-get, hx-post
Form submission HTMX hx-post, hx-put
Real-time updates HTMX WebSocket extension hx-ext="ws"
Content swapping HTMX hx-target, hx-swap
Polling HTMX hx-trigger="every 5s"
Loading states HTMX hx-indicator
Modal show/hide JS required - DOM manipulation
Toast notifications JS required - dynamic element creation
Clipboard operations JS required - navigator.clipboard API
Keyboard shortcuts JS required - keydown event handling
WebSocket state mgmt JS required - connection lifecycle
Complex animations JS required - GSAP or custom
Client-side validation JS required - before submission UX

When writing JS:

- Keep it minimal - one function per concern
- No frameworks (React, Vue, etc.) - vanilla JS only
- Use vendor libs sparingly (htmx, marked, gsap)
- All JS must work with HTMX lifecycle (htmx:afterSwap, etc.)
- Prefer CSS for animations when possible

Local Assets Only

All external libraries are bundled locally - NEVER use CDN:

ui/suite/js/vendor/
├── htmx.min.js           # HTMX core
├── htmx-ws.js            # WebSocket extension
├── htmx-json-enc.js      # JSON encoding
├── marked.min.js         # Markdown parser
├── gsap.min.js           # Animation (minimal use)
└── livekit-client.umd.min.js  # LiveKit video

ui/minimal/js/vendor/
└── (same structure)
<!-- CORRECT -->
<script src="js/vendor/htmx.min.js"></script>

<!-- WRONG - NEVER DO THIS -->
<script src="https://unpkg.com/htmx.org@1.9.10"></script>

Dependency Management

- Use diesel for any local database needs
- After adding to Cargo.toml: cargo audit must show 0 warnings
- If audit fails, find alternative library
- Minimize redundancy - check existing libs before adding new ones

Documentation Rules

- Rust code examples ONLY allowed in architecture/gbapp documentation
- Scan for ALL_CAPS.md files created at wrong places - delete or integrate
- Keep only README.md and PROMPT.md at project root level

Architecture

Dual Modes

Mode Command Description
Web cargo run Axum server on port 3000
Desktop cargo tauri dev Tauri native window

Code Organization

src/
├── main.rs           # Entry point - mode detection
├── lib.rs            # Feature-gated module exports
├── http_client.rs    # HTTP wrapper for botserver (web-only)
├── ui_server/
│   └── mod.rs        # Axum router + UI serving (web-only)
├── desktop/
│   ├── mod.rs        # Desktop module organization
│   ├── drive.rs      # File operations via Tauri
│   ├── tray.rs       # System tray infrastructure
│   └── stream.rs     # Streaming operations
└── shared/
    └── state.rs      # Shared application state

ui/
├── suite/            # Main UI (HTML/CSS/JS)
│   ├── js/vendor/    # Local JS libraries
│   └── css/          # Stylesheets
└── minimal/          # Minimal chat UI
    └── js/vendor/    # Local JS libraries

Feature Gating

#[cfg(feature = "desktop")]
pub mod desktop;

#[cfg(not(feature = "desktop"))]
pub mod http_client;

Security Architecture - MANDATORY

Centralized Auth Engine

All authentication is handled by security-bootstrap.js which MUST be loaded immediately after HTMX in the <head> section. This provides:

  1. Automatic HTMX auth headers - All hx-get, hx-post, etc. requests get Authorization header
  2. Fetch API interception - All fetch() calls automatically get auth headers
  3. XMLHttpRequest interception - Legacy XHR calls also get auth headers
  4. Session management - Handles token storage, refresh, and expiration

Script Loading Order (CRITICAL)

<head>
    <!-- 1. HTMX must load first -->
    <script src="js/vendor/htmx.min.js"></script>
    <script src="js/vendor/htmx-ws.js"></script>
    
    <!-- 2. Security bootstrap IMMEDIATELY after HTMX -->
    <script src="js/security-bootstrap.js"></script>
    
    <!-- 3. Other scripts can follow -->
    <script src="js/api-client.js"></script>
</head>

DO NOT Duplicate Auth Logic

// ❌ WRONG - Don't add auth headers manually
fetch("/api/data", {
    headers: { "Authorization": "Bearer " + token }
});

// ✅ CORRECT - Let security-bootstrap.js handle it
fetch("/api/data");

DO NOT Register Multiple HTMX Auth Listeners

// ❌ WRONG - Don't register duplicate listeners
document.addEventListener("htmx:configRequest", (e) => {
    e.detail.headers["Authorization"] = "Bearer " + token;
});

// ✅ CORRECT - This is handled by security-bootstrap.js automatically

Auth Events

The security engine dispatches these events:

  • gb:security:ready - Security bootstrap initialized
  • gb:auth:unauthorized - 401 response received
  • gb:auth:expired - Session expired, user should re-login
  • gb:auth:login - Dispatch to store tokens after login
  • gb:auth:logout - Dispatch to clear tokens

Token Storage Keys

All auth data uses these keys (defined in security-bootstrap.js):

  • gb-access-token - JWT access token
  • gb-refresh-token - Refresh token
  • gb-session-id - Session identifier
  • gb-token-expires - Token expiration timestamp
  • gb-user-data - Cached user profile

HTMX Patterns

Server-Side Rendering

<!-- Button triggers server request, response swaps into target -->
<button hx-get="/api/items" 
        hx-target="#items-list" 
        hx-swap="innerHTML">
    Load Items
</button>

<div id="items-list">
    <!-- Server returns HTML fragment here -->
</div>

Form Submission

<form hx-post="/api/items" 
      hx-target="#items-list" 
      hx-swap="beforeend">
    <input name="title" type="text" required>
    <button type="submit">Add</button>
</form>

WebSocket Real-time

<div hx-ext="ws" ws-connect="/ws/chat">
    <div id="messages"></div>
    <form ws-send>
        <input name="message" type="text">
        <button type="submit">Send</button>
    </form>
</div>

Server Response (Rust/Askama)

#[derive(Template)]
#[template(path = "partials/item.html")]
struct ItemTemplate {
    item: Item,
}

async fn create_item(
    State(state): State<Arc<AppState>>,
    Form(input): Form<CreateItem>,
) -> Html<String> {
    let item = save_item(&state, input).await;
    let template = ItemTemplate { item };
    Html(template.render().unwrap())
}

Adding Features

Process

  1. Add business logic to botserver first
  2. Create REST API endpoint in botserver (returns HTML for HTMX)
  3. Add HTTP wrapper in BotUI if needed
  4. Add UI in ui/suite/ using HTMX attributes
  5. For desktop-specific: Add Tauri command in src/desktop/

Desktop Tauri Command

#[tauri::command]
pub fn list_files(path: &str) -> Result<Vec<FileItem>, String> {
    let entries = std::fs::read_dir(path)
        .map_err(|e| e.to_string())?;
    
    let items: Vec<FileItem> = entries
        .filter_map(|e| e.ok())
        .map(|e| FileItem {
            name: e.file_name().to_string_lossy().to_string(),
            is_dir: e.path().is_dir(),
        })
        .collect();
    
    Ok(items)
}

COMPILATION POLICY - CRITICAL

NEVER compile during development. NEVER run cargo build or cargo check. Use static analysis only.

Workflow

  1. Make all code changes
  2. Use diagnostics tool for static analysis (NOT compilation)
  3. Fix any errors found by diagnostics
  4. At the end, inform user what needs restart

After All Changes Complete

Change Type User Action Required
Rust code (.rs files) "Recompile and restart botui"
HTML templates (.html in ui/) "Browser refresh only"
CSS/JS files "Browser refresh only"
Askama templates (.html in src/) "Recompile and restart botui"
Cargo.toml changes "Recompile and restart botui"

Format: At the end of your response, always state:

  • No restart needed - browser refresh only
  • 🔄 Restart botui - recompile required

Key Files Reference

src/main.rs           # Entry point, mode detection
src/lib.rs            # Feature-gated exports
src/http_client.rs    # botserverClient wrapper
src/ui_server/mod.rs  # Axum router, static files
ui/suite/index.html   # Main UI entry
ui/suite/base.html    # Base template
ui/minimal/index.html # Minimal chat UI

Dependencies

Library Version Purpose
axum 0.7.5 Web framework
reqwest 0.12 HTTP client
tokio 1.41 Async runtime
askama 0.12 HTML Templates
diesel 2.1 Database (sqlite)


Design System - UI Standards

The tasks.css file defines the standard patterns for ALL screens in General Bots.

All themes MUST implement these core components consistently.

Layout Standards

/* Full-height container - no global scroll */
.app-container {
    display: flex;
    flex-direction: column;
    height: 100vh;
    max-height: 100vh;
    overflow: hidden;
}

/* Two-column layout - list + detail */
.main-content {
    display: grid;
    grid-template-columns: 320px 1fr;
    flex: 1;
    overflow: hidden;
    height: calc(100vh - 120px);
}

/* Scrollable list panel (LEFT) */
.list-panel {
    overflow-y: scroll;
    overflow-x: hidden;
    height: 100%;
    scrollbar-width: auto;
    scrollbar-color: var(--border-light) var(--surface);
}

/* Fixed detail panel (RIGHT) - no scroll */
.detail-panel {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    height: 100%;
}

Scrollbar Standards

/* Visible scrollbar - 10px width */
.scrollable::-webkit-scrollbar {
    width: 10px;
}

.scrollable::-webkit-scrollbar-track {
    background: var(--surface);
    border-radius: 5px;
}

.scrollable::-webkit-scrollbar-thumb {
    background: var(--border-light);
    border-radius: 5px;
    border: 2px solid var(--surface);
}

.scrollable::-webkit-scrollbar-thumb:hover {
    background: var(--primary);
}

/* Firefox */
.scrollable {
    scrollbar-width: auto;
    scrollbar-color: var(--border-light) var(--surface);
}

Card Standards

/* Base card - used in task lists, items, etc. */
.card {
    background: var(--surface-hover);
    border: 2px solid var(--border);
    border-radius: 16px;
    padding: 16px 20px;
    cursor: pointer;
    transition: all 0.2s ease;
    position: relative;
}

.card:hover {
    border-color: var(--border-hover);
    background: var(--surface);
}

.card.selected {
    border-color: var(--primary);
    box-shadow: 0 0 0 2px var(--primary);
}

/* Card status indicator (left bar) */
.card::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    width: 5px;
    height: 100%;
    background: var(--text-secondary);
    transition: background 0.2s ease;
}

.card.status-running::before { background: var(--primary); }
.card.status-complete::before { background: var(--success); }
.card.status-error::before { background: var(--error); }
.card.status-pending::before { background: var(--text-secondary); }

Progress/Tree Indicators

/* Dot indicator - shows status */
.status-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
    background: var(--text-secondary);
    transition: all 0.3s ease;
}

.status-dot.running {
    background: var(--primary);
    box-shadow: 0 0 8px var(--primary-light);
    animation: dot-pulse 1.5s ease-in-out infinite;
}

.status-dot.completed {
    background: var(--primary);
}

.status-dot.pending {
    background: var(--text-secondary);
}

@keyframes dot-pulse {
    0%, 100% {
        opacity: 1;
        box-shadow: 0 0 10px var(--primary-light);
        transform: scale(1);
    }
    50% {
        opacity: 0.7;
        box-shadow: 0 0 4px var(--primary-light);
        transform: scale(0.9);
    }
}

/* Step badge */
.step-badge {
    padding: 4px 12px;
    background: var(--primary);
    color: var(--bg);
    border-radius: 4px;
    font-size: 11px;
    font-weight: 600;
}

.step-badge.pending {
    background: var(--surface);
    color: var(--text-secondary);
}

Tree/List with Children

/* Parent-child expandable tree */
.tree-section {
    border: 1px solid var(--border);
    background: var(--surface);
    border-radius: 8px;
    margin: 8px 16px;
    overflow: hidden;
}

.tree-row {
    display: flex;
    align-items: center;
    padding: 16px 20px;
    cursor: pointer;
    transition: background 0.15s;
}

.tree-row:hover {
    background: var(--surface-hover);
}

.tree-children {
    display: none;
    background: var(--bg);
}

.tree-section.expanded .tree-children {
    display: block;
}

.tree-child {
    border-bottom: 1px solid var(--border);
    padding-left: 24px;
}

.tree-item {
    display: flex;
    align-items: center;
    padding: 8px 20px 8px 40px;
    min-height: 32px;
}

Fixed Panels (Terminal, Status)

/* Fixed-height panel at bottom */
.fixed-panel {
    flex: 0 0 120px;
    height: 120px;
    min-height: 120px;
    max-height: 120px;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    border-top: 1px solid var(--border);
}

/* Variable-height panel with scroll */
.variable-panel {
    flex: 1 1 auto;
    min-height: 150px;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.variable-panel-content {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: scroll;
}

Status Badges

.status-badge {
    font-size: 11px;
    font-weight: 700;
    padding: 6px 12px;
    border-radius: 6px;
    text-transform: uppercase;
}

.status-badge.running {
    background: rgba(var(--primary-rgb), 0.15);
    color: var(--primary);
}

.status-badge.completed {
    background: rgba(var(--success-rgb), 0.15);
    color: var(--success);
}

.status-badge.error {
    background: rgba(var(--error-rgb), 0.15);
    color: var(--error);
}

.status-badge.pending {
    background: var(--surface);
    color: var(--text-secondary);
}

Theme Variables Required

Every theme MUST define these CSS variables:

[data-theme="your-theme"] {
    /* Backgrounds */
    --bg: #0a0a0a;
    --surface: #161616;
    --surface-hover: #1e1e1e;
    
    /* Borders */
    --border: #2a2a2a;
    --border-light: #3a3a3a;
    --border-hover: #4a4a4a;
    
    /* Text */
    --text: #ffffff;
    --text-secondary: #888888;
    --text-tertiary: #666666;
    
    /* Primary (accent) */
    --primary: #c5f82a;
    --primary-hover: #d4ff3a;
    --primary-light: rgba(197, 248, 42, 0.15);
    
    /* Status colors */
    --success: #22c55e;
    --warning: #f59e0b;
    --error: #ef4444;
    --info: #3b82f6;
}

Component Checklist for New Screens

When creating a new screen, ensure it has:

  • Full-height container with overflow: hidden
  • No global page scroll
  • List panel with visible scrollbar (if applicable)
  • Detail panel with fixed layout
  • Cards with status indicator bar
  • Status dots/badges using standard classes
  • Tree sections if showing parent-child relationships
  • Fixed terminal/status panels at bottom
  • Variable content area with internal scroll

Alert Infrastructure (Bell Notifications)

Use window.GBAlerts for app notifications that appear in the global bell icon:

// Task completed (with optional app URL)
window.GBAlerts.taskCompleted("My App", "/apps/my-app/");

// Email notification
window.GBAlerts.newEmail("john@example.com", "Meeting tomorrow");

// Chat message
window.GBAlerts.newChat("John", "Hey, are you there?");

// Drive sync
window.GBAlerts.driveSync("report.pdf", "uploaded");

// Calendar reminder
window.GBAlerts.calendarReminder("Team Meeting", "15 minutes");

// Error
window.GBAlerts.error("Drive", "Failed to sync file");

// Generic notification
window.GBAlerts.add("Title", "Message", "success", "🎉");

All notifications appear in the bell dropdown with sound (if enabled).


Remember

  • ZERO WARNINGS - Every clippy warning must be fixed
  • NO ALLOW IN CODE - Never use #[allow()] in source files
  • CARGO.TOML EXCEPTIONS OK - Disable lints with false positives in Cargo.toml with comment
  • NO DEAD CODE - Delete unused code, never prefix with _
  • NO UNWRAP/EXPECT - Use ? operator or proper error handling
  • INLINE FORMAT ARGS - format!("{name}") not format!("{}", name)
  • USE SELF - In impl blocks, use Self not the type name
  • DERIVE EQ - Always derive Eq with PartialEq
  • DISPLAY NOT TOSTRING - Implement Display, not ToString
  • USE DIAGNOSTICS - Use IDE diagnostics tool, never call cargo clippy directly
  • HTMX first: Minimize JS, delegate to server
  • Local assets: No CDN, all vendor files local
  • No business logic: All logic in botserver
  • HTML responses: Server returns fragments, not JSON
  • Version: Always 6.1.0 - do not change without approval
  • Theme system: Use data-theme attribute on body, 6 themes available
  • Session Continuation: When running out of context, create detailed summary: (1) what was done, (2) what remains, (3) specific files and line numbers, (4) exact next steps.