Metadata-Version: 2.4
Name: otoe
Version: 0.1.7
Summary: Experimental Python UI runtime with reactive components and live previews.
Author: Ale
License-Expression: MIT
Project-URL: Homepage, https://github.com/NeonShapeshifter/Otoe
Project-URL: Repository, https://github.com/NeonShapeshifter/Otoe
Project-URL: Issues, https://github.com/NeonShapeshifter/Otoe/issues
Project-URL: Changelog, https://github.com/NeonShapeshifter/Otoe/blob/main/CHANGELOG.md
Keywords: ui,desktop,reactive,components,python
Classifier: Development Status :: 2 - Pre-Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: User Interfaces
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: mypy>=1.10; extra == "dev"
Provides-Extra: release
Requires-Dist: build>=1.2; extra == "release"
Requires-Dist: twine>=6; extra == "release"
Dynamic: license-file

# Otoe

Otoe is an experimental Python UI runtime for building desktop-style
interfaces with component functions, reactive state, explicit events, and a
renderer boundary that can evolve beyond the current HTML proof backend.

The project is early. The current repository is a technical preview for the
runtime model, visual case studies, and live preview loop. It is not yet a
stable public framework or a production desktop renderer.

## What Works Today

- Python component functions with typed widget contracts.
- `signal`, `computed`, `effect`, owner cleanup, and lifecycle hooks.
- `Show` and keyed `For` control flow.
- Fake-widget mounting and deterministic snapshots.
- Static HTML preview rendering.
- Shared live HTML preview server with click/input event dispatch.
- Optional JSX-like `template(...)` syntax that returns the same `Node` tree.
- Experimental portable `css(...)` / `StyleSheet` API plus low-level
  `utility_css()` / `utility_stylesheet()` helpers for app styling.
- `otoe plan` diagnostics for checking an app against the first offline
  hardware/cage profile before any deployment bundle exists, including static
  extraction of literal `className` state classes for simple local targets.
- First `otoe.ui` primitives: cards, badges, action buttons, tabs, toolbars,
  stat cards, data tables, dialogs, toasts, command palettes, app shells,
  sidebar navigation, route views, command registries, shortcut scopes, menus,
  controlled selects, section headers, empty states, and feedback toasts.
- Modern default presets for no-custom-CSS app surfaces: app frames, sidebars,
  topbars, surfaces, metric grids, metric tiles, status pills, and list rows.
- Keyboard handling for command palettes, menus, selects, and button-backed
  controls in the live preview backend.
- `FocusScope` support for live focus trapping and focus restoration in dialogs
  and popovers.
- Live autofocus support for command overlays and other focused inputs.
- Wraith-shaped and SaaS-shaped case studies using the same UI primitives.
- UI kit kitchen-sink preview for validating primitives outside one product shape.
- Utility-first reference app for validating low-level styling ergonomics.
- Headless native layout, paint, PNG output, hit-testing, and click dispatch
  for the first renderer spike.
- `NativeSurface` for mounting a tree, rendering PNG frames, dispatching
  clicks, and refreshing the headless native frame from one object.
- `NativeWindowDriver` for testable native-window event dispatch over a
  `NativeSurface`, plus an optional Tk wrapper for local experiments.
- `run_native(...)` as the experimental native app entry point, currently backed
  by the optional Tk wrapper.
- Driver-level `key_input(...)` text editing for printable keys, Backspace,
  Delete, Enter/Tab fallback, and shortcut fallback.
- Controlled native `ScrollView(scrollY=..., onScroll=...)` support with
  clipped paint, clipped hit-testing, and wheel dispatch through the native
  window driver.
- Headless native focus and keyboard handling for autofocus, click-to-focus,
  Tab traversal, focused keydown handlers, button submit keys, and global
  shortcut payloads.
- Headless controlled input text dispatch through `NativeSurface.input_text(...)`.
- Framework-neutral native task board demo with search, filtered rows, empty
  state, modal state, shortcuts, controlled scroll, and PNG frame output.
- Lazy `NativeSurface` refresh when reactive props or control-flow branches
  change outside direct surface events.
- Disabled widgets are skipped for native focus and click dispatch.
- `ScrollView` bounds clip native paint output and hit-tested clicks.
- Native paint includes disabled control defaults and focused control rings.

## What Is Not Ready Yet

- Production desktop rendering/windowing.
- GPU rendering, layout engine integration, or accessibility tree output.
- Stable public API guarantees.
- Full component library or shadcn/Horizon-style UI kit.
- Packaging for production apps.

## Native Renderer Status

The native path is currently a deterministic headless renderer spike. It can
layout mounted Otoe trees, emit paint commands, write PNG preview frames, and
exercise click, focus, keyboard, input, and scroll dispatch through
`NativeSurface`.

This is enough for renderer tests, visual fixtures, and early framework API
validation. It is not yet a production desktop backend: there is no GPU
renderer, platform accessibility tree, text shaping engine, retained windowing
backend, or backend compatibility promise. See
`ADR-012-native-backend-boundary.md` for the backend boundary and
`ADR-013-native-layout-hardening.md` for the current layout-hardening contract.
`ADR-014-native-overflow-clipping.md` defines the current overflow policy:
normal containers do not clip, while `ScrollView` clips paint and hit testing.
For day-to-day workflow choices, see `NATIVE_WORKFLOWS.md`.

Native and window-facing exports are intentionally marked as experimental. The
imports remain available for examples and tests, but they are not backend
compatibility promises:

```python
from otoe import api_status

assert api_status("NativeSurface").category == "experimental-native"
```

## Quick Start

Use Python 3.11 or newer.

Install the latest published package from PyPI:

```bash
python -m pip install otoe
```

For local development:

```bash
python -m venv .venv
. .venv/bin/activate
python -m pip install -e ".[dev]"
pytest -q
```

On Debian/Ubuntu systems that report an externally managed Python environment,
do not install Otoe into the system Python. Use the virtual environment above,
or run examples directly from a checkout with `PYTHONPATH=src:.`.

Run the local framework health check:

```bash
python -m otoe check
python -m otoe check --tests
python -m otoe check --tests -- tests/test_cli.py -k new
python -m otoe new my_app
```

After installation, the same commands are available through the `otoe` console
script:

```bash
otoe check
otoe new my_app
otoe render examples.quickstart:app --out preview.html --pretty
otoe render examples.quickstart:app --out preview.png --native
otoe plan examples.quickstart:app --profile cage --no-strict-styles
otoe build examples.quickstart:app --out dist/cage --no-strict-styles
otoe compare-contract expected.json actual.json
otoe dev examples.live_counter:app --port 8767
```

`otoe new my_app` writes a small renderable app plus `styles.css`; pass
`--no-css` when you want only the Python scaffold.

Render the generated app with its stylesheet:

```bash
cd my_app
otoe render app:app --out preview.html --css styles.css --pretty
otoe render app:app --out preview.png --native --css styles.css
```

Render an importable Otoe node or zero-argument factory to HTML:

```bash
python -m otoe render examples.quickstart:app --out preview.html --pretty
```

Apply an Otoe CSS file inline while rendering:

```bash
python -m otoe render examples.quickstart:app --out preview.html --css path/to/styles.css --pretty
```

Render the same target through the native PNG path:

```bash
python -m otoe render examples.quickstart:app --out preview.png --native
```

Check an app against the first offline hardware/cage profile:

```bash
python -m otoe plan app:app --profile cage --css styles.css
python -m otoe plan app:app --profile cage --backend native-python --css styles.css
python -m otoe plan app:app --profile cage --backend-capability-profile backend-profile.json --css styles.css
python -m otoe plan app:app --profile cage --backend-coverage-requirements backend-readiness.json
python -m otoe plan app:app --profile cage --utilities
python -m otoe plan app:app --profile cage --utilities --out dist/otoe-plan.json
python -m otoe plan app:app --profile cage --utilities --json
python -m otoe plan app:app --profile-file otoe.profile.toml --out dist/otoe-plan.json
python -m otoe build app:app --profile cage --backend-capability-profile backend-profile.json --css styles.css --out dist/cage
python -m otoe build app:app --profile cage --backend-coverage-requirements backend-readiness.json --out dist/cage
python -m otoe backend-profile native-python
python -m otoe backend-profile --backend-capability-profile backend-profile.json --json
python -m otoe backend-profile --backend-capability-profile backend-profile.json --coverage-declaration --out backend-coverage-declaration.json
python -m otoe backend-coverage --requirements examples/native/contracts/backend_readiness_expected.json --backend native-python
python -m otoe backend-coverage --requirements examples/native/contracts/backend_readiness_expected.json --backend-capability-profile backend-profile.json --out backend-coverage.json
python -m otoe deps app:app --profile-file otoe.profile.toml --json
```

`otoe plan` is diagnostic only. It imports and mounts the target, checks used
classes against the selected style sources and backend capability profile, then
reports portable, html-only, deferred, and invalid style work before building
or deploying a bundle.
`--json` emits the same report as machine-readable JSON, and `--out` writes that
JSON as the first plan artifact.
`otoe backend-profile` inspects the built-in `native-python` profile or a
candidate JSON profile and can emit the matching coverage declaration without
running a renderer replay. `otoe backend-coverage` compares that profile or an
explicit coverage declaration against a readiness/requirements JSON artifact.
When a profile or CLI flag declares backend coverage requirements, `otoe plan`
embeds a `backendCoverage` report and exits nonzero if the selected backend
capability profile misses required coverage. `otoe build` writes the same gate
as `otoe-backend-coverage.json` and refuses to write `manifest.json` when it
fails.

When `otoe.profile.toml` exists in the current directory, `otoe plan` uses it by
default. CSS paths are relative to the profile file:

```toml
profile = "cage"
utilities = true
css = ["styles.css"]
assets = ["static/logo.png"]

[runtime]
allow_runtime_installs = false
files = ["app.py"]

[backend]
name = "native"
capability = "native-python"
# Optional backend coverage gate:
# coverage_requirements = "backend-readiness.json"
# Or, for experimental backend candidates:
# capability_profile = "backend-profile.json"

[deps]
packages = ["pytest"]
extras = ["dev"]
```

Explicit CLI flags override the profile file. For example, `--css custom.css`
replaces the profile `css` list, and `--no-utilities` disables profile-enabled
utilities.

`otoe deps` audits declared `[deps]` entries against the current build
environment. It reports installed and missing packages plus known and unknown
Otoe extras. It does not install anything, download anything, import the app
target, or write files; missing packages must be installed manually before a
hardware/cage deployment. During `otoe build`, the same audit is written as
`otoe-deps.json` and invalid dependency audits stop the build before
`manifest.json` is written.

Write the first minimal offline bundle contract:

```bash
python -m otoe build app:app --profile-file otoe.profile.toml --out dist/cage
python -m otoe build app:app --profile-file otoe.profile.toml --out dist/cage --validate
python -m otoe pack dist/cage --out dist/cage.tar.gz
```

`otoe build` currently writes `dist/cage/otoe-plan.json`,
`dist/cage/otoe-deps.json`, `dist/cage/otoe-styles.json`, and, when backend
coverage requirements are declared, `dist/cage/otoe-backend-coverage.json`.
It then writes `dist/cage/manifest.json`, copies declared assets under
`dist/cage/assets/`, copies selected Otoe framework/runtime files under
`dist/cage/framework/`, copies the simple local target module under
`dist/cage/app/` when the target is shaped like `app:app`, follows simple
same-directory imports such as `import helpers` and
`from helpers import view`, and copies declared extra runtime files under
`dist/cage/app/`.
It fails when the plan, dependency audit, backend coverage gate, or backend
selection is invalid, allows warning plans, and does not install dependencies,
download anything, or auto-discover package modules or arbitrary dynamic
imports yet. `[runtime] files` remains the explicit place for packages, dynamic
imports, and extra app files. The manifest
references `otoe-deps.json`, records copied framework files in `frameworkFiles`,
and records copied app files in `runtimeFiles`. The style artifact records used
classes, resolved portable declarations, direct widget style props, omitted
html-only/deferred declarations, diagnostics, tokens, backend capability
metadata, and low-level `styleOps` that backend candidates can apply without
re-parsing CSS on the target. Backend tooling can consume the artifact with
`otoe.style_ops.load_style_ir(...)` and `otoe.style_ops.apply_style_ops(...)`
instead of indexing the JSON shape directly. The same artifact can be inspected
from the CLI with `otoe style-ir dist/cage/otoe-styles.json --summary` or
`otoe style-ir dist/cage/otoe-styles.json --json`; add `--strict` to fail when
`styleOps` drift from compiled `rules` or `directStyles`.

The bundle also includes `otoe-run.py`, a minimal generated runner. It adds the
copied `app/` and `framework/` directories to `sys.path`, loads the manifest
target, supports `--check` for import/load validation, and supports `--png
frame.png` for a single headless native PNG frame using the bundled compiled
styles. It also supports `--verify` to check referenced bundle files, sizes,
SHA-256 hashes, schema versions, declared backend coverage reports, and strict
Style IR drift through the copied `otoe.style_ops` runtime module.
Core bundle artifacts declared through `plan`, `deps`, `styles`, and
`backendCoverage` must also appear in `artifacts` with size/hash metadata, and
the runner rejects invalid plan, dependency, or style artifacts even if the
manifest hash entries were updated after tampering. Hardware bundles also keep
`runtimeInstallsAllowed = false` as a runner/pack invariant.
`--layout-check` runs native layout/paint validation without writing a PNG.
Runtime style rehydration also validates the same contract by default when
loading `otoe-styles.json`. Pass `otoe build --validate` to run the generated
runner's `--verify`, `--check`, and `--layout-check` modes after writing the
bundle; this confirms the copied files are intact, the target loads from the
bundle instead of only from the workspace, declared backend coverage still
passes, dependency/style artifacts remain valid, and compiled styles can drive
native rendering.

`otoe pack` verifies the bundle with `otoe-run.py --verify`, repeats strict
Style IR drift detection against `otoe-styles.json`, preserves
`otoe-backend-coverage.json` when the manifest declares it, and writes a
portable `.tar.gz` archive for deployment. The pack step keeps the bundle rooted
at the archive top level and excludes local cache directories such as
`__pycache__/` and `.pytest_cache/`.

Compare JSON contract artifacts:

```bash
python -m otoe compare-contract expected.json actual.json
python -m otoe compare-contract expected.json actual.json --json
python -m otoe compare-contract expected.json actual.json --max-diffs 5
python -m otoe compare-contract expected.json actual.json --ignore-path /pngSmoke/path --ignore-path /calls/raster/signature/0/subject --ignore-path /calls/raster/hash
PYTHONPATH=src:. python -m examples.native.backend_candidate_skeleton --composed-renderer-contract-json --compact-contract --composed-renderer-png /tmp/composed_renderer_candidate.png --contract-out examples/native/contracts/composed_renderer_compact_expected.json
PYTHONPATH=src:. python -m examples.native.backend_candidate_skeleton --backend-readiness-json --contract-out examples/native/contracts/backend_readiness_expected.json
PYTHONPATH=src:. python -m otoe backend-profile native-python --coverage-declaration --out examples/native/contracts/backend_coverage_full_declaration.json
PYTHONPATH=src:. python -m otoe backend-coverage --requirements examples/native/contracts/backend_readiness_expected.json --backend-capability-profile examples/native/contracts/backend_candidate_partial_profile.json
PYTHONPATH=src:. python -m examples.native.backend_candidate_skeleton --style-ops-contract-json --bundle dist/cage --contract-out actual-style-ops-contract.json
```

`otoe compare-contract` performs a deterministic deep JSON comparison, exits
zero only when the contracts match, and reports JSON-pointer paths for
differences. Use `--ignore-path` for intentionally environment-specific JSON
pointer fields. If the composed renderer PNG smoke filename differs from the
fixture, ignore `/pngSmoke/path`, `/calls/raster/signature/0/subject`, and
`/calls/raster/hash` together. Use it with compact renderer contracts when
checking backend candidates in CI. The native backend candidate fixtures at
`examples/native/contracts/composed_renderer_compact_expected.json` and
`examples/native/contracts/backend_readiness_expected.json` are the current
expected compact composed-renderer contract and aggregate readiness report. The
`examples/native/contracts/backend_coverage_full_declaration.json` fixture is
generated from the `native-python` capability profile and records widgets,
inputs, styles, and declared style omissions that profile claims to cover
against the readiness report. Candidate-specific declarations can still be
passed with `--coverage-declaration`, and candidate-specific JSON capability
profiles can be passed with `--backend-capability-profile`. The
bundle-backed StyleOps fixture at
`examples/native/contracts/bundle_style_ops_expected.json` is the expected
contract for the hardware-style `--bundle` path. Refresh these fixtures only
for intentional contract changes, using `--contract-out` instead of shell
redirection.

Run an importable live preview app locally:

```bash
python -m otoe dev examples.live_counter:app --port 8767
```

Generate the static Wraith Mission Exec preview:

```bash
PYTHONPATH=src:. python -m examples.wraith.mission_exec_preview > preview/wraith_mission_exec.html
```

Run the live Wraith Mission Exec preview:

```bash
PYTHONPATH=src:. python -m examples.wraith.mission_exec_live_preview
```

Then open <http://127.0.0.1:8767>. Use `SIMULATE FRAME` to verify that
signals, events, and rerendering are actually changing visible state.

Run the live SaaS preview:

```bash
PYTHONPATH=src:. python -m examples.saas.live_preview
```

Then open <http://127.0.0.1:8766>.

Generate the static UI kit preview:

```bash
PYTHONPATH=src:. python -m examples.ui.preview > preview/ui.html
```

Run the live UI kit preview:

```bash
PYTHONPATH=src:. python -m examples.ui.live_preview
```

Then open <http://127.0.0.1:8768>. Use the sidebar, command launcher,
`Ctrl+K`/`Meta+K`, command search, Enter key, `Escape`, and single-key command
shortcuts to verify the live command overlay and route switching.

Generate the framework-neutral native counter PNG frames through
`NativeSurface`:

```bash
PYTHONPATH=src:. python -m examples.native.counter_demo
```

This writes `preview/native/native_counter_before.png` and
`preview/native/native_counter_after.png`.

Generate the framework-neutral native task board PNG frames:

```bash
PYTHONPATH=src:. python -m examples.native.task_board_demo
```

This writes initial, filtered, and modal frames under `preview/native/`.

Generate native-window driver PNG frames, or open the optional Tk wrapper:

```bash
PYTHONPATH=src:. python -m examples.native.window_demo
PYTHONPATH=src:. python -m examples.native.window_demo --window
```

The `--window` command requires Python's Tk bindings and a graphical display. On
Debian/Ubuntu, install the OS package with:

```bash
sudo apt install python3-tk
```

The `--window` mode uses the experimental native entry point:

```python
from otoe import run_native

run_native(App(), stylesheet=styles, title="Otoe")
```

`run_native(...)` routes through the experimental `NativeBackendAdapter`
boundary. The only built-in backend name today is `"tk"`; it is a manual-test
adapter, not a production desktop backend. The `"tk"` adapter presents native
paint commands on a Tk Canvas so manual windows can show readable text. The
Canvas scales geometry up to 2x for larger windows while keeping font sizes in
logical native units; this is a presentation proof, not responsive layout
reflow. The headless PNG output path remains deterministic and still uses marker
text.

## Tiny Example

```python
from otoe import Button, Text, VStack, component, computed, mount, signal


@component
def Counter():
    count = signal(0)
    label = computed(lambda: f"Clicked {count.value} times")

    return VStack(
        Text(label),
        Button("Increment", onClick=lambda: count.set(count.value + 1)),
        gap=8,
    )


tree = mount(Counter())
```

## Event Signatures

Built-in widget event handlers are plain callables. Otoe validates the handler
arity when the event fires and includes the widget/event contract in developer
errors. Arity mismatches raise `EventHandlerArityError`, which remains an
`EventHandlerError` for compatibility.

| Widget | Event | Handler shape |
| --- | --- | --- |
| `Button` | `onClick` | `lambda: ...` |
| `Button` | `onKeyDown` | `lambda key: ...` |
| `Button` | `onFocus`, `onBlur` | `lambda: ...` |
| `Input` | `onChange` | `lambda value: ...` |
| `Input` | `onKeyDown` | `lambda key: ...` |
| `Input` | `onFocus`, `onBlur` | `lambda: ...` |
| `ScrollView` | `onScroll` | `lambda next_scroll_y: ...` |
| `ShortcutScope` | `onGlobalKeyDown` | `lambda event: ...` |

The same contracts are available programmatically:

```python
from otoe import Button, event_signature_for, format_event_signature

signature = event_signature_for(Button, "onKeyDown")
assert format_event_signature("onKeyDown", signature) == "onKeyDown(key)"
```

The current `otoe.ui` callback surface follows the same style: `onClick()`,
`on_query(value)`, `on_select(command_id | item_id)`, `on_change(value)`,
`on_open_change(open)`, and `on_navigate(route_id)`.

## Project Shape

Otoe is intentionally split into layers:

- **Core runtime:** nodes, components, signals, effects, events, owners, control flow.
- **Renderer boundary:** fake widgets, HTML preview, `NativeSurface`, and an
  early headless native layout/paint/input spike.
- **Style system:** portable style representation and CSS preview adapter.
- **UI kits:** current `otoe.ui` primitives, growing toward libraries inspired by systems like shadcn or Horizon UI.
- **Case studies:** Wraith validates dense operational UI; SaaS validates softer product UI.

## Repository Map

- `src/otoe/` - runtime package.
- `examples/native/` - framework-neutral native renderer spike demos.
- `examples/hardware/`, `examples/admin/`, and `examples/data_workflow/` -
  Phase 5 professional reference apps.
- `examples/wraith/` - Wraith-shaped components and live previews.
- `examples/saas/` - SaaS-shaped generality case study.
- `examples/ui/` - shared UI primitive kitchen-sink preview.
- `preview/` - generated HTML/CSS preview artifacts, including the shared
  `reference_theme.css` base used by the Phase 5 reference apps.
- `tests/` - runtime and preview regression tests.
- `ADR-*.md` - design decisions.
- `BENCHMARKS.md` - concrete Otoe-vs-Wraith UI change benchmarks.
- `COMPONENT_COOKBOOK.md` - small component, state, control-flow, live preview,
  and native smoke recipes.
- `EXAMPLES_GUIDE.md` - current quickstart, live, native, UI kit, SaaS, and
  Wraith example surfaces.
- `REFERENCE_APP_PATTERNS.md` - Phase 5 reference app boundaries, provider
  contracts, and extraction rules.
- `MENTAL_MODEL.md` - how nodes, components, signals, events, control flow,
  mounting, and renderers fit together.
- `NATIVE_WORKFLOWS.md` - when to use HTML render, native PNG,
  `NativeSurface`, `NativeWindowDriver`, and `run_native(...)`.
- `NATIVE_RENDERER_SPIKE.md` - current native renderer support and deferred work.
- `STYLE_GUIDE.md` - supported style parser, token, HTML, and native style
  subset behavior.
- `TESTING_GUIDE.md` - snapshot, HTML, native surface, window driver, PNG, and
  backend acceptance testing guidance.
- `WIDGET_CONTRACTS.md` - core widget, control node, UI component, callback,
  and model contracts.
- `ROADMAP.md` - current status and phase plan.

## Fixture Data

Preview data is fictitious and sanitized. The Wraith examples are design and
runtime case studies; they do not run recon, touch network interfaces, or
perform security operations.

## Status

Current status: v0.1.7 public sync prepared; backend coverage gates, hardware
bundle verification, and Style IR packaging hardening are staged for the next
public release. See
`ROADMAP.md` for the active plan.

## License

MIT License. Copyright (c) 2026 Forvara.
