This guide is written for coding agents and fast-moving builders who want to extend this repository without redesigning the architecture from scratch.
This repository does not require an API wrapper for normal UI work.
Use this flow first:
- Add UI in a page module under template-basic/view/.
- Load data directly in Python when the page is rendered.
- Keep visible labels and dummy content in template-basic/config.json.
- Add a small API route only when external clients need it.
Use a separated frontend/backend architecture only if you actually need independent deployment, a public API surface, or a JavaScript-heavy app.
flowchart LR
A[Python logic] --> B[NiceGUI page]
B --> C[Shared shell]
C --> D[Browser UI]
A --> E[CSV / local files / local state]
Use this when one Python app owns the logic and the UI.
flowchart LR
A[Python backend] --> B[REST / WebSocket API]
B --> C[React / Vue frontend]
C --> D[Browser UI]
A --> E[DB / services]
Use this only when the separation solves a real deployment or integration problem.
- template-basic/main.py: loads config, theme values, registers pages, exposes a tiny API example
- template-basic/view/layout.py: shared ArkIde-style shell with left rail, main area, and right rail
- template-basic/view/home.py: home page example
- template-basic/view/chat.py: standalone chat example with local state only
- template-basic/view/dashboard.py: CSV-backed dashboard example with chart and table
- template-basic/config.json: text, layout options, preview data, dashboard settings, theme values
- template-basic/static/custom.css: shell styling and component polish
- template-basic/data/trading_engine_historical_data.csv: sample market data source
When adding a new feature, follow this order.
- Add a new page file under template-basic/view/.
- Register it in template-basic/main.py.
- Add a navigation entry in template-basic/config.json.
- Reuse render_shell from template-basic/view/layout.py.
- Put labels, section names, and fake content in template-basic/config.json instead of hardcoding them.
- Add only the minimum CSS needed in template-basic/static/custom.css.
Use this shape.
from nicegui import ui
from .layout import render_shell
def create_example_page(*, app_title: str, shell_content: dict, example_content: dict) -> None:
@ui.page('/example')
def example_page() -> None:
ui.page_title(f'{app_title} - Example')
def workspace() -> None:
with ui.element('section').classes('ark-console-card w-full'):
ui.label(example_content.get('title', 'Example')).classes('ark-section-title')
ui.label(example_content.get('copy', '')).classes('ark-console-copy')
render_shell(
app_title=app_title,
active='example',
shell_content=shell_content,
workspace_builder=workspace,
)Then register it in template-basic/main.py and add a nav entry in template-basic/config.json.
If the data is local and only used by this app, load it directly in the page module.
That is what template-basic/view/dashboard.py already does:
- Reads CSV with Python.
- Filters rows for the requested symbol and timeframe.
- Builds chart options in Python.
- Passes the result straight into NiceGUI.
This is the right choice for local tools, personal dashboards, prototypes, internal utilities, and offline or single-user workflows.
Add an API layer only if one of these is true.
- Another application needs to consume the same data.
- You want a JavaScript frontend deployed separately from Python.
- You need mobile, desktop, or third-party clients to call the backend.
- You need strict service boundaries for scaling or security.
If none of those are true, direct Python-driven UI is usually faster and easier to maintain.
Most people do not begin with a technical request.
They begin with something like this:
- I want something like a personal chat workspace.
- I want a screen like LM Studio, but simpler.
- I want a dashboard like a trading monitor.
- I want a local tool that remembers my notes and prompts.
- I want a page where I can load files, ask questions, and keep the results.
That is the right starting point.
The job of the AI is to translate that intent into concrete edits.
Use this mapping.
- "I want something like a local chat app" Result:
- start from template-basic/view/chat.py
- add model connection later
- keep local state first
- "I want something like a market dashboard" Result:
- start from template-basic/view/dashboard.py
- use CSV or local files first
- add selectors and derived metrics before adding a database
- "I want something like my personal AI workspace" Result:
- combine chat, notes, prompts, and file views
- add new pages under template-basic/view/
- keep labels and card content in template-basic/config.json
- "I want something like LM Studio, but for my workflow" Result:
- do not begin by cloning LM Studio features
- define the actual workflow first: chat, file search, evaluation, notes, export, dashboard
- implement the workflow in this shell one page at a time
- "I want a tool that remembers things" Result:
- first define what must be remembered
- if simple, store local files or JSON
- only add a DB after the memory model is clear
Before building, force the request into this sentence:
"I want to build a tool that helps me do X, by showing Y, storing Z, and letting me trigger W."
Once that sentence is clear, implementation becomes much easier.
They usually do not want:
- a raw model loader
- a generic API server
- a blank GUI shell
They usually want:
- a screen that feels like their workbench
- a repeatable workflow
- a place where chat, files, prompts, and results live together
- a tool that fits their own process instead of a public demo checklist
Default to local page state first.
- use local lists and values for chat demos
- derive dashboard data from files or config on render
- store reusable copy and display knobs in template-basic/config.json
Only introduce shared state when multiple pages truly need the same live data.
Keep the visual language stable.
- Prefer CSS variables over hardcoded colors and widths.
- Reuse the existing shell cards and spacing.
- Add new classes only when the current classes cannot express the new component.
- Avoid page-specific one-off hacks if the pattern may repeat.
For charts, start with the built-in NiceGUI ECharts path used in template-basic/view/dashboard.py.
This avoids extra dependencies for common cases like line charts, candlesticks, bar charts, and volume overlays.
Only add another charting package if ECharts genuinely blocks a required feature.
Before editing:
- Read template-basic/main.py, template-basic/config.json, and the target page in template-basic/view/.
- Check whether the requested text already belongs in config.json.
- Reuse render_shell unless the request explicitly replaces the shell.
While editing:
- Keep changes narrow.
- Do not split the app into frontend plus API unless the user asked for that architecture.
- Use the existing naming and page registration pattern.
After editing:
- Check Python errors.
- Start the app on the configured port.
- Confirm the new route is reachable.
If another AI needs a clear next task, these are safe.
- Add symbol and timeframe selectors to template-basic/view/dashboard.py.
- Add file upload and preview pages using the same shell.
- Replace dummy preview content in template-basic/config.json with project-specific controls.
- Add a second dashboard card for moving averages or volatility.
- Add export buttons that work locally before introducing APIs.
If you hand this repo to another AI, give it constraints that match the template instead of asking for a generic webapp.
Good prompt shape:
- name the page to edit
- name the data source
- say whether copy belongs in config.json
- say whether the shared shell must stay intact
- explicitly forbid unnecessary API separation
See AI_PROMPT_TEMPLATES.md for copy-paste prompts.
For this repository, the fastest path is:
Python logic -> NiceGUI page -> shared shell -> config-driven copy
Not:
Python backend -> custom API wrapper -> separate frontend -> extra complexity
Start simple, keep the architecture close to the actual problem, and only add boundaries when they solve a real deployment need.