📖 VX App Format — Developer Manual programfiles/vx_manual.txt

LUCI / VINX DESKTOP ENVIRONMENT

MASTER MANUAL

For developers, .vx app authors, .nbg graph designers, plugin authors, and the VinX Brain itself.

v3.1 · Architecture by Vincent Ilagan · Constellation theme removed · post-v3.0 sections added

This document is loaded into VinX's context so the Brain understands the full ecosystem. v3.1 adds: Cosmic Core service layer, app signing (Ed25519), permissions registry, native app adoption (luci_wm), per-workspace pinning, immersive mode, the VinX Bridge with action registry, and the AI Theme generator.

Chapter 1

What is this whole thing?

Luci is a custom fullscreen desktop environment in pure Python + Tk/Qt. It runs on FreeBSD (today) and provides a sovereign app ecosystem. Apps run inside Luci; Luci runs as a single process the desktop draws everything from.

  1. Luci Desktop — wallpaper, icons, dock, taskbar, themes
  2. .vx apps — Python files with a metadata header
  3. .nbg graphs — JSON visual programs (NodeBase format)
  4. .run bundles — packaged native Luci apps
  5. .nbgplugin / .zip — NodeBase plugins (community node types)
  6. VinX — local LLM brain (vinX.gguf) or user's chosen API / chat session
  7. Gate — AI-aware command shell
  8. NodeBase — visual scripting IDE + runtime
  9. Luna — built-in software 3D renderer
  10. Cosmic Core — userland service layer (Bus, Guard, Grants, HAL, FS, Proc, Registry, Prompt)

Everything is sandboxed inside the Luci folder. Nothing escapes that the user hasn't explicitly granted.

Chapter 2

What OS is Luci? — Architecture & roadmap

Be honest about the layering — the Brain must not claim more than what is real.

Luci is NOT a kernel. It does not boot from BIOS/UEFI, talk to hardware, manage memory, or schedule processes. A kernel does those.

Luci TODAY = a desktop environment / OS shell written in Python + Qt5/Tk, running on top of the FreeBSD 15 host kernel. Every window Luci draws is a real OS window underneath. This is a common architectural pattern: ChromeOS runs a shell on the Linux kernel; PlayStation OS runs a shell on a FreeBSD-forked kernel. None of them wrote a kernel from scratch; the innovation is the LAYER on top. Luci's layer is what is new: an AI-native desktop with capability-secured apps.

The Roadmap — three stages

  • Stage 1 (NOW) — Python layer on FreeBSD 15. Build the Luci experience: .vx apps, NodeBase, VinX, Luna, the Cosmic Core service layer, the signing model. Prove and ship the product.
  • Stage 2 — Performance pass + hardware reference unit. Shrink the ISO below 300 MB; cut idle RAM below 150 MB; co-design a laptop with the brand mark and TPN-aligned defaults.
  • Stage 3 (GOAL) — A purpose-built AI kernel (C / Rust). A separate, multi-year effort — the long-term north star.

Cross-platform note: the Python core (Qt5/Tk, sockets, .vx runtime, NodeBase) runs on FreeBSD, Linux, and Windows. The Cosmic HAL routes host-specific calls so .vx apps stay portable.

Chapter 3

Architecture — in-process VinX Bridge

Luci runs as one Qt5 process. Every .vx app is loaded INTO that process. When an app wants the AI, it does a plain Python import vinx_bridge as vb — there's no socket, no separate orb process, no port hop. The bridge is the ONE supported entry to the brain, and routes the call to whichever provider the user picked.

LUCI PROCESS (single Qt5) luci.py desktop · Gate · window mgr .vx app (any) import vinx_bridge as vb vinx_bridge.ask() · act() · assist() single import · zero socket · no port vinx_local.ask() local GGUF · always retained gpt_engine.ask() paid API · HTTPS vinx_chat_session.ask() drives Claude.ai / ChatGPT.com tab

Why this matters

  • No port to break. An app can't "lose connection" to VinX — they're in the same Python process.
  • One audit trail. Every brain call goes through vinx_bridge.ask / act / assist — easy to log, easy to gate.
  • Three brains, one surface. The user picks local · api · chat_session in VinX Settings; apps don't need to know which is active.
  • Local GGUF is the permanent fallback. Even with an API key set, if the API fails the bridge silently falls back to the local model — VinX never goes silent.

The provider config

# ~/.config/luci/vinx_brain.json — written by VinX Settings
{
  "mode":     "local" | "api" | "chat_session",
  "provider": "claude" | "openai" | "gemini" | "groq" | "deepseek",
  "service":  "claude" | "chatgpt" | "gemini" | "grok",
  "model":    "<model name>"
}
Legacy port 52525 (floating_core.py / _LuciPlug / _SystemBus): still present in the codebase for the old standalone-orb workflow, but not part of any modern code path. New code must use vinx_bridge. The orb's UI elements (Heart rings, status indicators) are now drawn directly inside Luci's process.

Chapter 4

What is a .vx file?

A .vx file is a Python file with metadata in the first comment lines. Luci loads, parses, and executes it. Each .vx represents one app.

Required header (must be the FIRST lines)

# VX:name=My App
# VX:icon=🎯
# VX:version=1.0
# VX:author=Your Name

Optional header keys (post-v3.0)

# VX:net=none|local|allowed:host1,host2|full   # network policy (Phase A)
# VX:cam=requested                              # camera intent (Phase B)
# VX:mic=requested                              # microphone intent
# VX:screen=requested                           # screen capture intent
# VX:files=read:~/path,write:~/other            # filesystem scope
# VX:sig=<base64 ed25519 signature>            # present only on signed apps

Required function

def main(desktop):
    # build the app UI here
    ...

When the user double-clicks the app icon, Luci calls main(desktop) with a reference to the Luci instance. From desktop you have access to everything.

Chapter 5

The desktop object

Key attributes

AttributeMeaning
desktop.rootTk root (fullscreen window)
desktop._windowslist of currently-open LucyWindow children
desktop._themecurrent theme name (string)
desktop._canvaswallpaper canvas (drawn behind everything)
desktop._screen_w / _hscreen dimensions
desktop.cosmiclive Cosmic Core singleton (post-v3.0)

Key methods

MethodPurpose
desktop.launch_vx(path)load + run another .vx app
desktop._toast(msg)show a transient toast notification
desktop._raise_all_windowsbring Luci windows above other OS windows
desktop._switch_theme(name)change theme at runtime
desktop.apply_chrome(win, title, icon)install the standard hex traffic-light chrome on a Toplevel

Built-in keyboard shortcuts

  • Escape — confirm-exit Luci
  • F1 / F4 — open Gate
  • F2 — open File Manager
  • F3 — open App Launcher
  • F11 — toggle fullscreen
  • Right-click wallpaper → context menu

Chapter 6

Using LucyWindow

from luci import LucyWindow, C, FONT, FONT_BOLD
import tkinter as tk

class MyApp(LucyWindow):
    def __init__(self, desktop):
        super().__init__(desktop, "My App", 480, 320, "🎯")
        tk.Label(self.content, text="Inside self.content",
                 bg=C["win_bg"], fg=C["text"],
                 font=FONT_BOLD).pack(pady=20)

def main(desktop):
    MyApp(desktop)

Inherited members

  • self._desk — the Luci instance
  • self.content — inner Frame/Widget to pack your UI into
  • self._minimize() — hide (taskbar still shows)
  • self._restore() — un-hide
  • self._close() — destroy + remove from taskbar
Pitfall: The red hex calls _close() directly, NOT closeEvent(). If your app spawned a subprocess (mpv, ffmpeg, etc.), override _close and stop the subprocess there — otherwise you'll get phantom audio / zombie processes.

Chapter 7

Colors & theme (the C dict)

from luci import C

Standard keys

bg, panel, dock, border, accent, accent2, text, dim, white, green, red, yellow, win_title, win_bg.

Themes available

ThemeVibe
midnightdeep navy — default
voiddark purple — deep space
forestdark green
biomechorganic carbon
haloglassmorphism — translucent panels

Glass themes have _glass: True — windows get -alpha 0.92.

Fonts

from luci import FONT, FONT_BOLD, FONT_SM, FONT_TITLE
from luci import FONT_CLOCK, FONT_ICON, FONT_DOCK
See also: AI Theme generator (Chapter 29) — generate a complete palette from a natural-language prompt.

Chapter 8

Where to place .vx files

Two zones — system code under the install root, user data under $HOME. This is the standard Unix split (XDG Base Directory spec), which means rsync / Syncthing / Chrome / mpv all find your data where they expect.

System code (immutable — package manager owns it)

PathPurpose
/usr/local/luci/Vinx-Desktop/programfiles/System apps (HIDDEN, shipped & signed)
/usr/local/luci/Vinx-Desktop/programfiles/cosmic/Cosmic Core service layer (immutable)
/usr/local/luci/Vinx-AI/VinX runtime (vinx_bridge.py lives here)
/usr/local/luci/.keys/Owner Ed25519 keys (root:wheel · 600 · schg)

User data (XDG-standard under $HOME)

PathPurpose
~/Desktop/User desktop — visible .vx + .run icons
~/Documents/Documents (notes, exports, activity log)
~/Pictures/ · ~/Videos/ · ~/Downloads/Standard user media folders
~/.config/luci/profile.jsonTheme + user prefs
~/.config/luci/vinx_brain.jsonActive brain mode (local / api / chat_session)
~/.config/luci/cosmic_grants.jsonPer-app resource grants
~/.config/luci/graphs/Saved .nbg graphs + .run bundles
~/.config/luci/plugins/User-installed NodeBase plugins
~/.local/share/luci/trash/Trash bin
~/Apps/User-written / AI-generated apps (unsigned by default → sandboxed)

Paths exposed by luci.py (POSIX values)

ConstantResolves to
LUCI_DIR/usr/local/luci/ (where luci.py lives)
PROG_DIR/usr/local/luci/Vinx-Desktop/programfiles/
HOME_DIR / ROOT_DIR/home/luci/ (the user's home)
DESK_DIR~/Desktop/
DOC_DIR~/Documents/
CONFIG_DIR~/.config/luci/
USER_FILE~/.config/luci/profile.json
LOG_FILE~/Documents/activity_log.txt
VINX_DIR/usr/local/luci/ (parent of LUCI_DIR)
Windows portable layout stays self-contained inside <luci.py-dir>/Vinx-Desktop/... — no $HOME split. Only POSIX hosts use the XDG layout above.
First-boot migrator (POSIX only). If old folders exist at <install>/Vinx-Desktop/desktop|documents|Photos|Video|.user, _migrate_user_data() COPIES them to the new $HOME paths and renames the originals to <name>.MIGRATED-YYYYMMDD-HHMMSS. Migration is idempotent and non-destructive — failed copies leave both intact.

Chapter 9

Gate — the AI-aware command shell

Open with F1, F4, the Gate dock button, or Gate(desktop).

Files

ls · cd · pwd · cat

Apps

  • new <name.vx> — create blank .vx template
  • edit <file.vx> — built-in code editor
  • run <name> — launch a .vx app
  • apps — list all installed apps
  • info <name> — show app metadata
  • trust <app.vx> · untrust <app.vx> — add / remove sha256 from ~/.config/luci/user_trusted.json
  • verify <app.vx> — show hash + trust source (system / user / signature / UNTRUSTED)
  • verify manifest — check the system manifest signature
  • manifest build|add|show|verify|hash — manage the system trusted-apps manifest (root)
  • sign <app.vx> · license <app.vx> — LEGACY per-device Ed25519 signing (transitional)

Brain / AI

  • ask <question> · vinx <question> — query VinX (routes through the bridge)
  • fix <name.vx> — VinX analyses a broken app
  • unload — unload VinX from RAM
  • heart — open Heart engine dashboard
  • learn — run the Learner

System

settings · theme [name] · log · monitor

Shell

  • git <cmd> — git passthrough
  • pip <cmd> — pip → portable Python only
  • py <file> — run a .py file with portable Python
  • where <name> — locate an executable
  • install <pkg>sudo -n pkg install -y (sudoers luci-pkg)

C++

compile <f.cpp> — compile C++ to binary (needs g++) · g++ / gcc passthroughs

Gate

clear · exit

IPC injection: VinX writes to memory/gate_cmd.json → Luci polls it → Gate._inject_cmd() runs the command and prints [VinX] <cmd>.

Chapter 10

Calling VinX AI from a .vx app

One way, always — direct in-process Python import. No socket, no port, no separate process to manage.

import vinx_bridge as vb

reply = vb.ask("Your prompt here", timeout=60)
# Routes through the user's active brain:
#   local GGUF · paid API · or web chat session.
# Falls back to local on failure — never silent.

Three surfaces

CallWhat it does
vb.ask(prompt, timeout=60)Plain text answer from the active brain. Returns "" if total failure.
vb.act(name, args)Run a registered capability by name (brightness, files, processes, theme, apps — 17 actions). Skips the LLM entirely.
vb.assist(user_text, max_turns=3)Full agent loop: model writes <<ACT name {args}>> tokens, bridge dispatches them through act(), feeds results back. Returns {reply, actions: [...]}.
vb.current_engine()Returns the active {mode, provider, service, model} — for status UI.
vb.has_provider()True if any brain is reachable. Use to gate AI-only UI.

Threading rule

Bridge calls are synchronous and can block for tens of seconds. Always run them off the Qt thread:

import threading
import vinx_bridge as vb

def _ask_off_thread(self, prompt):
    def _run():
        r = vb.ask(prompt, timeout=60) or "(no reply)"
        # Marshal back to Qt thread before touching widgets
        QTimer.singleShot(0, lambda: self._show(r))
    threading.Thread(target=_run, daemon=True).start()
Never go around the bridge. Direct vinx_local calls bypass the user's brain selection (their API key, their chat-session login) and skip the audit trail. The bridge IS the contract.

Chapter 11

The Old Soul — VinX's engines

The Heart engine + ring visualisation live inside Luci's process (drawn by heart.vx + vinx.vx). Each ring = one engine's current "level".

HEART · emotional state LEARN · idle memory consolidation MEM · long-term knowledge graph SYNC + TURBO · IPC + token rate
  • HEART (rose ring) — emotional state, updated by chat sentiment
  • LEARN (green ring) — idle consolidation of memory into learned_skills.json
  • MEM (blue ring) — long-term knowledge graph (Trainer.vinxcore)
  • SYNC + TURBO (purple / yellow rings) — IPC heartbeat + token rate

Chapter 12

NodeBase — visual scripting (.nbg)

NodeBase is a visual dataflow scripting language. The user designs programs by wiring nodes together; VinX can also generate these graphs from natural-language prompts.

Graphs are saved as .nbg files (JSON) at .user/graphs/.

.nbg file format

{
  "nodes": [
    {"id":"<unique>", "type":"<type>", "x":123, "y":456,
     "params":{"<key>":"<value as string>"}}
  ],
  "wires": [
    {"fn":"<from_node_id>", "fp":"<from_port>",
     "tn":"<to_node_id>",   "tp":"<to_port>"}
  ]
}

Rules

  • Every graph MUST have a node of type start with id="start_0".
  • All param values are strings (even numbers).
  • Wire fields: fn=from_node, fp=from_port, tn=to_node, tp=to_port.
  • Flow wires (orange) sequence execution.
  • Data wires carry values from output ports to input ports.

Port types (colour-coded on canvas)

TypeColourCarries
floworangecontrol flow — sequencing
stringcyantext data
numberyellowinteger or float
boolgreenTrue / False
listpurplearray / iterable
fileredfile path
anygreyaccepts anything

Chapter 13

NodeBase IDE — editing shortcuts

Mouse

  • Double-click canvas — open Add menu (with search)
  • Right-click canvas — Add menu near cursor / context menu
  • Right-click node — delete / duplicate / params
  • Click output port ● — begin a wire
  • Drag wire to empty space → quick-add filtered to compatible types
  • Click + drag node title — move node
  • Middle-drag / Alt-drag — pan the canvas
  • Scroll wheel — zoom in / out

Keyboard

KeyAction
Spacequick-add at cursor
Ctrl+Ffull Add menu (with search box)
Ffit-all to view
Ccenter on Start node
Mtoggle minimap
F5run graph
Ctrl+S / Ctrl+Osave / load .nbg
Ctrl+Z / Ctrl+Yundo / redo
Deleteremove selected node
Esccancel wire / close popup

Toolbar

▶ Run · ⬡ Add · 💾 Save · 📂 Load · 🗑 Clear · ↩ Undo · ↪ Redo · 🔍 Check · 🔧 Fix · 🤖 VinX · 🔌 Plug · ⛶ Fit · ⊙ Center · 🗺 Map

Chapter 14

Node categories (17 total · ~150+ types)

Standard

  • flow Start, End, If, For Each, Set/Get Var, Delay, Sequence
  • value String, Number, Boolean, Make List
  • math Math Op, Compare, Clamp, Random
  • string Concat, String Op, Split, Format
  • io Print, File Read, File Write, User Input
  • ai Ask VinX, Summarize, Act (NEW)
  • system Run Cmd, Open App, HTTP Get
  • util Note, Type Convert, Length, Index

PRO

  • ui Window, Canvas, Button, Label, Input, Slider, Color, Panel, Image View, Toolbar, Menu Bar, Layers, Inspector, Timeline, Viewport 2D/3D
  • gfx Load/Save Image, Brush, Erase, Layer Composite, Blend Mode, Mask, Crop, Resize, Color Adjust, Blur, Sharpen, Selection, Transform, Text Tool, Filter, Brush Stroke, Canvas Clear, Canvas → PNG
  • video Load/Extract Video, Chroma Key, Color Range Key, Mask Refine, Edge Feather, Track Point/Object, Stabilize, Composite, Export Video
  • 3d Viewport 3D, Camera, Light (Omni/Sun/Spot/Area), Material, Texture, Orbit View, Raycast, 3D Brush, Sculpt, Particle System, Physics Body, Render Scene, Floor + Grid, Object Manager, Viewport Mode, Primitives (cube/sphere/plane/cyl/torus/cone/grid), Particles (emit/fire/smoke/water/dust/force), Luna Render, Render Pass, Denoise, Compose, Subdivide, Array, Mirror, Bevel, Transform, Import OBJ/FBX/USD/glTF/STL, Export OBJ
  • sim Particle Emitter, Force Field, Noise Motion, Collision, Lifetime, Trail, Glow, Fluid Domain, Smoke Domain
  • doc Doc Page, Rich Text, Table, Spreadsheet, Formula Cell, Chart, Slide, Export PDF/DOCX/XLSX
  • logic Function, Custom Node, Class/Object, Event, State, Signal, Async, Try/Catch, Loop Break, Map, Filter, Reduce, Switch, Router, Cache, Database, History
  • app Asset, Asset Browser, Import Asset, Export App, Install App, App Manifest, Permissions, Save State, Load State, Plugin
  • gpu Shader, Fragment Shader, Vertex Shader, Texture Buffer, Compute Pass, Render Target, Post Process, Noise, Displacement

Chapter 15

3D subsystem — Donut3D / V3D

The 3D nodes work on a shared scene dict that all nodes mutate:

scene = {
    "meshes":    [{"kind", "params", "tx/ty/tz", "name", "material"}, ...],
    "lights":    [{"type":"sun"|"omni"|"spot"|"area", ...}, ...],
    "floors":    [{"size", "divisions", "y", "color"}, ...],
    "particles": [...],
    "camera":    {"x","y","z","yaw","pitch","distance",
                  "target_x","target_y","target_z","fov"},
    "viewport":  <Tk Canvas>,
    "mode":      "wireframe" | "shaded" | "rendered",
    "selected_mesh": <int index>,
    "_render_fn": <callable to re-render>,
}

Mesh primitives

cube · sphere · plane · cyl · torus · cone · grid

Light types

omni · sun · spot · area

Viewport modes

wireframe (edges only) · shaded (filled flat) · rendered (filled + outlined)

Camera controls (in viewport)

  • Left click — select mesh (no drag)
  • Left drag — orbit
  • Middle drag — pan target
  • Scroll wheel — zoom

Import / export formats

NodeFormatDependency
import_objWavefront .objbuilt-in parser, no deps
import_stlStereolithography .stlbuilt-in, ASCII + binary
import_fbxAutodesk FBXpip install pyassimp
import_usdPixar USDpip install usd-core
import_gltfglTF / GLBpip install pygltflib
export_objWrite all scene meshes as .objbuilt-in

Chapter 16

Luna — built-in software 3D renderer

Pure-Python rasterizer using PIL. No GPU needed.

Key features

  • Camera basis vectors (right/up/forward) with proper view xform
  • Perspective projection with FOV
  • Mesh primitives: 8-vert cubes, 96-vert spheres, 192-vert torus
  • GLOBAL face depth sort (painter's algorithm across all meshes)
  • Backface culling (skip ~50% of faces facing away)
  • Lambertian shading per face: ambient + Σ max(0, dot(n, lightDir))
  • Floor with world-aligned grid lines
  • Particle billboards (fire = warm gradient, smoke = grayscale)
  • Selected mesh outline (yellow + slight tint)

Pipeline

luna_render → reads scene, returns PIL.Image
              ALSO blits into scene.viewport canvas if present
              installs scene["_render_fn"] callback

Triggered re-renders: when camera orbits/pans/zooms, scene moves via _render_fn. Object Manager edits also call _render_fn.

Viewport performance — three rules

Keep these to keep editing smooth:
  1. Coalesced renders — at most ONE render in flight; mouse-motion events (~100/sec) can no longer pile up renders = no lag.
  2. Wireframe-while-dragging — orbit/pan/gizmo drag renders cheap wireframe (no face sort, no lighting, no fills); a full shaded render runs once on mouse release.
  3. _render_fn re-rasterizes the SAME scene dict — it does NOT re-run the graph flow. Camera nodes mutate the scene in place.

Not yet implemented (BETA stubs)

  • luna_pass — render passes (beauty, depth, normal, AO)
  • luna_denoise — Gaussian denoise (works as basic blur)
  • luna_compose — over/add/multiply/screen/mix

Chapter 17

Plugin system (Blender-style addons)

Drop a .nbgplugin/ folder OR .zip into Vinx-Desktop/plugins/. NodeBase auto-loads them on startup.

Plugin structure

MyPlugin.nbgplugin/
    manifest.json     ← REQUIRED: name, version, author
    nodes.py          ← OPTIONAL: register new node types
    graphs/           ← OPTIONAL: shipped .nbg templates
    assets/           ← OPTIONAL: icons, samples

manifest.json

{
  "name":        "MyPlugin",
  "version":     "1.0.0",
  "author":      "Your Name",
  "description": "What this plugin adds.",
  "category":    "3d",
  "permissions": ["graphics"],
  "engine":      "nodebase/1.0"
}

nodes.py — registering new node types

def register(register_node):

    def _exec_my_node(ex, node, inp, put, p):
        x = float(inp("x") or 0)
        put("doubled", x * 2)
        put("flow", True)

    register_node("my_double", {
        "label":   "×2  Double",
        "cat":     "math",
        "inputs":  [{"n":"flow","t":"flow"},
                    {"n":"x",   "t":"number"}],
        "outputs": [{"n":"flow",   "t":"flow"},
                    {"n":"doubled","t":"number"}],
        "params":  [],
    }, _exec_my_node)
Plugins CANNOT override built-in node types. Each plugin file is sha256-fingerprinted for tamper detection.

Sample plugin shipped: ToonShader.nbgplugin/ — adds toon_ramp, toon_outline, toon_posterize.

Chapter 18

Executor API (for plugin authors)

Your executor receives 5 arguments:

def my_executor(ex, node, inp, put, p):
    # ex   : the running _Executor (use ex.out("text", "sys"|"err"))
    # node : full node dict (id, type, x, y, params)
    # inp  : function — inp("port_name") resolves upstream value
    # put  : function — put("port_name", value) writes to output
    # p    : node["params"] dict

Important patterns

  • UI nodes should be IDEMPOTENT — check ex._ui_kept[nid] first
  • Event-driven nodes get re-run on user actions (button clicks etc.)
  • Mutate scene dict in-place; renderer reads on next call

Chapter 19

Build validator + auto-fix

Toolbar buttons

  • 🔍 Check — scans graph, lists issues, draws ⚠ rings on bad nodes
  • 🔧 Fix — auto-adds missing start/end/export_app, wires them
  • 🤖 VinX — sends graph + issues to VinX, gets fixed graph back

What _check_build catches

  • Missing start / end nodes
  • Missing export_app (informational)
  • Nodes with no incoming flow (won't execute)
  • Dangling wires (pointing to deleted nodes)

Chapter 20

NodeBase: Editor vs Player — the split

nodebase.vx PRIVATE editor / builder / test runner • Canvas · add-menu · wire editing • Save · undo / redo • Run (test the graph) • 📦 Export — build a .run ⚠ NEVER shipped inside an exported app nbcore.vx PUBLIC player / runtime ONLY • Load main.nbg + addons/*.nbgplugin • Register built-in core nodes • Execute flow / data wires • Runtime logging · run UI nodes • NO canvas · NO add menu · NO save
THE FREEZE RULE (architecture law): The built-in node set inside nbcore.vx is FROZEN as "Core stdlib v1". Do NOT edit nbcore.vx to add a new node or app feature. A missing capability MUST come from a universal .nbgplugin — never from changing the player. nbcore.vx stays stable forever; the ecosystem grows through plugins.

Name nodes by capability, never by app

  • OK media_trim · scene_render · ui_button · math_lerp
  • WRONG donut3d_export · michael_music_editor · my_special_btn

Chapter 21

.run app bundles (native distribution format)

Click 📦 Export in NodeBase's toolbar. The exporter:

  1. Detects every node type used in the current graph
  2. Classifies each: built-in core · plugin-provided · missing
  3. Maps plugin nodes → their source .nbgplugin folder
  4. Aborts with a clear error if any node is unresolved:
    Missing node: media_luna_cache_seek
    Required plugin not found — install the .nbgplugin.
  5. Packages a self-contained folder with .run extension:
MyApp.run/
    main.nbg              the visual program (graph source)
    runtime/
        nbcore.vx         the player — runs without nodebase.vx
    addons/
        *.nbgplugin/      ONLY the plugins this graph actually uses

To install: drop the .run folder into desktop/ or .user/graphs/. To launch: double-click in Luci's File Manager. Luci runs runtime/nbcore.vx, which loads main.nbg + addons and executes the graph. nodebase.vx is NOT required.

Legacy .run bundles used manifest.json + graph.nbg + main.vx; Luci's File Manager still launches those for back-compat.

Chapter 22

Public API exposed by NodeBase

External Python code can import nodebase.vx (via SourceFileLoader) and call:

FunctionPurpose
nodebase.run_graph_standalone(graph_dict, output_callback=None)Execute a parsed graph headlessly. Returns the executor.
nodebase.run_graph_file(nbg_path, output_callback=None)Convenience: load .nbg from disk + run.
nodebase.register_node(ntype, defn, executor)Add a new node type at runtime (used by plugin loader).
nodebase.load_plugins(plugin_dir=None, verbose=True)Re-scan the plugins folder. Idempotent.
nodebase.get_plugin_info()List of loaded plugin manifests.
nodebase.DEFSGlobal dict mapping ntype → node definition.
nodebase._LIVE_EXECUTORSList of executors kept alive by .run apps.

Chapter 23

AI graph generation (VinX writes graphs)

nodebase_ai.generate(task, timeout=60) returns (ok, graph_dict, error).

Pipeline

  1. Format task into a short prompt with all valid node types listed
  2. Call vinx_bridge.ask() (preferred) or vinx_local.ask() directly
  3. Strip markdown fences, extract first {...} block
  4. _repair_json closes unclosed brackets if truncated
  5. _validate ensures node types are valid; drops invalid wires
  6. Failed parses save raw output to .nb_last_failed.txt

Chapter 24

Worked examples in .user/graphs/

  • PaintLite.nbg — simple paint app — canvas + brush + color picker + save PNG. Demonstrates real event binding.
  • V3D.nbg — early 3D editor — viewport + cube/sphere primitives + camera orbit. Foundation for Donut3D.
  • Donut3D.nbg — full V3D successor — torus default scene, floor + grid, 4 light types, 5 primitives, 3 viewport modes (wireframe/shaded/rendered), Object Manager with per-object color picker + delete + transform editor, camera orbit/pan/zoom, click-to-select.

Chapter 25 · post-v3.0

AI Theme generator

Type a vibe — get a palette. The AI Themes panel feeds the user's prompt through VinX Bridge, parses the strict-JSON response into Luci's C dictionary, and applies it live across the running desktop.

Flow

User prompt "deep ocean sunrise" vinx_bridge.ask() routes to local · API · chat Strict JSON palette bg · panel · accent text · dim · border C dict applied live

The result feeds straight into desktop._switch_theme(name) (after persistence to .user/profile.json). Wallpaper, dock, window-chrome accent, hex traffic-light hover state — all repaint at once.

Chapter 26 · post-v3.0

Cosmic Core — the userland service layer

A microkernel-style service layer between Luci's .vx apps and the host kernel. Eight modules, ~1100 lines, loaded once at startup as desktop.cosmic.

.vx APPS — apps load through Cosmic on every launch 🌌 COSMIC CORE cosmic_bus · in-process pub/sub, 500-event ring buffer cosmic_guard · capability sandbox · rewrites os/subprocess/socket cosmic_grants · per-app per-resource permission registry cosmic_prompt · first-time grant dialog · 30 s timeout cosmic_hal · fs · proc · registry — host abstraction + service layer FreeBSD 15 kernel (host)

Modules

ModuleRole
cosmic_core.vxSingleton orchestrator — loads + wires every other module
cosmic_bus.vxThread-safe pub/sub event bus with 500-event ring history
cosmic_guard.vxPer-.vx capability sandbox — see Chapters 28 + 30
cosmic_grants.vxRegistry of (app, resource) → state (always / once / blocked)
cosmic_prompt.vxSync first-time grant dialog — blocks caller, fires Qt UI
cosmic_hal.vxHost adapter — run_cmd / shell / service per OS
cosmic_fs.vxluci:// URL resolver
cosmic_proc.vxSubprocess launcher with bus emissions
cosmic_registry.vxPlugin / node provider discovery

Chapter 27 · post-v3.0

App trust model — hybrid checksum + manifest

Trust is decided by SHA-256, not per-device keys. The same .vx hashes the same on every Luci install — so an app trusted on PC-A is automatically trusted on PC-B, no key exchange. The old per-device Ed25519 signature stays as a transitional fallback only.

Three sources of trust

app.vx loads cosmic_guard checks sha256 System manifest /usr/local/luci/.keys/trusted_apps.json (signed) User trust ~/.config/luci/user_trusted.json Legacy Ed25519 sig # VX:sig= header (transitional fallback)

System manifest — universal trust set

FilePurpose
/usr/local/luci/.keys/trusted_apps.jsonJSON of {rel_path: sha256_hex} for every first-party app
/usr/local/luci/.keys/trusted_apps.sigEd25519 signature of the manifest's bytes — verified once at boot

Ships with every Luci install. Same hashes everywhere → same universal trust set on every device. Local on-disk tampering is caught by the manifest signature check at boot — if the sig is invalid, the manifest is rejected and only user-trusted apps stay trusted.

User trust — per-recipient elevation

A user can explicitly trust a third-party app on their device. The hash is appended to ~/.config/luci/user_trusted.json:

{
  "<sha256 hex>": {
    "name":     "cool_app.vx",
    "path":     "/home/luci/Apps/cool_app.vx",
    "added_at": 1717898100
  }
}

Cosmic Guard hot-reloads this file on mtime change — newly trusted apps go silent immediately, no restart.

Gate commands

CommandAction
trust <app.vx>Add the file's sha256 to user_trusted.json
untrust <app.vx>Remove it from user_trusted.json
verify <app.vx>Show the hash + where trust comes from: system · user · signature · UNTRUSTED
verify manifestCheck the system manifest signature
manifest buildRescan programfiles/ + sign a fresh manifest (root)
manifest add <app.vx>Add one app to the existing manifest + re-sign (root)
manifest showPrint the manifest contents
sign <app.vx>LEGACY — sign with the per-device Ed25519 key (fallback path)

What "UNTRUSTED" actually means

Untrusted apps still run — UI works, local logic works. They just can't:

  • Call host commands (pkg, sudo, system binaries) without a prompt
  • Reach the network beyond their declared # VX:net= scope
  • Touch resources (camera, mic, screen) without going through the Cosmic grant prompt

Same UX as Gatekeeper / SmartScreen — third-party apps run, sensitive actions ask. Click "Allow Always" enough times and the user effectively trusts the app for its declared intent.

Two-PC scenario walkthrough

  1. Vincent writes cool_app.vx on PC-A.
  2. Sends it to PC-B via USB / network / chat.
  3. PC-B user opens Gate, types trust cool_app.vx.
  4. The file's sha256 is recorded in PC-B's user_trusted.json.
  5. Next launch: cosmic_guard sees the hash → silent full access, no prompts.
Edits invalidate everything. Changing one byte changes the sha256 — the app falls out of the manifest / user trust until re-hashed. Re-build the manifest (manifest build) after editing first-party apps, or re-trust (trust) after editing a third-party app.
Why keep the legacy Ed25519 path? So already-signed apps keep working during the rollout. _is_trusted falls back to the per-device signature check if neither manifest nor user trust matches. Once every first-party app is in the manifest, luci_sign.py can be retired.

Chapter 28 · post-v3.0 · Phase A

Network gating — per-app policy

Every .vx declares its network intent in the header:

# VX:net=none                              # DEFAULT for unmarked apps
# VX:net=local                             # loopback only (127.0.0.1, ::1)
# VX:net=allowed:api.host.com,other.host  # explicit whitelist
# VX:net=full                              # opt-in escape hatch

On import, cosmic_guard rewrites socket.socket in the app's namespace with a guarded subclass. Every connect() is policy-checked. Higher-level libraries (urllib, http.client, requests, httpx) all route through socket — guarding it once covers them all. Blocked attempts emit cosmic.net.blocked for the audit log.

Chapter 29 · post-v3.0 · Phase B

Resource grants — camera, mic, screen, files

Apps that want sensitive resources declare intent in the header AND go through a user-consent prompt on first use.

# VX:cam=requested
# VX:mic=requested
# VX:screen=requested
# VX:files=read:~/Pictures,write:~/Documents

On first cv2.VideoCapture(0) (or equivalent), Cosmic prompts the user:

WorkTracker wants to access your CAMERA.
[ Block ]   [ Allow Once ]   [ Allow Always ]

The decision is saved to ~/.config/luci/cosmic_grants.json. Apps that use a guarded API without declaring → automatic block, since omitting declaration is itself a signal.

Chapter 30 · post-v3.0

Permissions panel

A single pane of every grant Cosmic Core has issued — per app, per resource. List + revoke + audit-export.

  • Lists per-resource sections: Camera · Microphone · Screen · Network · Files · Other
  • Each row shows the app, the grant state, when it was set
  • Revoke any grant with one click — next access re-prompts
  • Export audit CSV button — for compliance reviewers
  • Auto-refreshes when other apps trigger grant events on the bus

Lives at programfiles/permissions.vx.

Chapter 31 · post-v3.0

Native app adoption — luci_wm.py

A separate process (luci_wm.py) auto-frames pkg-installed apps (Blender, Chrome, GIMP) with Luci's hex traffic-light chrome. The native app's window manager hint is read; luci_wm creates an override_redirect=True frame, parents the client into it, and surfaces it in the dock + workspace switcher.

Key invariants

  • Identify Luci-own windows by WM_CLASS (luci.py / Luci), not just PID
  • Skip override-redirect AND Luci-own windows — but still client.map() them (else they're invisible)
  • Frames are created override_redirect=True — else cross-connection maps re-frame and kill the client
  • Never use a blocking next_event() loop — a select/poll loop dropped the desktop's MapRequest once and produced a black screen

IPC contract

  • /tmp/luci-wm-windows.json — WM → Luci (window list)
  • /tmp/luci-wm-cmd — Luci → WM (HIDE | SHOW | RESTORE <id>)

Chapter 32 · post-v3.0

Workspaces & immersive mode

Every Luci window is workspace-tagged. Per-workspace pinning means apps "stay on" the workspace they were created on. Swiping between workspaces hides/shows accordingly.

Immersive mode

When an app enters fullscreen (red hex on a maximised window, or programmatically), Luci auto-allocates a fresh workspace, moves the app there, and hides the chrome (no dock, no topbar) until Esc. On exit, the workspace is freed and the user returns to their prior workspace.

Native (WM-framed) windows are NOT workspace-bound — binding them got windows hidden + lost on workspace switch. _wm_apply_workspace only SHOWs all (self-heals). The Overview HIDES all native windows on open and SHOWs all on close.

Chapter 33 · post-v3.0

VinX Bridge — single entry to the brain

.vx app import vinx_bridge as vb vinx_bridge.ask() reads ~/.config/luci/vinx_brain.json routes by mode: local · api · chat_session Local GGUF API provider Chat session vinx.gguf is ALWAYS the fallback — even if API fails, local answers. vb.act(name, args) → invokes 17-action registry vb.assist(text) → agent loop with tool use

The Bridge is the single supported way to talk to VinX. Three modes (local · api · chat_session) selected through VinX Settings. The local GGUF is permanently retained as the offline fallback — it never gets removed by user choices.

Chapter 34 · post-v3.0

Music · Video · Camera

Video player (video.vx) & Music player (music.vx)

Both run in-process as _QtLucyWindow subclasses, driven by an external mpv process over JSON-IPC on a Unix socket at /tmp/luci-mpv-*.sock. CPU-only — no GPU dependency. mpv runs with --vo=x11 for video, --no-video for music.

The red hex calls _close() directly, NOT closeEvent(). Override _close to call mpv.stop() (quit IPC → terminate → os.killpg) — otherwise: phantom audio. Always match mpv JSON-IPC replies by request_id and skip events, or pos/duration/song-switch read the wrong data.

Music tags & cover art

mutagen (pip-installed) reads ID3 / FLAC / MP4 metadata for the playlist + the now-playing card's cover art.

Camera (camera.vx)

OpenCV (cv2) feed with mode toolbar: Preview · Face detect · Face track · Face recognise · Hand track · Body detect. Hand track uses a YCrCb skin mask + convex-hull / convexity defects to extract a pixel-skeleton overlay (palm centre + fingertips). VinX bridge reads the live feed via /tmp/luci-vision.json for "what I see now" prompt context.

Chapter 35 · post-v3.0

Topbar widgets & foldering

The topbar is a horizontal strip of independent widget .vx apps. Each widget owns its own .vx file so they can be hot-swapped without touching luci.py.

  • Brand hex — left-most, opens the Luci system menu
  • App menu folders — current focused window's menu items grouped by section header
  • Topbar foldering — Files dropdown shows favourites + recent items; can be nested
  • Wi-Fi — wpa_supplicant + dhclient bridge
  • Volume — mixer-driven slider with mute
  • Brightnessbacklight command (real panel dim) with xrandr fallback
  • Battery — ACPI; warns at 25% / 7%
  • Clock — date + time
  • VinX status — current brain mode + ready/thinking indicator

Click any widget → floating panel opens just below the topbar. Click outside → panel closes.

Chapter 36

Minimal example — a complete .vx app

# VX:name=Tiny Counter
# VX:icon=🔢
# VX:version=1.0
# VX:author=Your Name

import tkinter as tk
from luci import LucyWindow, C, FONT_BOLD

class Counter(LucyWindow):
    def __init__(self, desktop):
        super().__init__(desktop, "Counter", 240, 160, "🔢")
        self._n = 0
        self._lbl = tk.Label(self.content, text="0",
                             bg=C["win_bg"], fg=C["accent2"],
                             font=("Consolas", 32, "bold"))
        self._lbl.pack(pady=14)
        tk.Button(self.content, text="+1",
                  bg=C["accent"], fg=C["white"],
                  font=FONT_BOLD, relief="flat", bd=0,
                  padx=20, pady=6,
                  command=self._inc).pack()

    def _inc(self):
        self._n += 1
        self._lbl.config(text=str(self._n))

def main(desktop):
    Counter(desktop)

Chapter 37

Real example — app that talks to VinX

# VX:name=Ask Bot
# VX:icon=💬
# VX:author=Your Name

import threading, tkinter as tk
from luci import LucyWindow, C, FONT, FONT_BOLD

class AskBot(LucyWindow):
    def __init__(self, desktop):
        super().__init__(desktop, "Ask Bot", 460, 360, "💬")
        self._out = tk.Text(self.content, bg=C["win_bg"],
                            fg=C["text"], font=FONT,
                            wrap="word", relief="flat", bd=8)
        self._out.pack(fill="both", expand=True)
        self._inp = tk.Entry(self.content, bg=C["border"],
                             fg=C["text"], font=FONT,
                             insertbackground=C["white"],
                             relief="flat", bd=6)
        self._inp.pack(fill="x", padx=4, pady=4)
        self._inp.bind("<Return>", self._send)

    def _send(self, _=None):
        q = self._inp.get().strip()
        if not q: return
        self._inp.delete(0, "end")
        self._out.insert("end", f"You: {q}\nVinX: thinking...\n")
        threading.Thread(target=self._ask, args=(q,),
                          daemon=True).start()

    def _ask(self, q):
        import vinx_bridge as vb
        reply = vb.ask(q, timeout=60) or "(no reply)"
        self.after(0, lambda: self._out.insert("end", f"VinX: {reply}\n"))

def main(desktop):
    AskBot(desktop)

Chapter 38

Tips

  • Always import C fresh inside your app code — don't cache.
  • Use LucyWindow / _QtLucyWindow whenever possible — never hand-roll close/min/max buttons.
  • For long ops, use threading.Thread; marshal results via self.after.
  • Use lucy_log(category, message) for the activity log trail.
  • Built-in vars in val_str: $desktop_path, $home, $os, $time.
  • Press F1 for Gate; F11 for fullscreen toggle.
  • UI nodes should be idempotent (check ex._ui_kept[nid]).
  • For 3D apps: scene dict is the universal carrier between nodes.
  • Always declare # VX:net + # VX:files + resource intents in new apps — undeclared intent is itself a Cosmic Guard block.
  • Re-sign after every edit. Editing invalidates the signature.

Chapter 39

File system reference (current FreeBSD layout)

Two zones, hard split. System code at /usr/local/luci/ is package-manager territory — immutable (chflags schg), no user writes. User data at /home/luci/ (or $HOME) follows the XDG Base Directory spec — same place every other Unix tool expects to find it.

Zone 1 — System code (immutable install root)

/usr/local/luci/                                install root · package manager owns it · chflags schg
├── luci.py                                desktop entry point (single Qt5 process)
├── luci_wm.py                              window manager · frames native apps
├── luci_sign.py                            Ed25519 signing tool (legacy fallback)
├── luci_manifest.py                        build + sign system trust manifest
├── .keys/                                  root:wheel · 600 · schg
│   ├── luci_ed25519.priv                  private key (NEVER distribute)
│   ├── luci_ed25519.pub                   public key (also embedded in cosmic_guard)
│   ├── trusted_apps.json                   system manifest · sha256 per app
│   └── trusted_apps.sig                    Ed25519 signature of the manifest
├── Vinx-AI/                                VinX runtime — pure in-process Python
│   ├── vinx_bridge.py                      ★ THE single entry to the brain
│   ├── vinx_local.py                      local GGUF subprocess wrapper
│   ├── gpt_engine.py                      multi-provider API router (Claude/GPT/...)
│   ├── vinx_chat_session.py                browser-automation brain (Claude.ai etc.)
│   ├── vinx_chat_worker.py                LLM worker (llama-cpp)
│   ├── vinx_actions.py                     17-action capability registry
│   ├── vinx_os_manual.py                   system-prompt knowledge base
│   ├── vinx_camera.py                      /tmp/luci-vision.json bridge
│   ├── vinx_cosmic.py                      cosmic_bus subscription
│   ├── vinx_memory.py                     long-term memory
│   ├── heart_engine.py                    Old Soul: emotion
│   ├── vinx_turbo.py                      autonomous reasoning loop
│   ├── nodebase_ai.py                     text → .nbg graph generator
│   └── floating_core.py                   legacy orb process (port 52525 · unused by new code)
└── Vinx-Desktop/
    └── programfiles/                         HIDDEN system .vx apps · signed
        ├── vx_manual.txt                   ← THE manual content
        ├── manual.vx                       Tk viewer for vx_manual.txt
        ├── cosmic/                           Cosmic Core service layer
        │   ├── cosmic_core.vx              singleton orchestrator
        │   ├── cosmic_bus.vx               pub/sub event bus
        │   ├── cosmic_guard.vx             capability sandbox (chflags schg)
        │   ├── cosmic_grants.vx            permission registry
        │   ├── cosmic_prompt.vx            first-time grant dialog
        │   ├── cosmic_hal.vx               host adapter
        │   ├── cosmic_fs.vx                luci:// path resolver
        │   ├── cosmic_proc.vx              subprocess launcher
        │   └── cosmic_registry.vx          plugin / node provider discovery
        ├── docs/                              HTML docs
        │   ├── luci-manual.html            this rich-styled manual
        │   └── cosmic-security-pitch.html  investor pitch
        ├── nodebase.vx                     NodeBase EDITOR (private)
        ├── nbcore.vx                       NodeBase PLAYER (ships in every .run)
        ├── terminal.vx                     Qt terminal
        ├── vinx.vx                          VinX chat panel + plug button
        ├── vinx_settings.vx                 4-tab brain picker (local/api/chat/keys)
        ├── vinx_model.vx                    model picker UI
        ├── camera.vx                        cv2 face/hand/body tracking
        ├── permissions.vx                   cosmic.grants UI
        ├── brightness.vx                    backlight + xrandr
        ├── music.vx                        mpv music player
        ├── video.vx                        mpv video player
        ├── notes.vx                        notepad
        ├── pixel.vx                        image viewer
        ├── themes.vx                       theme picker (+AI Theme)
        ├── heart.vx                        Heart engine UI
        ├── learner.vx                      knowledge consolidator
        ├── monitor.vx                      system monitor
        ├── log.vx                          activity log viewer
        ├── check.vx                        system self-check
        ├── cpp_ide.vx                      C++ source editor
        ├── sysApps.vx                      external app launcher
        ├── trash.vx                        trash bin UI
        ├── hosting.vx                       localhost dev server panel
        ├── blackhole.vx                     private vault
        ├── python/                           portable Python runtime (Windows builds)
        ├── icons/                            app + dock icons
        └── models/vinX.gguf                 local LLM (always retained as fallback)

Zone 2 — User data (XDG-standard under $HOME)

/home/luci/                                     user home · all writable user state lives here
├── Desktop/                                visible desktop icons (.vx + .run + shortcuts)
├── Documents/                              user documents
│   └── activity_log.txt                   Luci's activity log (LOG_FILE)
├── Downloads/                              browser + Gate downloads
├── Pictures/                               photos · screenshots
├── Videos/                                 video files
├── Apps/                                   user-written / AI-generated .vx apps · unsigned by default
├── .config/luci/                           XDG config (CONFIG_DIR)
│   ├── profile.json                       theme + user name (USER_FILE)
│   ├── settings.json                      startup apps list
│   ├── vinx_brain.json                     active brain: local / api / chat_session
│   ├── cosmic_grants.json                  per-app per-resource permission state
│   ├── user_trusted.json                   user-added trusted app hashes (sha256)
│   ├── graphs/                            saved NodeBase .nbg + exported .run bundles
│   └── plugins/                           user-installed NodeBase plugins (.nbgplugin / .zip)
├── .local/share/luci/
│   └── trash/                            trash bin (XDG data dir)
└── .Xauthority                            used by `su luci -c "env DISPLAY=:0 ..."` restart

# Plus shared OS-level locations Luci writes to at runtime:
/tmp/
├── luci-wm-windows.json                    WM → Luci window list
├── luci-wm-cmd                             Luci → WM command pipe
├── luci-mpv-*.sock                         mpv JSON-IPC sockets (music/video)
├── luci-vision.json                        camera frame metadata for VinX
├── luci-stderr.log                         desktop stderr
└── luci-vx-errors.log                      .vx app crash log
Migration on first POSIX boot: luci.py:_migrate_user_data() auto-COPIES (never moves) any old <install>/Vinx-Desktop/desktop|documents|Photos|Video|.user|.trash/ trees to the new $HOME XDG locations, then renames the originals to <name>.MIGRATED-YYYYMMDD-HHMMSS so legacy code paths can never accidentally write back. Idempotent and safe to re-run.
Windows portable layout ignores Zone 2 entirely — everything (system code AND user data) stays inside <luci.py-dir>/Vinx-Desktop/.... The XDG split is a POSIX-only design choice.

Chapter 40 · post-v3.0

Troubleshooting — when something breaks, look here first

SymptomWhere to lookLikely cause
App opens then closes/tmp/luci-vx-errors.logPython exception in app's main()
App "won't talk to the network"App's # VX:net= headerDefault none if undeclared — add an allowed: host
Camera shows blackPermissions panelGrant was set to blocked; revoke + re-launch
"App bypassed Cosmic" toastBus log: cosmic.bypassApp used os.system or kernel binary directly — switch to cosmic.hal.run_cmd
Window has no traffic lightsApp's window codeHand-rolled chrome — switch to _QtLucyWindow / LucyWindow
Phantom audio after closing videovideo.vx _close overrideOverride _close, call mpv.stop() there
Black screen after WM restartluci_wm.py event loopBlocking next_event() drops desktop MapRequest — restore non-blocking path
Native app re-framed twiceluci_wm override-redirect handlingFrame must be override_redirect=True
Native app vanishes on workspace switch_wm_apply_workspaceNative windows are not workspace-bound; only SHOW all
App got "ServiceUnknown" on "Show in folder"luci_files1.py D-Bus registrationKeep a live reference to BusName + object or it GCs
Wi-Fi drops after sleep/etc/rc.local watchdogrtw88 + background_dhclient watchdog rebinds
"setsid not found"FreeBSD command differencessetsid doesn't exist on FreeBSD — use daemon -f
Stale deploy persistschflags schg + file overwritechflags noschg; chmod u+w; verify with grep -c marker
VinX won't answerVinX Settings → active brainLocal model file missing OR API key invalid — bridge falls back to local
Signed app now blocks pkg/sudoFile was edited after signingHash changed — fall back to trust <app.vx> (user) or manifest add (system) in Gate
Third-party app prompts on every actionApp not in any trust sourceOpen Gate, run verify <app.vx> → if UNTRUSTED, run trust <app.vx>
"manifest INVALID" toast at bootSystem manifest tampered or sig mismatchRun verify manifest; rebuild with manifest build (root) to re-sign
Vincent's app trusted on PC-A, prompts on PC-BPC-B never added the hashOn PC-B: Gate → trust cool_app.vx · once-per-recipient-per-app

Restart the desktop cleanly

pkill -9 -f luci_wm.py
pkill -9 -f luci.py
sleep 3
su luci -c "env DISPLAY=:0 XAUTHORITY=/home/luci/.Xauthority \\
    nohup python3 /usr/local/luci/luci.py \\
    > /tmp/luci-stderr.log 2>&1 </dev/null &"

Confirm the desktop actually rendered

ffmpeg -f x11grab -video_size 1920x1080 -i :0 -frames:v 1 /tmp/s.png
# black ≈ 8 KB · real ≈ 800 KB+
# scp + view it

End of manual

That's the system.

Feed this entire file to VinX once at startup so the Brain has full context. Re-feed when this manual changes.

  • Architecture: Vincent Ilagan
  • v3.1 update: Cosmic Core service layer, app signing (Ed25519), permissions registry, native app adoption (luci_wm), per-workspace pinning + immersive mode, VinX Bridge + 17-action registry, AI Theme generator
  • v3.0 update: Luci OS roadmap, system-port socket bridge, nbcore.vx player, new .run layout, exporter, 3D viewport perf
  • Maintained at: programfiles/vx_manual.txt · viewed via manual.vx · stylised at docs/luci-manual.html