Architecture¶
panelini is a layout framework plus a panel library. This page explains how the pieces fit together, how they talk to each other, and what design decisions shaped the codebase.
Three layers¶
graph TB
subgraph core [" Core "]
init(["__init__.py"])
main(["Panelini"])
css(["main.css"])
end
subgraph panels [" Panels ( standalone ) "]
je(["JsonEditor"])
vn(["VisNetwork"])
gdt(["GraphDetailTool"])
ai(["AiChat"])
end
subgraph components [" Components ( panelini-coupled ) "]
future(["future components"])
end
init --> main
gdt --> vn
gdt -.-> je
ai -.-> main
classDef coreNode fill:#1e293b,stroke:#334155,color:#f8fafc
classDef panelNode fill:#0d7377,stroke:#095c5f,color:#ffffff
classDef componentNode fill:#6366f1,stroke:#4f46e5,color:#ffffff
class init,main,css coreNode
class je,vn,gdt,ai panelNode
class future componentNode
Layer |
What it does |
Where it lives |
|---|---|---|
Core |
Dashboard shell: header, sidebars, main area, footer. |
|
Panels |
Self-contained reusable UI: JSON editor, graph, chat. Work with or without Panelini. |
|
Components |
Building blocks that depend on the Panelini framework. Installed as optional extras. |
|
The key distinction: panels never import Panelini. They’re plain Panel components that plug into any dashboard. Components, by contrast, assume the panelini layout exists and wire into it directly.
Dashboard layout¶
graph TB
subgraph layout [" Panelini "]
direction TB
subgraph header [" Header "]
direction LR
logo(["Logo"]) --- title(["Title"]) --- nav(["Nav buttons"])
end
subgraph content [" Content "]
direction LR
sl(["Left sidebar"]) --- ma(["Main"]) --- sr(["Right sidebar"])
end
subgraph footer [" Footer "]
foot(["Footer content"])
end
end
header --> content
content --> footer
classDef h fill:#1e293b,stroke:#334155,color:#f8fafc
classDef m fill:#0d7377,stroke:#095c5f,color:#ffffff
classDef s fill:#6366f1,stroke:#4f46e5,color:#ffffff
classDef f fill:#94a3b8,stroke:#475569,color:#ffffff
class logo,title,nav h
class ma m
class sl,sr s
class foot f
Every region accepts any Panel object. Each is managed by a matching trio of methods:
Region |
Set |
Add |
Get |
|---|---|---|---|
Main |
|
|
|
Left sidebar |
|
|
|
Right sidebar |
|
|
|
Footer |
|
|
|
main_remove_index, main_clear, and friends round out the API.
Panel bridge (AnyWidget + Vue)¶
JsonEditor, VisNetwork, and GraphDetailTool all follow the same pattern: a Python-side param.Parameterized class speaks to a Vue.js wrapper in the browser via the AnyWidget bi-directional sync.
graph LR
subgraph python [" Python server "]
props(["param properties"])
callbacks(["@param.depends callbacks"])
end
subgraph bridge [" AnyWidget "]
sync(["bi-directional sync"])
end
subgraph browser [" Browser "]
vue(["Vue wrapper"])
lib(["JS library"])
dom(["DOM"])
end
props <--> sync
sync <--> vue
vue --> lib --> dom
dom -- events --> vue
vue -- "_event_data" --> sync
sync -- callback --> callbacks
classDef py fill:#1e293b,stroke:#334155,color:#f8fafc
classDef br fill:#6366f1,stroke:#4f46e5,color:#ffffff
classDef js fill:#0d7377,stroke:#095c5f,color:#ffffff
class props,callbacks py
class sync br
class vue,lib,dom js
Key points:
Param → JS — props (nodes, edges, options, value) sync automatically on change.
JS → Param — user events write to a single
_event_dataparam, which Python callbacks unpack.One-shot actions — methods like
add_nodeorset_schemaset a param that the frontend observes for a single tick.Bundled assets — JS + CSS are pre-built and shipped with the package. No
npm installat deploy time.
Data flow for a user interaction¶
sequenceDiagram
participant User
participant Vue as Vue wrapper
participant Bridge as AnyWidget
participant Py as Panel component
participant App as Your callback
User->>Vue: click / drag / type
Vue->>Bridge: _event_data = {...}
Bridge->>Py: sync param
Py->>Py: @param.depends fires
Py->>App: on_event(kind, data)
App->>Py: update_node(...)
Py->>Bridge: sync param
Bridge->>Vue: apply change
Vue->>User: re-render
The AI chat panel¶
graph TB
subgraph ai [" panelini.panels.ai "]
direction TB
fe(["AiChat<br/>frontend.py"])
be(["AiBackend<br/>backend.py"])
ifc(["AiInterface<br/>utils/ai_interface.py"])
cfg(["load_config<br/>utils/config.py"])
tools(["basic_tools.py<br/>+ user tools"])
end
subgraph providers [" Providers "]
anth(["Anthropic"])
azure(["Azure OpenAI"])
end
fe --> be
be --> ifc
be --> cfg
be --> tools
ifc --> anth
ifc --> azure
classDef ai fill:#0d7377,stroke:#095c5f,color:#ffffff
classDef prov fill:#6366f1,stroke:#4f46e5,color:#ffffff
class fe,be,ifc,cfg,tools ai
class anth,azure prov
AiChat— UI: chat widget, sidebar controls, markdown preview pane. Exposesmain_objectsandsidebar_objectsfor embedding.AiBackend— business logic: provider/model switching, tool-call loop, history management, export/import.AiInterface— thin LangChain wrapper that’s provider-agnostic. Streaming + tool binding in one place.Config — YAML file with env-var interpolation. Auto-discovered from
PANELINI_AI_CONFIG_PATH, thenconfig.ymlwalking upward, then the bundled default.
GraphDetailTool composition¶
graph TB
subgraph gdt [" GraphDetailTool "]
direction TB
subgraph controls [" Edit controls "]
direction LR
dis(["Disable edit"])
an(["Add node"])
ae(["Add edge"])
end
subgraph workspace [" Workspace "]
direction LR
vn(["VisNetwork"])
subgraph detail [" Detail pane "]
direction TB
viz(["Visualization"])
ed(["JsonEditor"])
end
end
end
controls --> vn
vn -- "node click" --> detail
ed -- "value change" --> vn
classDef c fill:#8b7355,stroke:#6b5840,color:#ffffff
classDef g fill:#0d7377,stroke:#095c5f,color:#ffffff
classDef d fill:#6366f1,stroke:#4f46e5,color:#ffffff
class dis,an,ae c
class vn g
class viz,ed d
GraphDetailTool is a reference implementation of the compose-panels pattern: take VisNetwork and JsonEditor, wire their events together, and expose one layout.
Features:
Single-node click → visualisation + editor
Multi-select → comparison table with bulk editing
Content-type detection → image / CSV / PDF / text rendering
Drag events → node positions sync back to the graph
Design decisions¶
No re-invention of reactivity. panelini rides entirely on
param— the same foundation Panel is built on.Bundle the frontend. Users don’t need a JS toolchain to deploy a panelini app.
Opt-in heaviness. LangChain is an optional extra; background images can be switched off.
Stable panels, evolving core. Panels are versioned with their JS bundles; the Panelini class is where most churn lives.
See also¶
API reference — API reference overview
Panels — guide to each reusable panel
Examples — runnable walkthroughs