Packaging, WebUI build, and cross-platform behavior
Corresponding source
| Subject | Source |
|---|---|
| Python package and build hooks | pyproject.toml, hatch_build.py |
| WebUI build configuration | webui/package.json, webui/vite.config.ts |
| WebUI static-asset integration | nanobot/web/ |
| Platform-sensitive Tools | nanobot/agent/tools/shell.py, sandbox.py |
| Build and platform tests | tests/test_package_version.py, tests/tools/test_exec_platform.py, tests/webui/, webui/src/tests/ |
Learning objectives
After this lesson, you should be able to:
- explain why the nanobot wheel contains Python, templates, Skills, WebUI, and Bridge content;
- distinguish the frontend development server from embedded production assets;
- locate differences between Windows and Unix Shell behavior;
- choose the correct verification command after changing release-related files.
Prerequisites
- Know that a wheel is a Python installation package.
- Know that Vite builds React/TypeScript into browser-loadable static files.
- Read basic
pyproject.tomlandpackage.jsonfields; React authoring is not required.
1. The product contains more than Python files
The current pyproject.toml builds with Hatchling. The wheel includes:
nanobot/**/*.py;- prompt templates;
- built-in Skills;
- generated
nanobot/web/dist; - other explicit resources.
force-include puts the repository-root bridge/ directory into the installed package at nanobot/bridge. The final two locations are build/install targets and may not exist in a clean source tree.
Two common changes can therefore work from source and fail after installation:
- adding a resource without including it in the wheel;
- changing WebUI source without first generating
nanobot/web/dist.
2. Two WebUI runtime modes
Development mode
webui/package.json provides dev. Vite runs on port 5173 by default and proxies HTTP routes such as /webui, /api, and /auth to:
NANOBOT_API_URLThe default is http://127.0.0.1:8765.
The WebSocket client uses its own connection address. Do not assume every WebSocket frame goes through Vite’s HTTP proxy.
Embedded mode
webui/vite.config.ts writes the production build to:
nanobot/web/distThe Python WebUI server serves static assets from that directory, and the released wheel must include it.
flowchart LR A["webui/src<br/>React + TypeScript"] --> B["Vite build"] B --> C["nanobot/web/dist"] C --> D["Hatch wheel"] D --> E["Installed nanobot WebUI"] F["bridge/"] -->|"force-include"| D G["nanobot/**/*.py"] --> D H["templates / Skills"] --> D
3. Bridge boundary
Bridge is not part of AgentLoop. It is an adapter resource for communication between an external platform and nanobot, included so the installed runtime can locate it.
When studying one, first ask whether its message still becomes an InboundMessage, then inspect the Bridge protocol. Shipping Bridge in the wheel is not a reason to put platform logic in the core.
4. Python and frontend version entry points
Key files:
pyproject.toml: Python version, dependencies, console script, build includes;webui/package.json: frontend scripts and dependencies;webui/vite.config.ts: development proxy and production output;nanobot/web/: Python static-resource service;nanobot/__init__.py: package version entry point;nanobot/cli/commands.py: CLI entry point.
Use requires-python in pyproject.toml as authority for Python. The surrounding documentation repository requires Node.js 22+ for its website, but nanobot WebUI package management and scripts are governed by webui/package.json and nanobot’s repository documentation.
5. Windows and Unix differences
Shell startup
ExecTool._spawn():
- uses
asyncio.create_subprocess_shell()for a one-line Windows command; - explicitly invokes
powershell -NoProfile -Commandfor a multiline Windows command; - selects bash by default on Unix, with allowed
sh,bash, orzsh; - reads the corresponding profile for a Unix login Shell.
Documentation and tests must not assume that Bash quoting works everywhere.
Sandbox
- bwrap wraps only the non-Windows path;
- Windows logs a warning and continues unsandboxed;
- parent-directory fsync may be skipped on Windows when the directory cannot be opened.
Paths and encoding
- source uses
Path.resolve(),os.pathsep, and path normalization extensively; - subprocess output is decoded as UTF-8 with replacement for invalid bytes;
- Session/configuration JSON uses UTF-8 and
ensure_ascii=False; - on Windows, do not confuse
\path separators with escape sequences.
6. Minimum verification after a change
Python core
From example/nanobot/code-EN:
pytest tests\matching_test_file.pyIf the package manifest or resource path changes, build the wheel and inspect its contents rather than checking only the command exit code.
WebUI
From example/nanobot/code-EN/webui, use the project’s lockfile and scripts:
bun run test
bun run buildThen verify that nanobot/web/dist changed and the Python server can serve the entry file.
Repository checks
Project rules explicitly prohibit ruff format because it would rewrite unrelated files. Run only the lint, test, or build command defined by the project and relevant to the change.
This learning library does not modify the source snapshot
These commands are for later isolated practice. Reading the lessons does not require a full build.
7. Common failures
| Symptom | Inspect first |
|---|---|
| source WebUI works, page is 404 in wheel | whether nanobot/web/dist was built and included |
| frontend API works, WebSocket connection fails | actual WebSocket address, not only the Vite HTTP proxy |
| command works on Linux but fails on Windows | Shell selection, path separator, quoting |
| bwrap configured but Windows still reaches host resources | this is the current explicitly unsupported path |
| Bridge file missing after installation | force-include in pyproject.toml and wheel contents |
| non-ASCII path or output is garbled | subprocess encoding, terminal encoding, whether file is UTF-8 |
8. Source and tests
Configuration and source:
pyproject.tomlwebui/package.jsonwebui/vite.config.tsnanobot/web/nanobot/agent/tools/shell.pynanobot/agent/tools/sandbox.py
Tests and release checks:
tests/test_package_version.pytests/cli/test_commands.pytests/tools/test_exec_platform.pytests/webui/webui/src/**/*.test.ts
Concrete test names can change. Locate them from the current output of rg --files tests webui.
Self-check
- Why might committing only a
webui/srcchange be insufficient for release? - How do the Vite development proxy and production static assets differ?
- What does bwrap actually do on Windows?
- After adding a template file, what should you verify beyond Python tests?
Next section: Extension Development