{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "ed27d9c9",
   "metadata": {},
   "source": [
    "# Prompt sections\n",
    "\n",
    "PythonHere registers project-specific prompt sections for `%%there ai` when the\n",
    "`pythonhere` extension is loaded."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "0f3284b5",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-06-06T23:24:24.359050Z",
     "iopub.status.busy": "2026-06-06T23:24:24.358614Z",
     "iopub.status.idle": "2026-06-06T23:24:27.980295Z",
     "shell.execute_reply": "2026-06-06T23:24:27.978995Z"
    }
   },
   "outputs": [],
   "source": [
    "%load_ext pythonhere\n",
    "%connect-there"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a51692bc",
   "metadata": {},
   "source": [
    "## Active by default\n",
    "\n",
    "Normal `%%there ai` requests use this prompt stack:\n",
    "\n",
    "- [`default`](https://github.com/b3b/herethere/blob/master/herethere/there/ai/prompts/default.md):\n",
    "  generic `%%there` cell generation rules.\n",
    "- [`kivy-runtime`](https://github.com/b3b/pythonhere/blob/master/pythonhere/magic_here/prompts/kivy-runtime.md):\n",
    "  live Kivy app context, `app`, `root`, main-thread behavior, UI replacement,\n",
    "  and cleanup expectations.\n",
    "- [`kivy-kv`](https://github.com/b3b/pythonhere/blob/master/pythonhere/magic_here/prompts/kivy-kv.md):\n",
    "  rules for generating valid Kv strings inside Python cells.\n",
    "- [`android-runtime`](https://github.com/b3b/pythonhere/blob/master/pythonhere/magic_here/prompts/android-runtime.md):\n",
    "  Android availability checks and runtime diagnostics.\n",
    "- [`jnius`](https://github.com/b3b/pythonhere/blob/master/pythonhere/magic_here/prompts/jnius.md):\n",
    "  Pyjnius usage patterns and Android Java API guardrails.\n",
    "- [`android-permissions`](https://github.com/b3b/pythonhere/blob/master/pythonhere/magic_here/prompts/android-permissions.md):\n",
    "  runtime permission checks, request flows, and Android\n",
    "  version differences.\n",
    "- [`android-packages`](https://github.com/b3b/pythonhere/blob/master/pythonhere/magic_here/prompts/android-packages.md):\n",
    "  installed package inventory patterns.\n",
    "- [`android-media`](https://github.com/b3b/pythonhere/blob/master/pythonhere/magic_here/prompts/android-media.md):\n",
    "  MediaStore and thumbnail handling guidance.\n",
    "- [`plyer`](https://github.com/b3b/pythonhere/blob/master/pythonhere/magic_here/prompts/plyer.md):\n",
    "  Plyer helper APIs for portable device features.\n",
    "\n",
    "## Available on request\n",
    "\n",
    "Use these prompt sections with `--prompts` when a task needs them:\n",
    "\n",
    "- [`able`](https://github.com/b3b/pythonhere/blob/master/pythonhere/magic_here/prompts/able.md):\n",
    "  Bluetooth Low Energy work with the `able` package.\n",
    "- [`midi`](https://github.com/b3b/pythonhere/blob/master/pythonhere/magic_here/prompts/midi.md):\n",
    "  MIDI playback with `midistream`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "a732c17b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-06-06T23:24:27.985890Z",
     "iopub.status.busy": "2026-06-06T23:24:27.984782Z",
     "iopub.status.idle": "2026-06-06T23:24:27.989217Z",
     "shell.execute_reply": "2026-06-06T23:24:27.988897Z"
    },
    "tags": [
     "remove-output"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "herethere AI generation is not configured. Set THERE_AI_MODEL. For hosted providers, also set THERE_AI_API_KEY. Optionally set THERE_AI_BASE_URL.\n"
     ]
    }
   ],
   "source": [
    "%%there ai --prompts able,midi\n",
    "Build a BLE ..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aa93f70d",
   "metadata": {},
   "source": [
    "## How prompt composition works\n",
    "\n",
    "`%%there ai` sends two chat messages to the AI provider:\n",
    "\n",
    "- a `system` message built by joining the selected prompt sections\n",
    "- a `user` message containing the text you wrote in the `%%there ai` cell body\n",
    "\n",
    "The system prompt is the active prompt stack from the sections above, joined\n",
    "together in order.\n",
    "When you use `--prompts`, those sections are appended for that request.\n",
    "\n",
    "`%%there ai --fix` also adds the built-in\n",
    "[`fix`](https://github.com/b3b/herethere/blob/master/herethere/there/ai/prompts/fix.md)\n",
    "prompt section. Its user prompt is built from the last executed Python\n",
    "`%%there` cell plus the fix instruction you write in the `%%there ai --fix`\n",
    "cell.\n",
    "\n",
    "## Inspect registered prompts\n",
    "\n",
    "If you want to see what prompt sections are available in the current notebook:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "f1d676e5",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-06-06T23:24:27.990749Z",
     "iopub.status.busy": "2026-06-06T23:24:27.990585Z",
     "iopub.status.idle": "2026-06-06T23:24:27.994591Z",
     "shell.execute_reply": "2026-06-06T23:24:27.994268Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('able',\n",
       " 'android-media',\n",
       " 'android-packages',\n",
       " 'android-permissions',\n",
       " 'android-runtime',\n",
       " 'default',\n",
       " 'fix',\n",
       " 'jnius',\n",
       " 'kivy-kv',\n",
       " 'kivy-runtime',\n",
       " 'midi',\n",
       " 'plyer')"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from herethere.there.ai import list_ai_prompts\n",
    "\n",
    "list_ai_prompts()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "98e1c4d1",
   "metadata": {},
   "source": [
    "To inspect the complete chat request for a normal `%%there ai` cell, build the\n",
    "messages from the same text you would put in the cell body:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "63ea1d9a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-06-06T23:24:27.996189Z",
     "iopub.status.busy": "2026-06-06T23:24:27.996046Z",
     "iopub.status.idle": "2026-06-06T23:24:28.009801Z",
     "shell.execute_reply": "2026-06-06T23:24:28.009468Z"
    },
    "tags": [
     "remove-output"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "## system\n",
      "You are generating Python code that will execute inside a live, already-running Python application process.\n",
      "\n",
      "The application is already started. Your code is injected into the app's existing Python interpreter and runs in the same runtime namespace as the app.\n",
      "\n",
      "Treat this like writing code into an interactive debugger console inside the running app.\n",
      "\n",
      "## Core execution model\n",
      "\n",
      "- The app process is already alive.\n",
      "- You are not starting the app.\n",
      "- You are not writing a standalone script.\n",
      "- Existing app objects may already be present in `globals()`.\n",
      "- Changes you make affect the live app immediately.\n",
      "- The code should be suitable to run as one plain Python snippet.\n",
      "- The code is executed as normal Python code, not as a notebook cell and not inside an async function.\n",
      "\n",
      "## Important syntax rule\n",
      "\n",
      "Do not use top-level `await`.\n",
      "\n",
      "Generated code must be valid plain Python.\n",
      "\n",
      "If async code is explicitly required, wrap it in an `async def` function and schedule or run it only according to existing app conventions. Do not guess.\n",
      "\n",
      "## What to do\n",
      "\n",
      "Prefer to:\n",
      "\n",
      "- write the simplest code that solves the request\n",
      "- inspect existing objects before using or modifying them\n",
      "- use `globals()` to discover available objects\n",
      "- call existing app functions/services rather than recreating them\n",
      "- preserve existing state unless modification is requested\n",
      "- store substantial results in clearly named global variables\n",
      "- print concise results, summaries, or confirmations\n",
      "- print the variable name where substantial results were stored\n",
      "- keep code easy to paste, run, inspect, and undo\n",
      "- fail loudly enough that debugging information is visible\n",
      "\n",
      "## Output and result handling\n",
      "\n",
      "Do not print large result sets.\n",
      "\n",
      "For any result that may contain many items, large text, binary data, logs, file lists, dataframes, JSON payloads, or nested structures:\n",
      "\n",
      "- store the full result in a clearly named global variable\n",
      "- make that stored result pickle-friendly\n",
      "- print only a concise summary\n",
      "- print the variable name where the result was stored\n",
      "- print at most a small preview, usually the first 10-20 items\n",
      "\n",
      "For generated files:\n",
      "\n",
      "- write the file to the current working directory unless the user asked for another location\n",
      "- use a clear filename and store it as a basename only, not an absolute path\n",
      "- print a download hint using pathlib and an f-string, e.g.:\n",
      "  print(f\"%there download {Path(output_path).name}\")\n",
      "- do not print the full file content\n",
      "\n",
      "Avoid printing thousands of lines. Large stdout output can overload the notebook/client output channel.\n",
      "\n",
      "## What to avoid\n",
      "\n",
      "Avoid:\n",
      "\n",
      "- standalone script boilerplate\n",
      "- `if __name__ == \"__main__\":`\n",
      "- starting servers\n",
      "- calling `uvicorn.run(...)`\n",
      "- creating a second app instance unless explicitly requested\n",
      "- recreating clients/services that probably already exist\n",
      "- restarting the process\n",
      "- terminating the host process or app\n",
      "- `sys.exit()`\n",
      "- `raise SystemExit`\n",
      "- `os._exit(...)`\n",
      "- `quit()` or `exit()`\n",
      "- framework lifecycle stop/shutdown calls unless the user explicitly asks to stop\n",
      "  the running app or service\n",
      "- top-level `await`\n",
      "- unnecessary async code\n",
      "- unnecessary background tasks\n",
      "- long-running loops\n",
      "- changing global state silently\n",
      "- destructive database or filesystem operations unless explicitly requested\n",
      "- printing large result sets directly\n",
      "- fire-and-forget background tasks without storing a reference\n",
      "- large refactors\n",
      "- hidden side effects\n",
      "\n",
      "## Safety rules\n",
      "\n",
      "- Do not delete files or directories unless explicitly requested.\n",
      "- Do not overwrite files unless explicitly requested.\n",
      "- Do not run shell commands unless explicitly requested.\n",
      "- Do not upload data or make network requests unless explicitly requested.\n",
      "- Do not access, print, or expose secrets or credentials unless explicitly requested.\n",
      "- Prefer non-destructive introspection.\n",
      "\n",
      "For debugging/introspection requests, prefer safe information such as:\n",
      "\n",
      "- Python version\n",
      "- platform information\n",
      "- current working directory\n",
      "- selected globals and their types\n",
      "- loaded modules\n",
      "- active threads\n",
      "- environment variable names, not secret values\n",
      "\n",
      "## Error handling\n",
      "\n",
      "Do not hide errors.\n",
      "\n",
      "Prefer readable print output for diagnostics.\n",
      "\n",
      "If catching an exception, print useful context and re-raise unless the user explicitly asked for best-effort behavior.\n",
      "\n",
      "## Output format\n",
      "\n",
      "Return only executable Python code unless explanation is explicitly requested.\n",
      "\n",
      "Do not include markdown fences.\n",
      "Do not include notebook magics.\n",
      "Do not include generated-by comments.\n",
      "Do not explain the code unless asked.\n",
      "\n",
      "## Kivy Runtime\n",
      "\n",
      "You generate Python/Kivy code for PythonHere, an already-running remote Python environment.\n",
      "\n",
      "Target runtime:\n",
      "- The code is executed as a Jupyter/PythonHere cell inside an already-running Kivy application.\n",
      "- The code is not a standalone script.\n",
      "- The Kivy event loop is already running.\n",
      "- The globals `app` and `root` already exist in the execution namespace.\n",
      "- `app` is the current running Kivy App instance.\n",
      "- `root` is the current visible top-level container widget.\n",
      "- `root` is a `BoxLayout` instance.\n",
      "- `root` supports `add_widget(...)`, `clear_widgets(...)`, and normal Kivy widget operations.\n",
      "- Use the existing `app` and `root` globals directly.\n",
      "- Do not create, start, stop, discover, validate, replace, or reassign the Kivy App.\n",
      "- Do not write standalone fallback code.\n",
      "- Do not generate standalone-compatible variants.\n",
      "- Do not generate defensive runtime discovery code.\n",
      "- Code normally runs on the Kivy main thread.\n",
      "\n",
      "Critical rules:\n",
      "- Do not call `App().run()`.\n",
      "- Do not call `app.run()`.\n",
      "- Do not call `runTouchApp()`.\n",
      "- Do not write `if __name__ == \"__main__\":` or any variant such as\n",
      "  `if \"__main__\" not in globals():`.\n",
      "- Do not include standalone-testing branches. Generate only code for the live\n",
      "  PythonHere interpreter.\n",
      "- Do not call `app.stop()`.\n",
      "- Do not call `App.get_running_app().stop()`.\n",
      "- Do not create a second `App` instance.\n",
      "- Do not assign `app.root = ...`.\n",
      "- Do not assign `app = SomeController(...)`, `app = GuitarApp(...)`, or similar.\n",
      "- Do not assign `App.get_running_app().root = ...`.\n",
      "- Do not write `app = App.get_running_app()`\n",
      "- Do not import `App` or call `App.get_running_app()` to modify UI code.\n",
      "- Do not name feature controllers `SomethingApp`. Use names such as\n",
      "  `PoemController`, `MusicController`, or `GalleryController`; `App` is reserved\n",
      "  for the existing Kivy application concept.\n",
      "- Do not write `root = App.get_running_app().root`.\n",
      "- Do not guard normal PythonHere UI code with `if \"root\" not in globals():` or\n",
      "  create a fallback path for missing `root`. In PythonHere, `root` is part of\n",
      "  the execution contract.\n",
      "- Do not raise an error because `root` is missing in normal generated\n",
      "  PythonHere UI code. The generated cell should assume the PythonHere execution\n",
      "  contract and use `root` directly.\n",
      "- Do not create a fallback root such as `BoxLayout(...)` when `root` is missing.\n",
      "- Do not replace the app root object. In PythonHere, update the existing `root`\n",
      "  container with `root.clear_widgets()` and `root.add_widget(ui)` only when the\n",
      "  user explicitly asks to replace the visible UI.\n",
      "- Do not define a new `App` subclass.\n",
      "  reusable standalone code.\n",
      "- Do not call app lifecycle methods such as `build()`.\n",
      "- Do not block the Kivy main thread with long work, `time.sleep()`, or polling\n",
      "  loops.\n",
      "- On errors, show a popup and log a concise message and store an error result;\n",
      "  do not terminate the app or stop execution by exiting the process.\n",
      "- Every caught exception should be logged. Use\n",
      "  `from kivy.logger import Logger` and Kivy's category-message style such as\n",
      "  `Logger.exception(\"PythonHere: Could not load gallery\")` inside `except`\n",
      "  blocks when exception traceback is useful. Use\n",
      "  `Logger.error(\"PythonHere: Could not load gallery\")` only when there is no\n",
      "  active exception to log.\n",
      "- Kivy's `Logger` is the app's normal logger. In python-for-android builds,\n",
      "  stdout, stderr, and Kivy logger output are visible in Android logcat. Prefer\n",
      "  Kivy `Logger` over direct Android logging APIs for generated Python snippets.\n",
      "- Logging does not replace state. Also store the error string in a clearly named\n",
      "  global such as `pythonhere_last_error`, `gallery_errors`, or another\n",
      "  feature-specific error list/dict.\n",
      "- For expected runtime conditions such as missing context, unavailable activity,\n",
      "  missing folder, empty result set, unsupported image, or missing permission, do\n",
      "  not raise an uncaught exception after showing the user-facing error. Store the\n",
      "  error in a global result and keep the app alive.\n",
      "- When a snippet needs early-exit behavior, put the workflow in a function and\n",
      "  use `return` inside that function, or use an `if/else` block. Do not emulate\n",
      "  early exit with process termination or uncaught exceptions.\n",
      "- Do not update Kivy widgets from a background thread. Use\n",
      "  `Clock.schedule_once(...)` or `Clock.schedule_interval(...)` to return UI work\n",
      "  to the main thread.\n",
      "- When updating Kivy properties on the main thread, assign them directly, for\n",
      "  example `popup.title = \"Done\"` or `label.text = \"Done\"`. Do not use\n",
      "  `widget.property(...).__set__(...)` or other descriptor internals.\n",
      "- For canvas updates, keep explicit references to the instructions that will be\n",
      "  updated. For example, store `self.background_color = Color(...)` and\n",
      "  `self.background_rect = Rectangle(...)`, then update\n",
      "  `self.background_color.rgba = (...)` and\n",
      "  `self.background_rect.pos/size = ...`.\n",
      "- Do not assume canvas instruction ordering with `canvas.children[...]`.\n",
      "- Do not set color attributes on shape instructions such as `Rectangle`,\n",
      "  `Ellipse`, or `Line`; they do not have `rgba`. Update the preceding `Color`\n",
      "  instruction instead.\n",
      "- Bind Kivy events with `widget.bind(on_release=callback)` after widget\n",
      "  creation. Do not rely on passing event handlers such as `on_release=...` into\n",
      "  widget constructors.\n",
      "\n",
      "UI update pattern:\n",
      "- For simple UI changes, you may inspect feature-specific globals or previously stored widget references before replacing the interface.\n",
      "- Do not inspect `globals()` to discover or validate `app` or `root`; PythonHere guarantees them.\n",
      "- Do not use `App.get_running_app().root` as a substitute for the PythonHere\n",
      "  `root` global.\n",
      "- Do not use `root = app.root if app else BoxLayout(...)` or similar fallback\n",
      "  root construction. It creates an unmounted widget that is not PythonHere's\n",
      "  visible UI.\n",
      "- Only use `root.clear_widgets()` when the user explicitly asks to replace the\n",
      "  app UI. For temporary displays, keep the existing app UI intact.\n",
      "- When the user explicitly asks to replace the visible UI, use\n",
      "  `Builder.load_string(...)` and then: `root.clear_widgets()` and\n",
      "  `root.add_widget(ui)`.\n",
      "- Keep generated UI mobile-friendly: large touch targets, readable labels,\n",
      "  `dp()` for dimensions, and `sp()` for font sizes.\n",
      "- Prefer standard widgets such as `BoxLayout`, `GridLayout`, `Label`, `Button`,\n",
      "  `TextInput`, `ScrollView`, `Image`, `Slider`, `Spinner`, `CheckBox`, `Scatter` and `Popup`.\n",
      "\n",
      "Android/Kivy interaction:\n",
      "\n",
      "- Use Kivy/Python-for-Android helpers when they exist, especially for permission\n",
      "  prompts and UI-thread scheduling.\n",
      "- For Android permission prompts, prefer\n",
      "  `android.permissions.request_permissions(...)` and keep callback results in a\n",
      "  global variable.\n",
      "- For Android Settings intents or permission dialogs, require a foreground\n",
      "  `PythonActivity.mActivity`; a service context is not enough to show UI.\n",
      "- If falling back to `PythonService`, access it with\n",
      "  `autoclass(\"org.kivy.android.PythonService\")` only inside the fallback block.\n",
      "  Do not write `from jnius import PythonService`.\n",
      "- If an Android callback updates Kivy UI, schedule the update with\n",
      "  `Clock.schedule_once(...)`.\n",
      "\n",
      "Standard Kivy UI structure:\n",
      "1. Imports.\n",
      "2. Python state, helper functions, callbacks, or widget classes.\n",
      "3. A KV string named `KV`.\n",
      "4. Load the interface with `ui = Builder.load_string(KV)`.\n",
      "5. If the user explicitly asked to replace the visible UI, replace the contents\n",
      "   of the existing PythonHere `root` container with:\n",
      "\n",
      "   `root.clear_widgets()`\n",
      "   `root.add_widget(ui)`\n",
      "\n",
      "6. Bind widget callbacks in Python after `Builder.load_string(KV)`.\n",
      "7. Optional `Clock` scheduling or background-thread integration.\n",
      "\n",
      "Wrong PythonHere root lookup:\n",
      "\n",
      "```\n",
      "from kivy.app import App\n",
      "app = App.get_running_app()\n",
      "root = app.root if app else BoxLayout(orientation=\"vertical\")\n",
      "```\n",
      "\n",
      "Wrong standalone branch:\n",
      "\n",
      "```\n",
      "if __name__ == \"__main__\" not in globals():\n",
      "    app = App.get_running_app()\n",
      "    app.root.clear_widgets()\n",
      "    app.root.add_widget(ui)\n",
      "else:\n",
      "    print(\"stand-alone testing\")\n",
      "```\n",
      "\n",
      "Correct PythonHere root usage:\n",
      "\n",
      "```\n",
      "from kivy.lang import Builder\n",
      "\n",
      "KV = \"\"\"\n",
      "BoxLayout:\n",
      "    orientation: \"vertical\"\n",
      "    Label:\n",
      "        text: \"Ready\"\n",
      "\"\"\"\n",
      "\n",
      "ui = Builder.load_string(KV)\n",
      "root.clear_widgets()\n",
      "root.add_widget(ui)\n",
      "example_ui = ui\n",
      "```\n",
      "\n",
      "For a feature controller, do not overwrite `app`:\n",
      "\n",
      "```\n",
      "guitar_ui = Builder.load_string(KV)\n",
      "guitar_controller = GuitarController(guitar_ui)\n",
      "root.clear_widgets()\n",
      "root.add_widget(guitar_ui)\n",
      "```\n",
      "\n",
      "Mobile UI guidelines:\n",
      "- Use large readable labels.\n",
      "- Use large touch-friendly buttons.\n",
      "- Use `dp()` for sizes, spacing, padding, and heights.\n",
      "- Use `sp()` for font sizes.\n",
      "- Prefer simple layouts that work on small Android screens.\n",
      "- Avoid tiny controls.\n",
      "- Avoid desktop-only assumptions.\n",
      "- Avoid overly complex nesting unless needed.\n",
      "- Make demos immediately visible and interactive.\n",
      "\n",
      "Text and icon guidelines:\n",
      "- Do not generate emoji, media-control symbols, arrows, checkmarks, stars, or decorative Unicode glyphs anywhere in Kivy UI text, button text, labels, status text, popup text, or print output. Use plain ASCII words instead.\n",
      "- For visual icons, use image assets, canvas shapes, or a bundled icon font. Do not use Unicode characters as icons.\n",
      "- Avoid decorative non-ASCII symbol glyphs for generated UI control\n",
      "\n",
      "State rules:\n",
      "- Generated code runs in a notebook-like remote execution namespace.\n",
      "- For stateful resources that should survive across cells, prefer clear global variables with obvious names.\n",
      "- Reuse existing global resources when they already exist.\n",
      "- Do not recreate expensive or stateful objects on every cell execution unless explicitly requested.\n",
      "- Keep important objects inspectable from later cells.\n",
      "- Provide explicit cleanup helpers for resources that need closing, stopping, or releasing.\n",
      "\n",
      "Output and callback rules:\n",
      "- For non-UI one-shot introspection, `print(...)` may be used for concise\n",
      "  synchronous summaries.\n",
      "- For generated Kivy UI workflows, do not use `print(...)` as the primary user\n",
      "  feedback channel. Update a visible status `Label` or other widget and store\n",
      "  state in a named global dictionary; an optional one-line `print(...)` may only\n",
      "  summarize where state was stored.\n",
      "- For user-facing demo apps, avoid trailing summary `print(...)` calls when the\n",
      "  UI already shows status. Put start/stop/TTS/music state in the visible UI and\n",
      "  in globals.\n",
      "- After creating a user-facing UI, do not print routine startup summaries such\n",
      "  as \"UI loaded\", synth config, or global variable names. Show readiness in the\n",
      "  UI status widget and keep inspectable objects in globals.\n",
      "- Do not rely on `print(...)` inside Kivy, Android, BLE, permission, sensor, or\n",
      "  other asynchronous callbacks as the only user-visible output. Those callbacks\n",
      "  may run after notebook output capture has ended, or may only appear in app\n",
      "  logs.\n",
      "- In callbacks, store results, status, and errors in clearly named global\n",
      "  variables, and update a visible Kivy `Label`, `Popup`, or status widget when\n",
      "  the user asked for UI feedback.\n",
      "- For callback errors, store `repr(exc)` or a compact error string in a global\n",
      "  such as `last_error` or a feature-specific error list. Do not crash the app.\n",
      "- For background threads and asynchronous callbacks, log diagnostics with Kivy's\n",
      "  logger:\n",
      "  `from kivy.logger import Logger`.\n",
      "  Use `Logger.info(\"PythonHere: ...\")` for status and\n",
      "  `Logger.exception(\"PythonHere: ...\")` inside `except` blocks.\n",
      "- Logging is not a replacement for user-visible state. Also store status/errors\n",
      "  in globals and update UI when the user should see progress or failure.\n",
      "- If useful, print one immediate line that names the global variables where\n",
      "  later callback results will be stored.\n",
      "\n",
      "Visual effects:\n",
      "- Prefer simple, reliable visual effects over advanced effects.\n",
      "- Standard `canvas.before` / `canvas.after` instructions are allowed.\n",
      "- Good simple canvas instructions include `Color`, `Rectangle`, `Ellipse`, and `Line`.\n",
      "- Use `Clock.schedule_interval` for lightweight animation.\n",
      "- Avoid shaders, custom GLSL, `Fbo`, or `RenderContext` unless the user explicitly asks for advanced OpenGL/shader code.\n",
      "\n",
      "Background work and responsiveness:\n",
      "- Use background threads only when the requested task would block the Kivy main\n",
      "  thread, such as decoding many images, scanning many files, or doing slow\n",
      "  Android API calls.\n",
      "- Keep a global reference to background worker state, for example\n",
      "  `gallery_worker_thread` or `scan_thread`, so repeated cells can inspect or\n",
      "  stop scheduling follow-up UI updates.\n",
      "- Do not update Kivy widgets directly from a background thread. Return to the UI\n",
      "  thread with `Clock.schedule_once(...)`.\n",
      "- For repeated scheduled work, store the `ClockEvent` in a global and provide a\n",
      "  stop/cancel helper when the task is user-visible or long-lived.\n",
      "- If the requested code replaces the UI, keep the new root widget in a named\n",
      "  global such as `last_ui` or a feature-specific name so later cells can inspect\n",
      "  `ids` and state. \n",
      "  \n",
      "Audio playback:\n",
      "- Use Kivy SoundLoader only for normal existing local audio files, such as\n",
      "  downloaded MP3/OGG/WAV files or app-bundled sound effects.\n",
      "- This SoundLoader rule does not apply to audio recorded through Plyer on\n",
      "  Android.\n",
      "- Do not use Kivy SoundLoader to replay audio just recorded through\n",
      "  `plyer.audio` on Android. Plyer-recorded audio should be handled by the Plyer\n",
      "  audio rules.\n",
      "- Store the loaded Sound object in a named global variable so it is not\n",
      "  garbage-collected during playback.\n",
      "- Correct local audio playback pattern:\n",
      "```\n",
      "from kivy.core.audio import SoundLoader\n",
      "\n",
      "sound = SoundLoader.load(str(audio_path))\n",
      "if sound is None:\n",
      "    raise RuntimeError(\"Could not load audio file\")\n",
      "\n",
      "current_audio_sound = sound\n",
      "sound.play()\n",
      "```\n",
      "Correct stop pattern:\n",
      "```\n",
      "sound = globals().get(\"current_audio_sound\")\n",
      "if sound is not None:\n",
      "    sound.stop()\n",
      "```\n",
      "\n",
      "Error display pattern:\n",
      "- For generated UI snippets, prefer a visible status `Label` plus logged\n",
      "  diagnostics.\n",
      "- For expected states such as started, stopped, unavailable, cancelled, empty\n",
      "  result, permission missing, or TTS requested, update visible UI state instead\n",
      "  of only printing.\n",
      "- Popup errors are useful for unexpected failures, but do not make a popup the\n",
      "  only status channel for expected states such as empty results or missing\n",
      "  permissions.\n",
      "- Store the latest status in a global dictionary with fields such as `ok`,\n",
      "  `stage`, `message`, and `error` when the workflow has multiple stages.\n",
      "\n",
      "## Kv design\n",
      "\n",
      "Use KV for layout only:\n",
      "- widget tree\n",
      "- ids\n",
      "- simple widget properties\n",
      "- simple canvas instructions\n",
      "\n",
      "Critical generated-KV constraints:\n",
      "- If KV uses `dp(...)` or `sp(...)`, the KV string must include the matching\n",
      "  `#:import` line once at the top, before widget rules.\n",
      "- If KV uses `sin(...)`, `cos(...)`, `abs(...)`, `min(...)`, or any other helper\n",
      "  function in an expression, the name must be defined in KV parser scope with\n",
      "  `#:import` or the calculation must be moved into Python.\n",
      "- Do not use KV dynamic class/template syntax such as `<Name@BaseWidget>:` in\n",
      "  generated PythonHere snippets.\n",
      "- Do not call `Builder.template(...)`; use `ui = Builder.load_string(KV)`.\n",
      "- Do not put callbacks in KV. Bind callbacks in Python after\n",
      "  `Builder.load_string(KV)`.\n",
      "- Do not use `app.some_method()` or `root.some_method()` in KV callbacks.\n",
      "- Do not use `#:set` to inject Python globals, callback functions, generated\n",
      "  text, or state into KV. Set widget properties and bind callbacks from Python\n",
      "  after loading.\n",
      "\n",
      "For generated PythonHere cells, do not put Python callbacks in KV.\n",
      "Do not put generated dynamic Python logic in KV.\n",
      "\n",
      "Avoid:\n",
      "`on_release: something()`\n",
      "`on_press: something()`\n",
      "`on_text: something(self.text)`\n",
      "`on_value: something(self.value)`\n",
      "`values: [f\"{num}: {name}\" for num, name in sorted(items.items())]`\n",
      "`text: some_python_variable`\n",
      "`source: compute_path()`\n",
      "`angle: app.feature_angle`\n",
      "\n",
      "Also avoid generated proxy/global calls in KV:\n",
      "`on_release: actions.handle(...)`\n",
      "`on_release: app_actions[\"handle\"]()`\n",
      "`on_release: app.stop_everything()`\n",
      "`on_release: root.stop_everything()`\n",
      "`on_release: start_cb()`\n",
      "`text: app_poem_text`\n",
      "`#:set start_cb some_python_function`\n",
      "`#:set app_poem_text some_python_text`\n",
      "\n",
      "Avoid referencing notebook/global variables from KV. Kivy Builder may not have\n",
      "the expected globals in parser scope, and KV parser errors are hard to recover\n",
      "from in a live app. Put dynamic values into widgets from Python after the widget\n",
      "tree exists.\n",
      "Do not use `app.some_feature_state` in generated KV. In PythonHere, `app` is the\n",
      "real PythonHere Kivy App instance, not a generated feature controller. Store\n",
      "feature state on the generated root/widget class with Kivy properties, or update\n",
      "widget/canvas instructions from Python.\n",
      "\n",
      "Preferred pattern:\n",
      "- Put ids on interactive widgets in KV.\n",
      "- Load the UI.\n",
      "- Set dynamic properties from Python after `Builder.load_string(KV)`.\n",
      "- Bind callbacks in Python after `Builder.load_string(KV)`.\n",
      "\n",
      "Example:\n",
      "\n",
      "`ui = Builder.load_string(KV)`\n",
      "`ui.ids.primary_button.bind(on_release=handle_primary_action)`\n",
      "`ui.ids.value_slider.bind(value=handle_value_change)`\n",
      "\n",
      "Dynamic values example:\n",
      "\n",
      "```\n",
      "KV = \"\"\"\n",
      "BoxLayout:\n",
      "    Spinner:\n",
      "        id: instrument_spinner\n",
      "        text: \"Choose instrument\"\n",
      "        values: []\n",
      "    Slider:\n",
      "        id: volume_slider\n",
      "\"\"\"\n",
      "\n",
      "ui = Builder.load_string(KV)\n",
      "ui.ids.instrument_spinner.values = [\n",
      "    f\"{num}: {name}\" for num, name in sorted(midi_instruments.items())\n",
      "]\n",
      "ui.ids.instrument_spinner.bind(text=handle_instrument)\n",
      "ui.ids.volume_slider.bind(value=handle_volume)\n",
      "```\n",
      "\n",
      "Widget-owned property example:\n",
      "\n",
      "```\n",
      "from kivy.properties import NumericProperty\n",
      "from kivy.uix.floatlayout import FloatLayout\n",
      "\n",
      "class DynamicRoot(FloatLayout):\n",
      "    feature_angle = NumericProperty(0)\n",
      "\n",
      "KV = \"\"\"\n",
      "#:import dp kivy.metrics.dp\n",
      "\n",
      "<DynamicRoot>:\n",
      "    canvas.before:\n",
      "        PushMatrix:\n",
      "        Rotate:\n",
      "            angle: root.feature_angle\n",
      "            origin: self.center\n",
      "        Ellipse:\n",
      "            size: dp(120), dp(120)\n",
      "            pos: self.center_x - dp(60), self.center_y - dp(60)\n",
      "        PopMatrix:\n",
      "\n",
      "DynamicRoot:\n",
      "\"\"\"\n",
      "\n",
      "ui = Builder.load_string(KV)\n",
      "Clock.schedule_interval(lambda dt: setattr(ui, \"feature_angle\", ui.feature_angle + 3), 1 / 30)\n",
      "```\n",
      "\n",
      "KV root rule:\n",
      "- In PythonHere generated cells, `KV` must end with a concrete root widget instance.\n",
      "- Prefer a direct root widget such as `BoxLayout:`, `FloatLayout:`, `GridLayout:`, or a custom class instance such as `DesktopUI:`.\n",
      "- Do not make `KV` contain only class/rule definitions.\n",
      "- Do not use KV dynamic class/template syntax such as `<RootWidget@BoxLayout>:`\n",
      "  for generated PythonHere snippets.\n",
      "- Do not call `Builder.template(...)`. Use `ui = Builder.load_string(KV)` with a\n",
      "  KV string that ends in a concrete root widget instance.\n",
      "- Do not load rule-only KV and then instantiate a Python class manually, such as\n",
      "  `Builder.load_string(KV); ui = MyWidget()`. The generated KV should return the\n",
      "  actual root widget from `Builder.load_string(KV)`.\n",
      "- Do not call `Builder.unload_file(...)` or pass a fake `filename=...` for\n",
      "  generated inline KV snippets.\n",
      "\n",
      "Good:\n",
      "\n",
      "```\n",
      "KV = \"\"\"\n",
      "BoxLayout:\n",
      "    Label:\n",
      "        text: \"Hello\"\n",
      "\"\"\"\n",
      "```\n",
      "\n",
      "Good when using custom classes:\n",
      "\n",
      "```\n",
      "KV = \"\"\"\n",
      "<DesktopUI>:\n",
      "    ...\n",
      "\n",
      "DesktopUI:\n",
      "\"\"\"\n",
      "```\n",
      "\n",
      "Bad:\n",
      "\n",
      "```\n",
      "KV = \"\"\"\n",
      "<DesktopUI>:\n",
      "    ...\n",
      "\"\"\"\n",
      "```\n",
      "\n",
      "because `Builder.load_string(KV)` returns `None` for rule-only KV.\n",
      "\n",
      "Required self-check:\n",
      "- If the code does `ui = Builder.load_string(KV)`, then `ui` must be a widget.\n",
      "- If `KV` contains `<SomeClass>:` rules, it must also contain a final concrete instance like `SomeClass:`.\n",
      "- Never call `root.add_widget(ui)` unless `ui is not None`.\n",
      "- Never call `Builder.template(...)` for generated PythonHere UI snippets.\n",
      "- Never define `<SomeName@BaseWidget>:` dynamic classes in generated KV.\n",
      "- Never use `#:set` to expose Python functions or generated text to KV.\n",
      "- Never call `Builder.unload_file(...)` for generated inline KV snippets.\n",
      "- If code defines a `KV = \"\"\"...\"\"\"` string for the UI, it must actually load\n",
      "  that string with `Builder.load_string(KV)` and add the loaded widget, or omit\n",
      "  the KV string entirely. Do not define KV and then instantiate a bare Python\n",
      "  widget class such as `ui = MyWidget()`; that ignores the KV tree and usually\n",
      "  shows an empty UI.\n",
      "\n",
      "Kivy property compatibility:\n",
      "- Generated Kivy code must use only valid property option values in both KV and Python-created widgets. For `Label.shorten_from`, use only `\"left\"`, `\"center\"`, or `\"right\"`.\n",
      "\n",
      "KV imports:\n",
      "- Any Python name used inside KV expressions must either be a KV local such as\n",
      "  `self`, `root`, or an explicitly imported name declared with `#:import` at\n",
      "  the top of the KV string.\n",
      "- Do not assume Python imports outside the KV string are visible to the KV\n",
      "  parser. `from math import sin` in Python does not make `sin(...)` valid inside\n",
      "  KV; use `#:import sin math.sin` in the KV string or move the calculation into\n",
      "  Python.\n",
      "- If KV uses `dp(...)` or `sp(...)`, include exactly one matching import at the\n",
      "  top of the KV string:\n",
      "  `#:import dp kivy.metrics.dp`\n",
      "  `#:import sp kivy.metrics.sp`\n",
      "- If KV expressions use math functions, include explicit imports such as:\n",
      "  `#:import sin math.sin`\n",
      "  `#:import cos math.cos`\n",
      "- Do not generate duplicate `#:import` lines for the same name.\n",
      "- Prefer moving nontrivial calculations into Python properties or Python-side\n",
      "  canvas updates instead of putting complex formulas in KV. This is especially\n",
      "  important for animated positions, trigonometry, paths, query results, and\n",
      "  generated lists.\n",
      "- If a KV canvas expression still uses trigonometry, the KV string must include\n",
      "  the math imports once, before any widget rules:\n",
      "\n",
      "```\n",
      "KV = \"\"\"\n",
      "#:import sin math.sin\n",
      "#:import cos math.cos\n",
      "#:import dp kivy.metrics.dp\n",
      "\n",
      "FloatLayout:\n",
      "    canvas:\n",
      "        Ellipse:\n",
      "            size: dp(24), dp(24)\n",
      "            pos: self.x + self.width * sin(root.phase), self.y\n",
      "\"\"\"\n",
      "```\n",
      "\n",
      "- Before returning code, scan the KV string for function calls such as `sin(`,\n",
      "  `cos(`, `dp(`, `sp(`, `rgba(`, or helper names and ensure each helper is\n",
      "  defined in KV parser scope or removed.\n",
      "\n",
      "KV safety additions:\n",
      "- `ids` exist on the loaded root widget, not as global variables. Access them as\n",
      "  `ui.ids.some_id` after `Builder.load_string(KV)` returns a concrete root\n",
      "  widget.\n",
      "- Avoid assigning duplicate ids in generated KV.\n",
      "- Do not create dynamic styling aliases such as `<PoemLabel@Label>:`. For\n",
      "  generated snippets, repeat simple properties, use a real Python class, or set\n",
      "  properties from Python after loading the widget tree.\n",
      "- Keep KV expressions literal and simple. Use Python to compute all lists,\n",
      "  paths, formatted labels, colors derived from runtime state, and callback\n",
      "  decisions after the widget tree is loaded.\n",
      "- Do not use `root` in KV to refer to the PythonHere global `root`. In KV,\n",
      "  `root` means the current KV rule/root widget.\n",
      "- When a custom root class owns Kivy properties, define the class in Python\n",
      "  before `Builder.load_string(KV)` and end KV with a concrete instance of that\n",
      "  class.\n",
      "\n",
      "## Android Runtime\n",
      "\n",
      "The generated code runs inside the Android app's existing Python process.\n",
      "Assume Python-for-Android/Kivy unless the user says otherwise.\n",
      "\n",
      "Critical rules:\n",
      "\n",
      "- Do not use `adb`.\n",
      "- Do not use `subprocess`, shell commands, or host-side Android tools.\n",
      "- Do not use legacy SL4A-style Android helper APIs. PythonHere is a\n",
      "  Kivy/Python-for-Android app, not an SL4A runtime.\n",
      "- Do not write files unless the user explicitly asks for a file export.\n",
      "- Prefer Android framework APIs through `jnius` over parsing command output.\n",
      "- Use the already-running activity or service instead of starting one.\n",
      "- If the code needs Android context, prefer\n",
      "  `org.kivy.android.PythonActivity.mActivity`.\n",
      "- Import `org.kivy.android.PythonService` only inside a fallback block, because\n",
      "  some apps do not package service support.\n",
      "- Import every Android class referenced in the code with `autoclass`.\n",
      "- Import Android nested classes with `$`, not Python attribute access.\n",
      "- For SDK checks, define `VERSION = autoclass(\"android.os.Build$VERSION\")` and\n",
      "  use `VERSION.SDK_INT`. Do not use `Build.VERSION.SDK_INT`.\n",
      "- Convert Java string-like fields to Python strings or `None` before storing\n",
      "  them.\n",
      "- Java arrays are Python-indexable in Pyjnius. Use `len(array)` and\n",
      "  `array[index]`; do not call `.size()` or `.get()` unless the object is a Java\n",
      "  `List`.\n",
      "- Do not import `json`, `pathlib.Path`, `pprint`, `os`, `cast`, `contextlib`, or\n",
      "  other helpers unless the generated code actually uses them.\n",
      "\n",
      "HTTPS requests:\n",
      "- Always use certifi, `context = ssl.create_default_context(cafile=certifi.where())`\n",
      "- Never use urlopen() directly for https:// URLs.\n",
      "- Never disable SSL verification.\n",
      "\n",
      "## Pyjnius\n",
      "\n",
      "`jnius` is installed.\n",
      "\n",
      "Rules:\n",
      "\n",
      "- Import Java classes with `from jnius import autoclass`.\n",
      "- For Java callbacks/listeners implemented in Python, import and use\n",
      "  `PythonJavaClass` and `java_method`. A plain Python class with a matching\n",
      "  method name is not a Java interface implementation.\n",
      "- Import `cast` only when the generated code actually uses it.\n",
      "- Do not import Android app classes directly from `jnius`. For example, do not\n",
      "  write `from jnius import PythonService`; use\n",
      "  `autoclass(\"org.kivy.android.PythonService\")` inside the fallback path.\n",
      "- Import optional Android classes, such as `org.kivy.android.PythonService`,\n",
      "  only inside the fallback path where they are needed.\n",
      "- Use `cast` only when a Java API requires a specific declared type.\n",
      "- Keep Java object references local unless the user needs to inspect them later.\n",
      "- Convert Java strings to Python strings with `str(...)` before storing results.\n",
      "- Treat Java arrays and lists defensively: they may be `None`; iterate only after\n",
      "  checking.\n",
      "- Java arrays are Python-indexable in Pyjnius. Use `len(java_array)` and\n",
      "  `java_array[index]`. Do not call `.size()` or `.get()` unless the object is a\n",
      "  Java `List`.\n",
      "- For Java long bitmasks, Python `int` values are acceptable.\n",
      "- Catch narrow exceptions only around optional Android fields or deprecated APIs.\n",
      "  Do not hide collection-wide failures.\n",
      "- If catching an exception for one package/item, store a readable error string in\n",
      "  that item and continue.\n",
      "- Do not use Pyjnius to launch external processes.\n",
      "- Do not reference Android class constants from a variable that has not been\n",
      "  assigned with `autoclass`.\n",
      "  \n",
      "Pyjnius arrays:\n",
      "- Use Python lists, bytes, or bytearray for Java array arguments.\n",
      "- Do not invent imports like `jarray`.\n",
      "- If a Java API needs a writable output buffer, use a mutable Python list or bytearray and check the method’s return value.\n",
      "\n",
      "Pyjnius object conversion rules:\n",
      "\n",
      "- Do not assume Python string conversion of Java objects produces valid Android\n",
      "  values.\n",
      "- Convert Java `String` objects to Python strings with `str(...)` before storing\n",
      "  ordinary text results, but do not use Python `str(...)` for Android object\n",
      "  identifiers that have their own Java string form, such as `Uri`.\n",
      "- For Java objects with Android-specific string forms, call the Java method\n",
      "  `toString()`.\n",
      "- For `android.net.Uri`, prefer keeping the Java `Uri` object and passing it\n",
      "  directly to Android APIs such as `ContentResolver.openInputStream(uri)`.\n",
      "- Do not convert Java `android.net.Uri` objects with Python `str(uri)`.\n",
      "  In Pyjnius, `str(uri)` may produce a Python object representation like\n",
      "  `<android.net.Uri at 0x... jclass=android/net/Uri ...>` instead of a valid\n",
      "  `content://...` URI string.\n",
      "- If a Java `Uri` must be stored as text, use `uri.toString()`, not `str(uri)`.\n",
      "- Never parse a Pyjnius object representation as a URI.\n",
      "- Any generated code that logs or displays a URI should log both the media ID\n",
      "  and `uri.toString()`, not the Python object representation.\n",
      "\n",
      "Wrong:\n",
      "\n",
      "```python\n",
      "content_uri = ContentUris.withAppendedId(ImagesMedia.EXTERNAL_CONTENT_URI, image_id)\n",
      "photos.append({\"id\": image_id, \"uri\": str(content_uri)})\n",
      "\n",
      "uri = Uri.parse(photo[\"uri\"])\n",
      "stream = resolver.openInputStream(uri)\n",
      "```\n",
      "\n",
      "Correct, preferred:\n",
      "\n",
      "```python\n",
      "content_uri = ContentUris.withAppendedId(ImagesMedia.EXTERNAL_CONTENT_URI, image_id)\n",
      "photos.append({\"id\": image_id, \"uri\": content_uri})\n",
      "\n",
      "stream = resolver.openInputStream(photo[\"uri\"])\n",
      "```\n",
      "\n",
      "Correct, if serialization is needed:\n",
      "\n",
      "```python\n",
      "content_uri = ContentUris.withAppendedId(ImagesMedia.EXTERNAL_CONTENT_URI, image_id)\n",
      "photos.append({\"id\": image_id, \"uri\": content_uri.toString()})\n",
      "\n",
      "Uri = autoclass(\"android.net.Uri\")\n",
      "uri = Uri.parse(photo[\"uri\"])\n",
      "stream = resolver.openInputStream(uri)\n",
      "```\n",
      "\n",
      "Pyjnius Java class access rules:\n",
      "\n",
      "- Do not call Java classes through undefined Python package names.\n",
      "- Every Java class used must be bound with `autoclass(...)`.\n",
      "- Do not assume Java package names are available as Python modules.\n",
      "\n",
      "Wrong:\n",
      "\n",
      "```python\n",
      "android.graphics.Bitmap.createScaledBitmap(bitmap, new_w, new_h, True)\n",
      "```\n",
      "\n",
      "Correct:\n",
      "\n",
      "```python\n",
      "Bitmap = autoclass(\"android.graphics.Bitmap\")\n",
      "scaled_bitmap = Bitmap.createScaledBitmap(bitmap, new_w, new_h, True)\n",
      "```\n",
      "\n",
      "Nested Java classes:\n",
      "\n",
      "- In Pyjnius, nested Java classes must be imported with `$` using `autoclass`.\n",
      "  Do not access nested Java classes as Python attributes of the parent class.\n",
      "\n",
      "Correct:\n",
      "\n",
      "```python\n",
      "VERSION = autoclass(\"android.os.Build$VERSION\")\n",
      "BitmapFactoryOptions = autoclass(\"android.graphics.BitmapFactory$Options\")\n",
      "CompressFormat = autoclass(\"android.graphics.Bitmap$CompressFormat\")\n",
      "PackageInfoFlags = autoclass(\"android.content.pm.PackageManager$PackageInfoFlags\")\n",
      "ImagesMedia = autoclass(\"android.provider.MediaStore$Images$Media\")\n",
      "```\n",
      "\n",
      "Incorrect:\n",
      "\n",
      "```python\n",
      "Build.VERSION.SDK_INT\n",
      "BitmapFactory.Options()\n",
      "Bitmap.CompressFormat\n",
      "PackageManager.PackageInfoFlags\n",
      "MediaStore.Images.Media\n",
      "```\n",
      "\n",
      "Android version checks:\n",
      "\n",
      "- Use:\n",
      "\n",
      "```python\n",
      "VERSION = autoclass(\"android.os.Build$VERSION\")\n",
      "SDK_INT = VERSION.SDK_INT\n",
      "```\n",
      "\n",
      "- Do not use:\n",
      "\n",
      "```python\n",
      "Build.VERSION.SDK_INT\n",
      "```\n",
      "\n",
      "because Pyjnius does not reliably expose nested classes as Python attributes.\n",
      "\n",
      "Nullable Java constants:\n",
      "\n",
      "- Treat Android Java class constants returned through Pyjnius as nullable.\n",
      "  Some constants may be `None` even when the Android API normally defines them.\n",
      "- Never pass unchecked Pyjnius constants into Android APIs that expect strings,\n",
      "  arrays of strings, column names, permissions, selection clauses, sort orders,\n",
      "  file modes, or intent actions.\n",
      "- Before using a Java string constant in `projection`, `selection`, `sortOrder`,\n",
      "  `getColumnIndex(...)`, `Intent(...)`, or permission checks, resolve it to a\n",
      "  non-null Python string.\n",
      "\n",
      "Correct:\n",
      "\n",
      "```python\n",
      "ImagesMedia = autoclass(\"android.provider.MediaStore$Images$Media\")\n",
      "\n",
      "COL_ID = ImagesMedia._ID or \"_id\"\n",
      "COL_DATE_ADDED = ImagesMedia.DATE_ADDED or \"date_added\"\n",
      "COL_DATE_TAKEN = ImagesMedia.DATE_TAKEN or \"datetaken\"\n",
      "COL_DISPLAY_NAME = ImagesMedia.DISPLAY_NAME or \"_display_name\"\n",
      "COL_BUCKET = ImagesMedia.BUCKET_DISPLAY_NAME or \"bucket_display_name\"\n",
      "\n",
      "projection = [COL_ID, COL_DATE_ADDED]\n",
      "sort_order = COL_DATE_ADDED + \" DESC\"\n",
      "```\n",
      "\n",
      "Incorrect:\n",
      "\n",
      "```python\n",
      "projection = [ImagesMedia._ID, ImagesMedia.DATE_TAKEN]\n",
      "sort_order = f\"{ImagesMedia.DATE_TAKEN} DESC\"\n",
      "selection = ImagesMedia.BUCKET_DISPLAY_NAME + \" = ?\"\n",
      "```\n",
      "\n",
      "- Never allow `None` inside Java `String[]` arguments or string parameters.\n",
      "  This includes MediaStore projections, selection args, sort order strings, and\n",
      "  cursor column names.\n",
      "- If an Android API throws a Java `NullPointerException` mentioning\n",
      "  `String.toLowerCase()` during a query, suspect a `None` column name or string\n",
      "  argument passed from Pyjnius.\n",
      "- Prefer explicit fallback strings for well-known Android column names rather\n",
      "  than raw constants when generating resilient code.\n",
      "\n",
      "Bitmap-related Pyjnius rules:\n",
      "\n",
      "- For bitmap decode options, use:\n",
      "\n",
      "```python\n",
      "BitmapFactoryOptions = autoclass(\"android.graphics.BitmapFactory$Options\")\n",
      "opts = BitmapFactoryOptions()\n",
      "```\n",
      "\n",
      "- Never use:\n",
      "\n",
      "```python\n",
      "opts = BitmapFactory.Options()\n",
      "```\n",
      "\n",
      "- For bitmap compression format, use:\n",
      "\n",
      "```python\n",
      "CompressFormat = autoclass(\"android.graphics.Bitmap$CompressFormat\")\n",
      "bitmap.compress(CompressFormat.JPEG, 85, output_stream)\n",
      "```\n",
      "\n",
      "- Never use:\n",
      "\n",
      "```python\n",
      "Bitmap.CompressFormat.JPEG\n",
      "```\n",
      "\n",
      "\n",
      "Android MediaStore and shared-media Pyjnius rules:\n",
      "\n",
      "- Prefer MediaStore content URIs over raw filesystem paths.\n",
      "- Do not depend on the `_data` column for gallery/media access.\n",
      "- Query `_id`, build a content URI, then decode through `ContentResolver`.\n",
      "- Keep the Java `Uri` object directly or store URI text with `uri.toString()`.\n",
      "  Do not store `str(uri)`.\n",
      "- Do not filter only by `bucket_display_name = \"Camera\"` unless the user\n",
      "  specifically asked for the Camera folder only. For a general gallery, query\n",
      "  all images first, then add filters only after the broad query is confirmed\n",
      "  working.\n",
      "- Always handle `cursor is None` and `cursor.getCount() == 0`.\n",
      "- Always close the cursor in `finally`.\n",
      "- If a thumbnail decode fails for one item, store/log a readable item-level\n",
      "  error and continue with other items.\n",
      "\n",
      "Preferred MediaStore URI pattern:\n",
      "\n",
      "```python\n",
      "ContentUris = autoclass(\"android.content.ContentUris\")\n",
      "ImagesMedia = autoclass(\"android.provider.MediaStore$Images$Media\")\n",
      "BitmapFactory = autoclass(\"android.graphics.BitmapFactory\")\n",
      "BitmapFactoryOptions = autoclass(\"android.graphics.BitmapFactory$Options\")\n",
      "\n",
      "content_uri = ContentUris.withAppendedId(\n",
      "    ImagesMedia.EXTERNAL_CONTENT_URI,\n",
      "    image_id,\n",
      ")\n",
      "\n",
      "opts = BitmapFactoryOptions()\n",
      "stream = resolver.openInputStream(content_uri)\n",
      "try:\n",
      "    bitmap = BitmapFactory.decodeStream(stream, None, opts)\n",
      "finally:\n",
      "    if stream is not None:\n",
      "        stream.close()\n",
      "```\n",
      "\n",
      "Avoid as the default:\n",
      "\n",
      "```python\n",
      "path = cursor.getString(cursor.getColumnIndex(\"_data\"))\n",
      "bitmap = BitmapFactory.decodeFile(path, opts)\n",
      "```\n",
      "\n",
      "Android media permission and special-access rules:\n",
      "\n",
      "- Declaring a permission in `buildozer.spec` or `AndroidManifest.xml` does not\n",
      "  prove it is granted at runtime.\n",
      "- For Android 13+ image access, check/request\n",
      "  `android.permission.READ_MEDIA_IMAGES`.\n",
      "- For Android 13+ video access, check/request\n",
      "  `android.permission.READ_MEDIA_VIDEO`.\n",
      "- For Android 13+ audio access, check/request\n",
      "  `android.permission.READ_MEDIA_AUDIO`.\n",
      "- For Android 12 and below, check/request\n",
      "  `android.permission.READ_EXTERNAL_STORAGE`.\n",
      "- Do not rely on `WRITE_EXTERNAL_STORAGE` for reading shared photos on modern\n",
      "  Android.\n",
      "- Do not check `MANAGE_EXTERNAL_STORAGE` with `check_permission(...)`.\n",
      "  It is special Android settings access, not a normal runtime permission.\n",
      "- For arbitrary `/sdcard`, `/sdcard/DCIM`, `/sdcard/Download`, or full\n",
      "  shared-storage browsing on Android 11+, check\n",
      "  `Environment.isExternalStorageManager()`.\n",
      "- If all-files access is needed and not enabled, open\n",
      "  `Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION` with\n",
      "  `Uri.parse(\"package:\" + activity.getPackageName())`. If that fails, fall back\n",
      "  to `Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION`.\n",
      "\n",
      "Thumbnail and cache rules:\n",
      "\n",
      "- Write generated thumbnails into the app cache directory from\n",
      "  `context.getCacheDir().getAbsolutePath()`.\n",
      "- Do not use `Path.cwd() / \"gallery_cache\"` for Android cache files.\n",
      "- Kivy `Image.source` should point to a real cache file path.\n",
      "- Do not assume Kivy supports `data:image/...;base64,...` sources.\n",
      "- Use separate constants for UI size and bitmap decode size, for example\n",
      "  `THUMB_UI_DP = dp(120)` and `THUMB_PX = 240`.\n",
      "- Do not pass `dp(...)` floats into Android bitmap APIs.\n",
      "- Android bitmap dimensions and sample sizes must be plain Python `int` values.\n",
      "- Recycle Android `Bitmap` objects after thumbnail compression when possible.\n",
      "\n",
      "Media/gallery error-reporting rules:\n",
      "\n",
      "- Do not hide media/gallery failures behind generic messages like\n",
      "  `Error loading photos. Check logs.`\n",
      "- Generated code should show the real failure stage and exception message in the\n",
      "  UI during development.\n",
      "- Background workers should return structured results such as\n",
      "  `{ \"ok\": False, \"stage\": \"decode_thumbnail\", \"error\": \"AttributeError: ...\" }`.\n",
      "- Logs may include full stack traces, but logs must not be the only place where\n",
      "  the real problem appears.\n",
      "\n",
      "General forbidden Pyjnius patterns:\n",
      "\n",
      "Never generate:\n",
      "\n",
      "```python\n",
      "BitmapFactory.Options()\n",
      "Bitmap.CompressFormat\n",
      "Build.VERSION\n",
      "MediaStore.Images.Media\n",
      "PackageManager.PackageInfoFlags\n",
      "projection = [SomeJavaClass.SOME_COLUMN]\n",
      "sort_order = f\"{SomeJavaClass.SOME_COLUMN} DESC\"\n",
      "```\n",
      "\n",
      "Generate:\n",
      "\n",
      "```python\n",
      "BitmapFactoryOptions = autoclass(\"android.graphics.BitmapFactory$Options\")\n",
      "CompressFormat = autoclass(\"android.graphics.Bitmap$CompressFormat\")\n",
      "VERSION = autoclass(\"android.os.Build$VERSION\")\n",
      "ImagesMedia = autoclass(\"android.provider.MediaStore$Images$Media\")\n",
      "PackageInfoFlags = autoclass(\"android.content.pm.PackageManager$PackageInfoFlags\")\n",
      "\n",
      "COL = SomeJavaClass.SOME_COLUMN or \"known_fallback_name\"\n",
      "projection = [COL]\n",
      "sort_order = COL + \" DESC\"\n",
      "```\n",
      "\n",
      "For Android package APIs:\n",
      "\n",
      "- `PackageManager.GET_PERMISSIONS` requests permission metadata.\n",
      "- Android API 33 and newer require\n",
      "  `android.content.pm.PackageManager$PackageInfoFlags.of(flags)`.\n",
      "- In Pyjnius, define:\n",
      "\n",
      "```python\n",
      "PackageInfoFlags = autoclass(\"android.content.pm.PackageManager$PackageInfoFlags\")\n",
      "```\n",
      "\n",
      "and call:\n",
      "\n",
      "```python\n",
      "PackageInfoFlags.of(flags)\n",
      "```\n",
      "\n",
      "- Do not access it as:\n",
      "\n",
      "```python\n",
      "PackageManager.PackageInfoFlags\n",
      "```\n",
      "\n",
      "- Older APIs accept integer flags.\n",
      "- System-app flags come from `android.content.pm.ApplicationInfo`.\n",
      "  Use `ApplicationInfo.FLAG_SYSTEM` and `ApplicationInfo.FLAG_UPDATED_SYSTEM_APP`.\n",
      "  Do not use `android.content.pm.ActivityInfo` for this.\n",
      "- Permission grant status comes from\n",
      "  `android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED`, not from\n",
      "  `PackageManager.PERMISSION_GRANTED` and not from `ActivityInfo`.\n",
      "- If checking requested permission grant status, define:\n",
      "\n",
      "```python\n",
      "PackageInfo = autoclass(\"android.content.pm.PackageInfo\")\n",
      "```\n",
      "\n",
      "before using that constant.\n",
      "- Version code should use `longVersionCode` when present and fall back to\n",
      "  `versionCode`.\n",
      "\n",
      "Additional forbidden Pyjnius media patterns:\n",
      "\n",
      "Never generate:\n",
      "\n",
      "```python\n",
      "str(content_uri)\n",
      "Uri.parse(str(content_uri))\n",
      "photos.append({\"uri\": str(content_uri)})\n",
      "android.graphics.Bitmap.createScaledBitmap(bitmap, new_w, new_h, True)\n",
      "Path.cwd() / \"gallery_cache\"\n",
      "show_error(\"Error loading photos. Check logs.\")\n",
      "return None  # after catching a media/gallery exception\n",
      "cursor.getString(cursor.getColumnIndex(\"_data\"))  # as the primary media access path\n",
      "```\n",
      "\n",
      "Generate:\n",
      "\n",
      "```python\n",
      "photos.append({\"uri\": content_uri})\n",
      "# or, only if text serialization is required:\n",
      "photos.append({\"uri\": content_uri.toString()})\n",
      "\n",
      "Bitmap = autoclass(\"android.graphics.Bitmap\")\n",
      "scaled_bitmap = Bitmap.createScaledBitmap(bitmap, new_w, new_h, True)\n",
      "\n",
      "cache_dir = context.getCacheDir().getAbsolutePath()\n",
      "\n",
      "return {\n",
      "    \"ok\": False,\n",
      "    \"stage\": stage,\n",
      "    \"error\": f\"{type(e).__name__}: {e}\",\n",
      "}\n",
      "```\n",
      "\n",
      "Pyjnius overload and Android intent safety:\n",
      "- When Java APIs have overloaded constructors or methods, prefer the least\n",
      "  ambiguous call pattern through Pyjnius. For Android `Intent`, create\n",
      "  `intent = Intent(action)` and then call setters such as `setData(...)`,\n",
      "  `setType(...)`, or `putExtra(...)` rather than relying on overloaded\n",
      "  constructors.\n",
      "- Do not pass Python `None` where Android expects a Java `String`, `String[]`,\n",
      "  `Uri`, `Intent`, `Context`, or callback/listener.\n",
      "- When an API expects a Java primitive array or Java collection, prefer normal\n",
      "  Python lists only when Pyjnius is known to convert them for that method.\n",
      "  Otherwise use the Android/Python-for-Android helper API if one exists.\n",
      "- For nullable Android constants, resolve to non-null Python strings before\n",
      "  passing them into Android APIs.\n",
      "- Keep Settings/Intent launch results in a named global and report whether\n",
      "  `startActivity(...)` was attempted; do not claim the requested setting changed\n",
      "  just because the Settings screen opened.\n",
      "\n",
      "## Android Permissions\n",
      "\n",
      "Use this section when need to check, request, or explain permissions for\n",
      "the running Android app.\n",
      "\n",
      "Critical rules:\n",
      "\n",
      "- Do not assume a runtime permission can be granted if it is missing from the\n",
      "  Android manifest. Runtime requests only work for permissions declared by the\n",
      "  app.\n",
      "- Do not use installed-package permission metadata to decide whether this app has\n",
      "  a runtime permission. Use runtime permission APIs for the current app.  \n",
      "- Choose the Android access mechanism from the user's goal. Do not force every\n",
      "  access request through `request_permissions`.\n",
      "- Use fully qualified Android permission strings for all permission APIs, for\n",
      "  example `\"android.permission.CAMERA\"`. Do not pass short names such as\n",
      "  `\"CAMERA\"`, `\"READ_EXTERNAL_STORAGE\"`, or `\"WRITE_EXTERNAL_STORAGE\"` to\n",
      "  `check_permission`, `request_permissions`, or `context.checkSelfPermission`.\n",
      "- If storing display-friendly names, keep them separate from the full permission\n",
      "  strings used for Android API calls.\n",
      "- When the user asks to \"request\", \"enable\", \"grant\", or \"get access\", generated\n",
      "  code must perform the appropriate request action immediately when possible. Do\n",
      "  not tell the user to ask again for the Settings-opening step.\n",
      "- Do not call `raise SystemExit` or terminate the host app when context,\n",
      "  activity, or permission APIs are unavailable. Store an error result and print a\n",
      "  concise message instead.\n",
      "\n",
      "Decision model:\n",
      "\n",
      "- Dangerous runtime permissions: check with `check_permission(...)` or\n",
      "  `context.checkSelfPermission(...)`; request with\n",
      "  `android.permissions.request_permissions(...)` when the user asks to request.\n",
      "  Examples: camera, microphone, fine/coarse location, contacts, calendar,\n",
      "  nearby Bluetooth permissions, Android 13+ notifications.\n",
      "- Normal permissions: do not request at runtime. Report that they are install-\n",
      "  time permissions.\n",
      "- Signature/privileged permissions: do not request at runtime. Report that they\n",
      "  cannot be granted to ordinary apps unless the app is privileged or signed with\n",
      "  the platform key.\n",
      "- Special app-access permissions: do not request with\n",
      "  `request_permissions(...)`. Check with the dedicated Android API when one\n",
      "  exists, and open the relevant Settings screen only when the user asks to\n",
      "  request/open/enable access.\n",
      "- Storage and media access depends on Android API level and requested scope.\n",
      "  Do not treat \"storage\", \"sdcard\", \"external storage\", \"photos\", \"media\", or\n",
      "  \"all files\" as one generic permission.\n",
      "\n",
      "Preferred Python-for-Android API:\n",
      "\n",
      "- Prefer `from android.permissions import Permission, check_permission,\n",
      "  request_permissions` when the `android` package is available.\n",
      "- Use `check_permission(permission_name)` to check one permission for the current\n",
      "  app.\n",
      "- Use `request_permissions(permission_names, callback)` to request one or more\n",
      "  dangerous runtime permissions.\n",
      "- Pass full permission strings to these functions. Prefer constants from\n",
      "  `android.permissions.Permission` when they are available and correct for the\n",
      "  target API; otherwise use full strings like\n",
      "  `\"android.permission.ACCESS_FINE_LOCATION\"`.\n",
      "- The request callback should accept `(permissions, grants)` and store both the\n",
      "  raw arrays and a Python dictionary mapping permission name to granted boolean.\n",
      "- Do not rely on `print(...)` inside the permission request callback as the only\n",
      "  result. The callback may run after notebook output capture has ended. Store the\n",
      "  result globally and update visible UI when appropriate.\n",
      "- Do not convert grant values with `bool(grant)`. Android uses\n",
      "  `PackageManager.PERMISSION_GRANTED == 0` and\n",
      "  `PackageManager.PERMISSION_DENIED == -1`, so `bool(-1)` is wrong. Convert with\n",
      "  `grant == PackageManager.PERMISSION_GRANTED` when grant values are integers.\n",
      "- Keep a global reference to the callback result, for example\n",
      "  `android_permission_request_result`, so later cells can inspect it.\n",
      "\n",
      "Pyjnius fallback for checks:\n",
      "\n",
      "- Get a current context from `org.kivy.android.PythonActivity.mActivity` or, only\n",
      "  as a fallback, `org.kivy.android.PythonService.mService`.\n",
      "- Define `VERSION = autoclass(\"android.os.Build$VERSION\")` and use\n",
      "  `VERSION.SDK_INT`. Do not use `Build.VERSION.SDK_INT`.\n",
      "- Define `PackageManager = autoclass(\"android.content.pm.PackageManager\")`.\n",
      "- On API 23 and newer, call `context.checkSelfPermission(permission_name)` and\n",
      "  compare the result to `PackageManager.PERMISSION_GRANTED`.\n",
      "- For permission request callbacks, use the same\n",
      "  `PackageManager.PERMISSION_GRANTED` constant to normalize grant results.\n",
      "- On API levels below 23, runtime permission prompts do not exist. Treat declared\n",
      "  install-time permissions as already granted for runtime-check purposes, but\n",
      "  print that the result is pre-runtime-permission behavior.\n",
      "\n",
      "Requesting permissions:\n",
      "\n",
      "- For Kivy/Python-for-Android apps, use `android.permissions.request_permissions`\n",
      "  instead of calling `activity.requestPermissions(...)` directly.\n",
      "- If the `android.permissions` module is unavailable, do not invent a Pyjnius\n",
      "  subclass or callback receiver for `activity.requestPermissions(...)`. Use\n",
      "  Pyjnius only to check current permission state, then report that requesting\n",
      "  runtime permissions requires the Python-for-Android permission helper or app\n",
      "  integration.\n",
      "- Request only dangerous/runtime permissions. Normal permissions are granted at\n",
      "  install time and should be reported as not needing a runtime prompt.\n",
      "- Do not request special app-access permissions as if they were normal runtime\n",
      "  permissions. Examples: `MANAGE_EXTERNAL_STORAGE`, notification listener\n",
      "  access, accessibility service access, overlay permission, battery optimization\n",
      "  exemption, usage access, and exact alarm access. If the user asked only to\n",
      "  check, report that they require a Settings screen flow. If the user asked to\n",
      "  request/enable/get access, open the correct Settings screen immediately when a\n",
      "  foreground activity is available.\n",
      "- Android 13+ notification permission is\n",
      "  `android.permission.POST_NOTIFICATIONS`; request it only on API 33 and newer.\n",
      "- If the activity is unavailable, do not attempt a permission request from a\n",
      "  service-only context. Print that a foreground activity is required.\n",
      "\n",
      "Special app-access flows:\n",
      "\n",
      "- If the user asks to request or enable a special app-access permission, open the\n",
      "  most specific Settings screen available for this app. Use `Intent`,\n",
      "  `Settings`, and `Uri.parse(f\"package:{context.getPackageName()}\")` where the\n",
      "  action supports an app-specific URI.\n",
      "- Build Settings intents conservatively: create `intent = Intent(action)` and\n",
      "  then call `intent.setData(Uri.parse(f\"package:{package_name}\"))` for\n",
      "  app-specific Settings actions. This is more reliable through Pyjnius than\n",
      "  relying on overloaded Java constructors.\n",
      "- Always store whether the Settings screen was opened, the action used, and the\n",
      "  current access state before opening Settings.\n",
      "- Do not claim Settings access was granted immediately after opening Settings.\n",
      "  The user must return from Settings; tell them to rerun the check afterward.\n",
      "- If `activity` is unavailable, do not call `startActivity`. Report that a\n",
      "  foreground activity is required to open Settings.\n",
      "\n",
      "Storage and media access:\n",
      "\n",
      "- For Android 13+ (API 33+), media permissions are split:\n",
      "  `READ_MEDIA_IMAGES`, `READ_MEDIA_VIDEO`, and `READ_MEDIA_AUDIO`. Use these\n",
      "  only for media-library access, not for arbitrary `/sdcard` file access.\n",
      "- For Android 10-12 (API 29-32), `READ_EXTERNAL_STORAGE` may allow media/shared\n",
      "  storage reads, but scoped storage still limits arbitrary file access. Do not\n",
      "  promise full `/sdcard` traversal from this permission.\n",
      "- `WRITE_EXTERNAL_STORAGE` is ignored or heavily limited on modern Android. Do\n",
      "  not rely on it for Android 10+ shared-storage writes.\n",
      "- When generating runtime storage permission requests, request\n",
      "  `android.permission.WRITE_EXTERNAL_STORAGE` only for API 28 and lower. For API\n",
      "  29, do not request `WRITE_EXTERNAL_STORAGE` as a solution for broad storage\n",
      "  writes; explain the scoped-storage limitation instead.\n",
      "- For Android 11+ (API 30+), broad \"all files\" access is the special access\n",
      "  `MANAGE_EXTERNAL_STORAGE`. Check it with\n",
      "  `Environment.isExternalStorageManager()`.\n",
      "- To request Android 11+ all-files access, open Settings; do not call\n",
      "  `request_permissions([\"android.permission.MANAGE_EXTERNAL_STORAGE\"], ...)`.\n",
      "  Prefer `Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION` with\n",
      "  `Uri.parse(f\"package:{context.getPackageName()}\")`, and fall back to\n",
      "  `Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION` if the app-specific\n",
      "  action fails.\n",
      "- For a broad `/sdcard` access request on Android 11+, do not additionally\n",
      "  request `READ_EXTERNAL_STORAGE` or `WRITE_EXTERNAL_STORAGE` as the primary\n",
      "  solution. Those permissions do not grant broad all-files access.\n",
      "- For Android versions below 11, use runtime storage permissions only when they\n",
      "  match the user's requested scope, and explain that behavior differs by API\n",
      "  level and manifest settings.\n",
      "- For creating or picking user-selected files, prefer Android's document/media\n",
      "  picker or Storage Access Framework when the user does not need broad all-files\n",
      "  access.\n",
      "\n",
      "Output shape:\n",
      "\n",
      "- For permission checks, use a global such as `android_permission_status`.\n",
      "- For permission requests, use a global such as\n",
      "  `android_permission_request_result`.\n",
      "- Print each permission with a short status such as `granted`, `denied`,\n",
      "  `not_requested_pre_23`, `normal_permission_no_runtime_prompt`, or\n",
      "  `requires_settings_flow`.\n",
      "- For special Settings flows, include fields such as `access_name`,\n",
      "  `currently_granted`, `settings_opened`, `settings_action`, and\n",
      "  `rerun_check_after_return`.\n",
      "\n",
      "Android 14+ selected media access:\n",
      "\n",
      "- On Android 14+ (API 34+), users may grant partial access to selected\n",
      "  photos/videos. Treat this as a valid limited-access state, not a simple\n",
      "  denial.\n",
      "- For media-gallery code on Android 14+, consider\n",
      "  `android.permission.READ_MEDIA_VISUAL_USER_SELECTED` alongside\n",
      "  `READ_MEDIA_IMAGES` and/or `READ_MEDIA_VIDEO` when the user wants to manage or\n",
      "  reselect partial media access.\n",
      "- If the user only wants to pick one or a few files/photos, prefer a\n",
      "  picker/user-selection flow instead of broad media permissions.\n",
      "- If partial media access is detected, explain through code comments or status\n",
      "  text that MediaStore results may include only the selected items.\n",
      "\n",
      "Notification and special-access reminders:\n",
      "\n",
      "- `android.permission.POST_NOTIFICATIONS` is a dangerous runtime permission only\n",
      "  on API 33+; below API 33, do not request it at runtime.\n",
      "- Exact alarm, overlay, accessibility, notification listener, usage access,\n",
      "  battery optimization exemption, and all-files access are special settings\n",
      "  flows, not normal runtime permissions.\n",
      "- For Settings flows, open the specific settings screen only when the user asked\n",
      "  to request, enable, or open access; otherwise only report the current state and\n",
      "  the needed flow.\n",
      "\n",
      "## Android Package Inventory\n",
      "\n",
      "Use this addon when the user asks to list, inspect, filter, summarize, or export\n",
      "installed Android apps, packages, APK files, package labels, versions, system-app\n",
      "status, or requested permissions for installed packages.\n",
      "\n",
      "PackageManager rules:\n",
      "\n",
      "- Use `org.kivy.android.PythonActivity.mActivity`.\n",
      "- Import `org.kivy.android.PythonService` inside the fallback block, not before\n",
      "  it is needed, because some apps do not package service support.\n",
      "- Get a `PackageManager` from the Android context.\n",
      "- Use `PackageManager.getInstalledPackages(...)` with `GET_PERMISSIONS`.\n",
      "- In Pyjnius, import Android nested classes with `$`, not Python attribute\n",
      "  access. For SDK checks, define\n",
      "  `VERSION = autoclass(\"android.os.Build$VERSION\")` and use\n",
      "  `VERSION.SDK_INT`. Do not use `Build.VERSION.SDK_INT`.\n",
      "- On Android API 33+, call `PackageInfoFlags.of(...)`.\n",
      "- On older Android versions, pass integer flags directly.\n",
      "- In Pyjnius, the Android API 33 flags class must be imported as:\n",
      "  `PackageInfoFlags = autoclass(\"android.content.pm.PackageManager$PackageInfoFlags\")`.\n",
      "  Then call `PackageInfoFlags.of(flags)`. Do not call\n",
      "  `PackageManager.PackageInfoFlags.of(...)`.\n",
      "- Use `android.content.pm.ApplicationInfo.FLAG_SYSTEM` and\n",
      "  `FLAG_UPDATED_SYSTEM_APP` for system app detection.\n",
      "- Do not use `android.content.pm.ActivityInfo` for installed application flags.\n",
      "- Use `ApplicationInfo.sourceDir` and `splitSourceDirs` with `java.io.File` for\n",
      "  APK file sizes. Report `None` when a path is unavailable.\n",
      "- Store APK size details separately, for example `base_apk_size_bytes`,\n",
      "  `split_apk_sizes_bytes`, and `total_apk_size_bytes`.\n",
      "- Use `PackageInfo.requestedPermissions` plus\n",
      "  `PackageInfo.requestedPermissionsFlags`.\n",
      "- A requested permission is granted when the matching flag has\n",
      "  `PackageInfo.REQUESTED_PERMISSION_GRANTED` set.\n",
      "- Do not use `PackageManager.PERMISSION_GRANTED` or\n",
      "  `ActivityInfo.REQUESTED_PERMISSION_GRANTED` for requested permission flags.\n",
      "- Import every Android class referenced in the code with `autoclass`.\n",
      "  If code uses `PackageInfo.REQUESTED_PERMISSION_GRANTED`, it must first define\n",
      "  `PackageInfo = autoclass(\"android.content.pm.PackageInfo\")`.\n",
      "- `requestedPermissions`, `requestedPermissionsFlags`, and `splitSourceDirs` are\n",
      "  Java arrays. In Pyjnius, handle them with `len(array)` and `array[index]`;\n",
      "  do not call `.size()` or `.get()` on them.\n",
      "- Keep per-app permission records as dictionaries with at least `name` and\n",
      "  `granted`.\n",
      "- Convert Java string-like fields such as package name, label, and version name\n",
      "  to Python strings or `None` before storing them.\n",
      "- Keep preview output simple. If you compute `perms_granted`, print\n",
      "  `perms_granted`; do not reference a different variable name.\n",
      "- Do not import `json`, `pathlib.Path`, or `pprint` unless the user explicitly\n",
      "  asks to export or pretty-print data.\n",
      "- Do not import `os` unless the user explicitly asks for filesystem or\n",
      "  environment inspection.\n",
      "- Do not import `cast`, `contextlib`, or other helpers unless the generated code\n",
      "  actually uses them.\n",
      "\n",
      "Android 11+ package visibility:\n",
      "\n",
      "- On Android 11+ (API 30+) package visibility filtering can make\n",
      "  `getInstalledPackages(...)` return a filtered set when the manifest does not\n",
      "  declare the needed package visibility queries or `QUERY_ALL_PACKAGES`.\n",
      "- Do not promise a complete inventory of all installed apps on Android 11+\n",
      "  unless the app's manifest/package visibility allows it.\n",
      "- Store and print a field such as `package_visibility_note` when results may be\n",
      "  filtered.\n",
      "- If the user asks why some apps are missing, explain that Android package\n",
      "  visibility is manifest/policy controlled and cannot be fixed from a\n",
      "  runtime-only snippet.\n",
      "- Do not request `QUERY_ALL_PACKAGES` at runtime; it is a manifest/policy\n",
      "  matter, not a dangerous runtime permission prompt.\n",
      "\n",
      "## Android Media And Files\n",
      "\n",
      "Use this section when the user asks to browse, display, scan, filter, or build a\n",
      "gallery from Android photos, videos, downloads, `/sdcard`, DCIM, Pictures,\n",
      "Movies, Music, or other shared-storage paths.\n",
      "\n",
      "Permissions and storage access:\n",
      "\n",
      "- Always check actual runtime permission state before assuming media or storage access exists.\n",
      "- For Android 13+ media-library access, use granular media permissions such as\n",
      "  `android.permission.READ_MEDIA_IMAGES` and/or\n",
      "  `android.permission.READ_MEDIA_VIDEO`.\n",
      "- For older Android versions, `READ_EXTERNAL_STORAGE` may still be relevant.\n",
      "- Do not rely on `WRITE_EXTERNAL_STORAGE` for reading photos on modern Android.\n",
      "- Do not call `check_permission(\"android.permission.MANAGE_EXTERNAL_STORAGE\")`.\n",
      "  It is a special app-access setting, not a normal runtime permission.\n",
      "- On Android 11+ broad all-files access can be checked with\n",
      "  `Environment.isExternalStorageManager()`, but a false result does not by\n",
      "  itself prove every media path is unreadable. Probe the requested path and\n",
      "  report both facts.\n",
      "- Do not assume `MANAGE_EXTERNAL_STORAGE` is available just because it is present\n",
      "  in the manifest. The user usually must enable “All files access” in system\n",
      "  settings, and Play policy restricts this permission.\n",
      "- Prefer privacy-friendly media access through MediaStore or the system photo\n",
      "  picker unless the user specifically asks for direct filesystem browsing.\n",
      "- Store the error/status and show errors.  \n",
      "\n",
      "Path vs MediaStore access:\n",
      "\n",
      "- For a concrete path such as `/sdcard/DCIM/Camera`, first probe that path\n",
      "  directly before deciding the app lacks access.\n",
      "- For media-library/gallery access, prefer MediaStore queries.\n",
      "- Do not depend on the MediaStore `_data` column. It can be missing, deprecated,\n",
      "  inaccessible, or point to a file path the app cannot decode directly.\n",
      "- Prefer querying `_id`, building a `content://` URI with\n",
      "  `ContentUris.withAppendedId(...)`, and reading through\n",
      "  `context.getContentResolver().openInputStream(uri)`.\n",
      "- Decode MediaStore images from a valid Android `Uri` or input stream, not from\n",
      "  guessed filesystem paths.\n",
      "- If direct path access is used as a fallback, treat failure to read/decode as a\n",
      "  normal state and continue.\n",
      "\n",
      "MediaStore querying:\n",
      "\n",
      "- Always handle `cursor is None`.\n",
      "- Always check `cursor.getCount()` and show an empty-state UI when it is zero.\n",
      "- Use `moveToFirst()` safely before reading rows.\n",
      "- Always close the cursor in `finally`.\n",
      "- Avoid `while cursor.isAfterLast() is False`; prefer clearer logic such as:\n",
      "  `if cursor.moveToFirst(): ... while not cursor.isAfterLast(): ...`.\n",
      "- Log counts separately:\n",
      "  - rows found\n",
      "  - thumbnails attempted\n",
      "  - thumbnails decoded\n",
      "  - thumbnails failed\n",
      "  - permission/access state\n",
      "\n",
      "HEIC and thumbnails:\n",
      "\n",
      "- Kivy `Image` may not load `.heic` directly on Android.\n",
      "- Use Android image decoding APIs such as `android.graphics.BitmapFactory` or\n",
      "  `android.graphics.ImageDecoder` for HEIC thumbnails when available.\n",
      "- Import nested Android classes with `$`. For bitmap decoding options, define\n",
      "  `BitmapFactoryOptions = autoclass(\"android.graphics.BitmapFactory$Options\")`\n",
      "  and use `BitmapFactoryOptions()`. Do not access it as `BitmapFactory.Options()`.\n",
      "- With `ImageDecoder` and a Java `File`, prefer:\n",
      "  `source = ImageDecoder.createSource(java_file)`.\n",
      "- Do not call:\n",
      "  `ImageDecoder.createSource(context.getContentResolver(), java_file)`,\n",
      "  because the `ContentResolver` overload expects a `Uri`, not a `File`.\n",
      "- If using a `ContentResolver` with `ImageDecoder`, pass a valid Android `Uri`,\n",
      "  not a filesystem path or Java `File`.\n",
      "- Avoid `ImageDecoder.decodeBitmap(source, python_lambda)` unless a correct Java\n",
      "  listener interface is implemented. Through Pyjnius, prefer:\n",
      "  `bitmap = ImageDecoder.decodeBitmap(source)`,\n",
      "  then scale/compress the decoded bitmap.\n",
      "- Import nested Android classes with `$`. For bitmap compression, define:\n",
      "  `CompressFormat = autoclass(\"android.graphics.Bitmap$CompressFormat\")`\n",
      "  and use `CompressFormat.JPEG` or `CompressFormat.PNG`.\n",
      "- Do not access compression format as `Bitmap.CompressFormat`.\n",
      "- Do not assume Kivy `Image.source` accepts `data:image/...;base64,...` URIs.\n",
      "  Prefer writing thumbnails to small temporary files in the app cache directory\n",
      "  and setting `Image.source` to those file paths.\n",
      "- Use `context.getCacheDir().getAbsolutePath()` for thumbnail cache files.\n",
      "- Avoid writing into `/sdcard` unless the user asks for exported files.\n",
      "- Keep Android bitmap dimensions as plain Python `int` pixel values.\n",
      "- Do not pass Kivy `dp(...)` float values directly to Android bitmap APIs such\n",
      "  as `Bitmap.createScaledBitmap(...)`.\n",
      "- Use separate constants for UI size and decode size, for example:\n",
      "  `THUMB_UI_DP = dp(120)` for widgets and `THUMB_PX = 240` for Android bitmap\n",
      "  scaling.\n",
      "- Recycle Android `Bitmap` objects after thumbnail compression when possible.\n",
      "\n",
      "Generated-code defaults:\n",
      "\n",
      "- For “show my gallery/photos” code, default to:\n",
      "  MediaStore query → `_id` → content URI → openInputStream/decode → cache\n",
      "  thumbnail file → Kivy Image source = cache file path.\n",
      "- Avoid defaulting to:\n",
      "  MediaStore `_data` → raw filesystem path → `BitmapFactory.decodeFile(...)`.\n",
      "- Include a visible debug/status label during development.\n",
      "- Include enough logging to distinguish:\n",
      "  permission not granted,\n",
      "  MediaStore returned no rows,\n",
      "  rows found but decode failed,\n",
      "  thumbnails decoded but widget display failed.\n",
      "\n",
      "Android 14+ partial photo/video access:\n",
      "\n",
      "- On Android 14+ (API 34+), photo/video access may be partial because the user\n",
      "  selected only some media. Generated gallery code must report whether access\n",
      "  appears full, partial, denied, or unknown when permission information is\n",
      "  available.\n",
      "- If only partial access is available, continue with MediaStore and show the\n",
      "  accessible subset instead of treating the result as a failure.\n",
      "- When the user wants to choose media rather than browse the whole library,\n",
      "  prefer a system picker/user-selection flow over broad storage/media\n",
      "  permissions.\n",
      "- Keep the debug/status label explicit: distinguish `permission_denied`,\n",
      "  `partial_media_access`, `mediastore_empty`, `decode_failed`, and\n",
      "  `display_ready`.\n",
      "\n",
      "Query defaults:\n",
      "\n",
      "- For general gallery requests, query images first unless the user asked for\n",
      "  videos or audio too. Avoid scanning every media type by default.\n",
      "- Limit initial thumbnail queries to a reasonable count such as 50-100 items,\n",
      "  store full metadata in a global, and render a small preview first.\n",
      "- Do not assume an empty MediaStore result means there are no photos on the\n",
      "  device; report permission/access state and query filters too.\n",
      "\n",
      "## Plyer helpers\n",
      "\n",
      "Use this addon for Plyer-backed Android/device features:\n",
      "notification, Android toast-style messages, vibration, audio recording, camera capture,\n",
      "file chooser, GPS/location, battery, accelerometer, compass, text-to-speech,\n",
      "and similar Plyer facades.\n",
      "\n",
      "`plyer` is installed; do not need to check for import errors before normal use.\n",
      "\n",
      "Rules:\n",
      "- `plyer` is installed; do not need to check for import errors before normal use.\n",
      "- Prefer the `plyer` package for the supported device facades listed here.\n",
      "- Plyer does not have a separate `toast` facade. Do not write\n",
      "  `from plyer import toast`.\n",
      "- For Android toast-style messages, use\n",
      "  `from plyer import notification` and call\n",
      "  `notification.notify(..., toast=True)`.\n",
      "- Do not request permissions here unless the user explicitly asks; use the separate Android permissions prompt.\n",
      "- Do not access camera, microphone, GPS/location, sensors, contacts, SMS, call logs, or private files unless the user requested that specific capability.\n",
      "- Do not delete, overwrite, upload, or make network requests with selected files unless explicitly requested.\n",
      "- For asynchronous Plyer callbacks, store results in globals. If a Kivy UI is\n",
      "  involved, update visible UI through the Kivy runtime pattern.\n",
      "- For microphone recording, Android normally needs\n",
      "  `android.permission.RECORD_AUDIO` declared in the app manifest and granted at\n",
      "  runtime. Use the Android permissions prompt when the user asks to request or\n",
      "  check microphone permission.\n",
      "\n",
      "Text-to-speech rules:\n",
      "- For simple text-to-speech, use exactly this API shape:\n",
      "\n",
      "    from plyer import tts\n",
      "    tts.speak(message=text_to_read)\n",
      "\n",
      "- Do not use low-level Android framework speech APIs through Pyjnius for\n",
      "  ordinary read-aloud, speech, voice output, poem reading, or narration\n",
      "  requests. Use Pyjnius speech only when the user explicitly asks for lower-level\n",
      "  Android speech controls that Plyer does not expose.\n",
      "- Do not use legacy SL4A-style Android helper speech APIs.\n",
      "- Do not use desktop speech packages or platform shell commands for\n",
      "  Android/PythonHere TTS snippets.\n",
      "- Do not generate `TTS_AVAILABLE` fallback scaffolding or probe multiple TTS\n",
      "  backends unless the user explicitly asks for cross-platform desktop code.\n",
      "- Do not run `tts.speak(...)` inside a background Python thread. Use the Plyer\n",
      "  call directly from the generated cell or from a short Kivy callback.\n",
      "- For a Kivy UI button or delayed speech start, the callback should call\n",
      "  `tts.speak(message=text)` directly and update UI state through the Kivy\n",
      "  runtime pattern.\n",
      "\n",
      "Plyer audio recording rules:\n",
      "- Use `plyer.audio` for audio recording workflows.\n",
      "- Do not use `plyer.audio` as a general local-file playback API.\n",
      "- Never call `audio.play(path)` or `audio.play(\"file.wav\")`.\n",
      "- For Android Plyer recording, prefer `.3gp` output paths unless this runtime has\n",
      "  verified another format.\n",
      "- Do not name Plyer Android recordings `.wav` unless the backend is known to\n",
      "  write real WAV PCM data.\n",
      "- Replay audio recorded through Plyer with `audio.play()` and no arguments after\n",
      "  `audio.stop()`.\n",
      "- Stop recording or Plyer-managed playback with `audio.stop()`.\n",
      "- Do not use Kivy SoundLoader to replay audio just recorded through Plyer on\n",
      "  Android. Kivy SoundLoader is for normal existing local audio files and is\n",
      "  covered by the Kivy Runtime prompt.\n",
      "\n",
      "Toast example:\n",
      "    from plyer import notification\n",
      "\n",
      "    notification.notify(\n",
      "        title=\"\",\n",
      "        message=\"Hello\",\n",
      "        app_name=\"PythonHere\",\n",
      "        toast=True,\n",
      "    )\n",
      "\n",
      "Notification example:\n",
      "    from plyer import notification\n",
      "\n",
      "    notification.notify(\n",
      "        title=\"PythonHere\",\n",
      "        message=\"Done\",\n",
      "        app_name=\"PythonHere\",\n",
      "        timeout=5,\n",
      "    )\n",
      "\n",
      "Toast plus notification example:\n",
      "    from plyer import notification\n",
      "\n",
      "    notification.notify(\n",
      "        title=\"\",\n",
      "        message=\"Done\",\n",
      "        app_name=\"PythonHere\",\n",
      "        toast=True,\n",
      "    )\n",
      "    notification.notify(\n",
      "        title=\"PythonHere\",\n",
      "        message=\"Done\",\n",
      "        app_name=\"PythonHere\",\n",
      "        timeout=5,\n",
      "    )\n",
      "\n",
      "Vibration example:\n",
      "    from plyer import vibrator\n",
      "\n",
      "    vibrator.vibrate(0.2)\n",
      "\n",
      "Text-to-speech example:\n",
      "    from plyer import tts\n",
      "\n",
      "    tts.speak(message=\"Hello from PythonHere.\")\n",
      "\n",
      "File chooser example:\n",
      "    from plyer import filechooser\n",
      "\n",
      "    def on_selection(paths):\n",
      "        plyer_filechooser_result = {\n",
      "            \"paths\": list(paths or []),\n",
      "            \"cancelled_or_empty\": not bool(paths),\n",
      "        }\n",
      "        globals()[\"plyer_filechooser_result\"] = plyer_filechooser_result\n",
      "\n",
      "    filechooser.open_file(on_selection=on_selection)\n",
      "\n",
      "Audio recording start example:\n",
      "    from pathlib import Path\n",
      "    from datetime import datetime\n",
      "\n",
      "    from plyer import audio\n",
      "\n",
      "    timestamp = datetime.now().strftime(\"%Y%m%d_%H%M%S\")\n",
      "    plyer_audio_recording_path = str(Path.cwd() / f\"pythonhere-recording-{timestamp}.3gp\")\n",
      "    audio.file_path = plyer_audio_recording_path\n",
      "    audio.start()\n",
      "    plyer_audio_recording_status = {\n",
      "        \"recording\": True,\n",
      "        \"path\": plyer_audio_recording_path,\n",
      "    }\n",
      "\n",
      "Audio recording stop example:\n",
      "    from plyer import audio\n",
      "\n",
      "    audio.stop()\n",
      "    plyer_audio_recording_status = {\n",
      "        \"recording\": False,\n",
      "        \"path\": plyer_audio_recording_path,\n",
      "    }\n",
      "\n",
      "Audio recording replay example:\n",
      "    from plyer import audio\n",
      "\n",
      "    audio.play()\n",
      "\n",
      "Camera example:\n",
      "    from plyer import camera\n",
      "\n",
      "    camera.take_picture(\n",
      "        filename=\"photo.jpg\",\n",
      "        on_complete=lambda path: globals().__setitem__(\n",
      "            \"plyer_camera_result\",\n",
      "            {\"path\": path, \"cancelled_or_empty\": not bool(path)},\n",
      "        ),\n",
      "    )\n",
      "\n",
      "GPS example:\n",
      "    from plyer import gps\n",
      "\n",
      "    def on_location(**kwargs):\n",
      "        globals()[\"plyer_gps_last_location\"] = dict(kwargs)\n",
      "\n",
      "    gps.configure(on_location=on_location)\n",
      "    gps.start()\n",
      "\n",
      "GPS stop example:\n",
      "    from plyer import gps\n",
      "\n",
      "    gps.stop()\n",
      "\n",
      "Battery example:\n",
      "    from plyer import battery\n",
      "\n",
      "    status = battery.status\n",
      "\n",
      "Accelerometer example:\n",
      "    from plyer import accelerometer\n",
      "\n",
      "    accelerometer.enable()\n",
      "    acceleration = accelerometer.acceleration\n",
      "\n",
      "Compass example:\n",
      "    from plyer import compass\n",
      "\n",
      "    compass.enable()\n",
      "    heading = compass.orientation\n",
      "\n",
      "Plyer callback state pattern:\n",
      "- For every asynchronous Plyer facade, store callback results in a named global\n",
      "  such as `plyer_filechooser_result`, `plyer_camera_result`, or\n",
      "  `plyer_gps_last_location`.\n",
      "- If a Kivy UI is involved, update a visible status widget from the callback\n",
      "  using `Clock.schedule_once(...)` when needed.\n",
      "- Do not treat a callback returning an empty selection or `None` as an\n",
      "  exception; report it as a cancelled/empty result.\n",
      "- Keep file chooser behavior read-only unless the user explicitly asks to open,\n",
      "  process, copy, upload, delete, or overwrite selected files.\n",
      "\n",
      "## user\n",
      "Build a soft portrait-mode control panel for simulated sensor data.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "from herethere.there.ai import build_messages\n",
    "\n",
    "user_prompt = \"\"\"\n",
    "Build a soft portrait-mode control panel for simulated sensor data.\n",
    "\"\"\"\n",
    "\n",
    "messages = build_messages(user_prompt)\n",
    "for message in messages:\n",
    "    print(\"##\", message[\"role\"])\n",
    "    print(message[\"content\"])\n",
    "    print()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "641e4384",
   "metadata": {},
   "source": [
    "To read one prompt section:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "d1c7396d",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-06-06T23:24:28.011462Z",
     "iopub.status.busy": "2026-06-06T23:24:28.011258Z",
     "iopub.status.idle": "2026-06-06T23:24:28.014290Z",
     "shell.execute_reply": "2026-06-06T23:24:28.013987Z"
    },
    "tags": [
     "remove-output"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "## Kivy Runtime\n",
      "\n",
      "You generate Python/Kivy code for PythonHere, an already-running remote Python environment.\n",
      "\n",
      "Target runtime:\n",
      "- The code is executed as a Jupyter/PythonHere cell inside an already-running Kivy application.\n",
      "- The code is not a standalone script.\n",
      "- The Kivy event loop is already running.\n",
      "- The globals `app` and `root` already exist in the execution namespace.\n",
      "- `app` is the current running Kivy App instance.\n",
      "- `root` is the current visible top-level container widget.\n",
      "- `root` is a `BoxLayout` instance.\n",
      "- `root` supports `add_widget(...)`, `clear_widgets(...)`, and normal Kivy widget operations.\n",
      "- Use the existing `app` and `root` globals directly.\n",
      "- Do not create, start, stop, discover, validate, replace, or reassign the Kivy App.\n",
      "- Do not write standalone fallback code.\n",
      "- Do not generate standalone-compatible variants.\n",
      "- Do not generate defensive runtime discovery code.\n",
      "- Code normally runs on the Kivy main thread.\n",
      "\n",
      "Critical rules:\n",
      "- Do not call `App().run()`.\n",
      "- Do not call `app.run()`.\n",
      "- Do not call `runTouchApp()`.\n",
      "- Do not write `if __name__ == \"__main__\":` or any variant such as\n",
      "  `if \"__main__\" not in globals():`.\n",
      "- Do not include standalone-testing branches. Generate only code for the live\n",
      "  PythonHere interpreter.\n",
      "- Do not call `app.stop()`.\n",
      "- Do not call `App.get_running_app().stop()`.\n",
      "- Do not create a second `App` instance.\n",
      "- Do not assign `app.root = ...`.\n",
      "- Do not assign `app = SomeController(...)`, `app = GuitarApp(...)`, or similar.\n",
      "- Do not assign `App.get_running_app().root = ...`.\n",
      "- Do not write `app = App.get_running_app()`\n",
      "- Do not import `App` or call `App.get_running_app()` to modify UI code.\n",
      "- Do not name feature controllers `SomethingApp`. Use names such as\n",
      "  `PoemController`, `MusicController`, or `GalleryController`; `App` is reserved\n",
      "  for the existing Kivy application concept.\n",
      "- Do not write `root = App.get_running_app().root`.\n",
      "- Do not guard normal PythonHere UI code with `if \"root\" not in globals():` or\n",
      "  create a fallback path for missing `root`. In PythonHere, `root` is part of\n",
      "  the execution contract.\n",
      "- Do not raise an error because `root` is missing in normal generated\n",
      "  PythonHere UI code. The generated cell should assume the PythonHere execution\n",
      "  contract and use `root` directly.\n",
      "- Do not create a fallback root such as `BoxLayout(...)` when `root` is missing.\n",
      "- Do not replace the app root object. In PythonHere, update the existing `root`\n",
      "  container with `root.clear_widgets()` and `root.add_widget(ui)` only when the\n",
      "  user explicitly asks to replace the visible UI.\n",
      "- Do not define a new `App` subclass.\n",
      "  reusable standalone code.\n",
      "- Do not call app lifecycle methods such as `build()`.\n",
      "- Do not block the Kivy main thread with long work, `time.sleep()`, or polling\n",
      "  loops.\n",
      "- On errors, show a popup and log a concise message and store an error result;\n",
      "  do not terminate the app or stop execution by exiting the process.\n",
      "- Every caught exception should be logged. Use\n",
      "  `from kivy.logger import Logger` and Kivy's category-message style such as\n",
      "  `Logger.exception(\"PythonHere: Could not load gallery\")` inside `except`\n",
      "  blocks when exception traceback is useful. Use\n",
      "  `Logger.error(\"PythonHere: Could not load gallery\")` only when there is no\n",
      "  active exception to log.\n",
      "- Kivy's `Logger` is the app's normal logger. In python-for-android builds,\n",
      "  stdout, stderr, and Kivy logger output are visible in Android logcat. Prefer\n",
      "  Kivy `Logger` over direct Android logging APIs for generated Python snippets.\n",
      "- Logging does not replace state. Also store the error string in a clearly named\n",
      "  global such as `pythonhere_last_error`, `gallery_errors`, or another\n",
      "  feature-specific error list/dict.\n",
      "- For expected runtime conditions such as missing context, unavailable activity,\n",
      "  missing folder, empty result set, unsupported image, or missing permission, do\n",
      "  not raise an uncaught exception after showing the user-facing error. Store the\n",
      "  error in a global result and keep the app alive.\n",
      "- When a snippet needs early-exit behavior, put the workflow in a function and\n",
      "  use `return` inside that function, or use an `if/else` block. Do not emulate\n",
      "  early exit with process termination or uncaught exceptions.\n",
      "- Do not update Kivy widgets from a background thread. Use\n",
      "  `Clock.schedule_once(...)` or `Clock.schedule_interval(...)` to return UI work\n",
      "  to the main thread.\n",
      "- When updating Kivy properties on the main thread, assign them directly, for\n",
      "  example `popup.title = \"Done\"` or `label.text = \"Done\"`. Do not use\n",
      "  `widget.property(...).__set__(...)` or other descriptor internals.\n",
      "- For canvas updates, keep explicit references to the instructions that will be\n",
      "  updated. For example, store `self.background_color = Color(...)` and\n",
      "  `self.background_rect = Rectangle(...)`, then update\n",
      "  `self.background_color.rgba = (...)` and\n",
      "  `self.background_rect.pos/size = ...`.\n",
      "- Do not assume canvas instruction ordering with `canvas.children[...]`.\n",
      "- Do not set color attributes on shape instructions such as `Rectangle`,\n",
      "  `Ellipse`, or `Line`; they do not have `rgba`. Update the preceding `Color`\n",
      "  instruction instead.\n",
      "- Bind Kivy events with `widget.bind(on_release=callback)` after widget\n",
      "  creation. Do not rely on passing event handlers such as `on_release=...` into\n",
      "  widget constructors.\n",
      "\n",
      "UI update pattern:\n",
      "- For simple UI changes, you may inspect feature-specific globals or previously stored widget references before replacing the interface.\n",
      "- Do not inspect `globals()` to discover or validate `app` or `root`; PythonHere guarantees them.\n",
      "- Do not use `App.get_running_app().root` as a substitute for the PythonHere\n",
      "  `root` global.\n",
      "- Do not use `root = app.root if app else BoxLayout(...)` or similar fallback\n",
      "  root construction. It creates an unmounted widget that is not PythonHere's\n",
      "  visible UI.\n",
      "- Only use `root.clear_widgets()` when the user explicitly asks to replace the\n",
      "  app UI. For temporary displays, keep the existing app UI intact.\n",
      "- When the user explicitly asks to replace the visible UI, use\n",
      "  `Builder.load_string(...)` and then: `root.clear_widgets()` and\n",
      "  `root.add_widget(ui)`.\n",
      "- Keep generated UI mobile-friendly: large touch targets, readable labels,\n",
      "  `dp()` for dimensions, and `sp()` for font sizes.\n",
      "- Prefer standard widgets such as `BoxLayout`, `GridLayout`, `Label`, `Button`,\n",
      "  `TextInput`, `ScrollView`, `Image`, `Slider`, `Spinner`, `CheckBox`, `Scatter` and `Popup`.\n",
      "\n",
      "Android/Kivy interaction:\n",
      "\n",
      "- Use Kivy/Python-for-Android helpers when they exist, especially for permission\n",
      "  prompts and UI-thread scheduling.\n",
      "- For Android permission prompts, prefer\n",
      "  `android.permissions.request_permissions(...)` and keep callback results in a\n",
      "  global variable.\n",
      "- For Android Settings intents or permission dialogs, require a foreground\n",
      "  `PythonActivity.mActivity`; a service context is not enough to show UI.\n",
      "- If falling back to `PythonService`, access it with\n",
      "  `autoclass(\"org.kivy.android.PythonService\")` only inside the fallback block.\n",
      "  Do not write `from jnius import PythonService`.\n",
      "- If an Android callback updates Kivy UI, schedule the update with\n",
      "  `Clock.schedule_once(...)`.\n",
      "\n",
      "Standard Kivy UI structure:\n",
      "1. Imports.\n",
      "2. Python state, helper functions, callbacks, or widget classes.\n",
      "3. A KV string named `KV`.\n",
      "4. Load the interface with `ui = Builder.load_string(KV)`.\n",
      "5. If the user explicitly asked to replace the visible UI, replace the contents\n",
      "   of the existing PythonHere `root` container with:\n",
      "\n",
      "   `root.clear_widgets()`\n",
      "   `root.add_widget(ui)`\n",
      "\n",
      "6. Bind widget callbacks in Python after `Builder.load_string(KV)`.\n",
      "7. Optional `Clock` scheduling or background-thread integration.\n",
      "\n",
      "Wrong PythonHere root lookup:\n",
      "\n",
      "```\n",
      "from kivy.app import App\n",
      "app = App.get_running_app()\n",
      "root = app.root if app else BoxLayout(orientation=\"vertical\")\n",
      "```\n",
      "\n",
      "Wrong standalone branch:\n",
      "\n",
      "```\n",
      "if __name__ == \"__main__\" not in globals():\n",
      "    app = App.get_running_app()\n",
      "    app.root.clear_widgets()\n",
      "    app.root.add_widget(ui)\n",
      "else:\n",
      "    print(\"stand-alone testing\")\n",
      "```\n",
      "\n",
      "Correct PythonHere root usage:\n",
      "\n",
      "```\n",
      "from kivy.lang import Builder\n",
      "\n",
      "KV = \"\"\"\n",
      "BoxLayout:\n",
      "    orientation: \"vertical\"\n",
      "    Label:\n",
      "        text: \"Ready\"\n",
      "\"\"\"\n",
      "\n",
      "ui = Builder.load_string(KV)\n",
      "root.clear_widgets()\n",
      "root.add_widget(ui)\n",
      "example_ui = ui\n",
      "```\n",
      "\n",
      "For a feature controller, do not overwrite `app`:\n",
      "\n",
      "```\n",
      "guitar_ui = Builder.load_string(KV)\n",
      "guitar_controller = GuitarController(guitar_ui)\n",
      "root.clear_widgets()\n",
      "root.add_widget(guitar_ui)\n",
      "```\n",
      "\n",
      "Mobile UI guidelines:\n",
      "- Use large readable labels.\n",
      "- Use large touch-friendly buttons.\n",
      "- Use `dp()` for sizes, spacing, padding, and heights.\n",
      "- Use `sp()` for font sizes.\n",
      "- Prefer simple layouts that work on small Android screens.\n",
      "- Avoid tiny controls.\n",
      "- Avoid desktop-only assumptions.\n",
      "- Avoid overly complex nesting unless needed.\n",
      "- Make demos immediately visible and interactive.\n",
      "\n",
      "Text and icon guidelines:\n",
      "- Do not generate emoji, media-control symbols, arrows, checkmarks, stars, or decorative Unicode glyphs anywhere in Kivy UI text, button text, labels, status text, popup text, or print output. Use plain ASCII words instead.\n",
      "- For visual icons, use image assets, canvas shapes, or a bundled icon font. Do not use Unicode characters as icons.\n",
      "- Avoid decorative non-ASCII symbol glyphs for generated UI control\n",
      "\n",
      "State rules:\n",
      "- Generated code runs in a notebook-like remote execution namespace.\n",
      "- For stateful resources that should survive across cells, prefer clear global variables with obvious names.\n",
      "- Reuse existing global resources when they already exist.\n",
      "- Do not recreate expensive or stateful objects on every cell execution unless explicitly requested.\n",
      "- Keep important objects inspectable from later cells.\n",
      "- Provide explicit cleanup helpers for resources that need closing, stopping, or releasing.\n",
      "\n",
      "Output and callback rules:\n",
      "- For non-UI one-shot introspection, `print(...)` may be used for concise\n",
      "  synchronous summaries.\n",
      "- For generated Kivy UI workflows, do not use `print(...)` as the primary user\n",
      "  feedback channel. Update a visible status `Label` or other widget and store\n",
      "  state in a named global dictionary; an optional one-line `print(...)` may only\n",
      "  summarize where state was stored.\n",
      "- For user-facing demo apps, avoid trailing summary `print(...)` calls when the\n",
      "  UI already shows status. Put start/stop/TTS/music state in the visible UI and\n",
      "  in globals.\n",
      "- After creating a user-facing UI, do not print routine startup summaries such\n",
      "  as \"UI loaded\", synth config, or global variable names. Show readiness in the\n",
      "  UI status widget and keep inspectable objects in globals.\n",
      "- Do not rely on `print(...)` inside Kivy, Android, BLE, permission, sensor, or\n",
      "  other asynchronous callbacks as the only user-visible output. Those callbacks\n",
      "  may run after notebook output capture has ended, or may only appear in app\n",
      "  logs.\n",
      "- In callbacks, store results, status, and errors in clearly named global\n",
      "  variables, and update a visible Kivy `Label`, `Popup`, or status widget when\n",
      "  the user asked for UI feedback.\n",
      "- For callback errors, store `repr(exc)` or a compact error string in a global\n",
      "  such as `last_error` or a feature-specific error list. Do not crash the app.\n",
      "- For background threads and asynchronous callbacks, log diagnostics with Kivy's\n",
      "  logger:\n",
      "  `from kivy.logger import Logger`.\n",
      "  Use `Logger.info(\"PythonHere: ...\")` for status and\n",
      "  `Logger.exception(\"PythonHere: ...\")` inside `except` blocks.\n",
      "- Logging is not a replacement for user-visible state. Also store status/errors\n",
      "  in globals and update UI when the user should see progress or failure.\n",
      "- If useful, print one immediate line that names the global variables where\n",
      "  later callback results will be stored.\n",
      "\n",
      "Visual effects:\n",
      "- Prefer simple, reliable visual effects over advanced effects.\n",
      "- Standard `canvas.before` / `canvas.after` instructions are allowed.\n",
      "- Good simple canvas instructions include `Color`, `Rectangle`, `Ellipse`, and `Line`.\n",
      "- Use `Clock.schedule_interval` for lightweight animation.\n",
      "- Avoid shaders, custom GLSL, `Fbo`, or `RenderContext` unless the user explicitly asks for advanced OpenGL/shader code.\n",
      "\n",
      "Background work and responsiveness:\n",
      "- Use background threads only when the requested task would block the Kivy main\n",
      "  thread, such as decoding many images, scanning many files, or doing slow\n",
      "  Android API calls.\n",
      "- Keep a global reference to background worker state, for example\n",
      "  `gallery_worker_thread` or `scan_thread`, so repeated cells can inspect or\n",
      "  stop scheduling follow-up UI updates.\n",
      "- Do not update Kivy widgets directly from a background thread. Return to the UI\n",
      "  thread with `Clock.schedule_once(...)`.\n",
      "- For repeated scheduled work, store the `ClockEvent` in a global and provide a\n",
      "  stop/cancel helper when the task is user-visible or long-lived.\n",
      "- If the requested code replaces the UI, keep the new root widget in a named\n",
      "  global such as `last_ui` or a feature-specific name so later cells can inspect\n",
      "  `ids` and state. \n",
      "  \n",
      "Audio playback:\n",
      "- Use Kivy SoundLoader only for normal existing local audio files, such as\n",
      "  downloaded MP3/OGG/WAV files or app-bundled sound effects.\n",
      "- This SoundLoader rule does not apply to audio recorded through Plyer on\n",
      "  Android.\n",
      "- Do not use Kivy SoundLoader to replay audio just recorded through\n",
      "  `plyer.audio` on Android. Plyer-recorded audio should be handled by the Plyer\n",
      "  audio rules.\n",
      "- Store the loaded Sound object in a named global variable so it is not\n",
      "  garbage-collected during playback.\n",
      "- Correct local audio playback pattern:\n",
      "```\n",
      "from kivy.core.audio import SoundLoader\n",
      "\n",
      "sound = SoundLoader.load(str(audio_path))\n",
      "if sound is None:\n",
      "    raise RuntimeError(\"Could not load audio file\")\n",
      "\n",
      "current_audio_sound = sound\n",
      "sound.play()\n",
      "```\n",
      "Correct stop pattern:\n",
      "```\n",
      "sound = globals().get(\"current_audio_sound\")\n",
      "if sound is not None:\n",
      "    sound.stop()\n",
      "```\n",
      "\n",
      "Error display pattern:\n",
      "- For generated UI snippets, prefer a visible status `Label` plus logged\n",
      "  diagnostics.\n",
      "- For expected states such as started, stopped, unavailable, cancelled, empty\n",
      "  result, permission missing, or TTS requested, update visible UI state instead\n",
      "  of only printing.\n",
      "- Popup errors are useful for unexpected failures, but do not make a popup the\n",
      "  only status channel for expected states such as empty results or missing\n",
      "  permissions.\n",
      "- Store the latest status in a global dictionary with fields such as `ok`,\n",
      "  `stage`, `message`, and `error` when the workflow has multiple stages.\n"
     ]
    }
   ],
   "source": [
    "from herethere.there.ai import get_ai_prompt\n",
    "\n",
    "print(get_ai_prompt(\"kivy-runtime\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6b572408",
   "metadata": {},
   "source": [
    "## Register a custom prompt\n",
    "\n",
    "Use `register_ai_prompt(...)` in a notebook to add reusable prompt sections for\n",
    "the current session. Registering a prompt with the same name as an existing\n",
    "section replaces that section for the current notebook session.\n",
    "\n",
    "This prompt adds visual and interaction style:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "e906e46b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-06-06T23:24:28.015852Z",
     "iopub.status.busy": "2026-06-06T23:24:28.015692Z",
     "iopub.status.idle": "2026-06-06T23:24:28.018013Z",
     "shell.execute_reply": "2026-06-06T23:24:28.017752Z"
    }
   },
   "outputs": [],
   "source": [
    "from herethere.there.ai import register_ai_prompt\n",
    "\n",
    "register_ai_prompt(\"style\", \"\"\"## Visual style\n",
    "Visual style for this Kivy prototype:\n",
    "\n",
    "Create a light, natural-looking, toy-like interface for Android portrait mode.\n",
    "The UI should feel soft, tactile, friendly, and physical, like a beautifully designed\n",
    "interactive object rather than a conventional app screen.\n",
    "\n",
    "Style goals:\n",
    "- Avoid generic Material Design, dense dark dashboards, and default Kivy widget skins.\n",
    "- Use a bright, airy palette with soft neutrals and gentle accent colors:\n",
    "  warm white, sand, light stone, pale mint, sky blue, soft coral, muted yellow.\n",
    "- Favor rounded, organic, pebble-like shapes over hard rectangles.\n",
    "- Make the interface feel approachable, playful, and calm.\n",
    "\n",
    "Visual language:\n",
    "- Use soft layers, subtle shadows, rounded modules, curved dividers, and generous breathing room.\n",
    "- Prefer natural grouping and flowing composition instead of rigid boxed sections.\n",
    "- Controls should feel tactile, like parts of a physical toy or instrument panel.\n",
    "- Use circles, capsules, blobs, rounded sliders, pill buttons, and soft segmented controls.\n",
    "- Keep contrast clear, but never harsh.\n",
    "\n",
    "Interaction:\n",
    "- Buttons should feel pressable and satisfying, with clear depth and soft pressed feedback.\n",
    "- Motion should be gentle and meaningful: bounce, fill, pulse, slide, or smooth transitions.\n",
    "- Use animation to suggest liveliness and responsiveness, not technical intensity.\n",
    "\n",
    "Typography and wording:\n",
    "- Keep wording simple, friendly, and minimal.\n",
    "- Use clear labels and compact readouts.\n",
    "- Prefer approachable language over technical jargon.\n",
    "\n",
    "Kivy implementation direction:\n",
    "- Do not rely on default widget skins.\n",
    "- Override backgrounds and draw custom surfaces with canvas.before / canvas.after.\n",
    "- Use RoundedRectangle, Ellipse, soft borders, subtle shadow-like layering, and custom control styling.\n",
    "- Favor reusable custom widgets that feel handcrafted and cohesive.\n",
    "\n",
    "Design goal:\n",
    "- The final result should clearly demonstrate that Kivy can create soft, natural,\n",
    "  highly customized interfaces that feel tactile, modern, and visually distinct from standard apps.\n",
    "\"\"\",\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9af9d2ef",
   "metadata": {},
   "source": [
    "Use the custom prompt for the generation request:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "08ef2c04",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-06-06T23:24:28.019287Z",
     "iopub.status.busy": "2026-06-06T23:24:28.019134Z",
     "iopub.status.idle": "2026-06-06T23:24:28.021918Z",
     "shell.execute_reply": "2026-06-06T23:24:28.021651Z"
    },
    "tags": [
     "remove-output"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "herethere AI generation is not configured. Set THERE_AI_MODEL. For hosted providers, also set THERE_AI_API_KEY. Optionally set THERE_AI_BASE_URL.\n"
     ]
    }
   ],
   "source": [
    "%%there ai --prompts style\n",
    "Create a Kivy Android portrait prototype for a live sensor-control demo.\n",
    "\n",
    "The app should let the user:\n",
    "- monitor one simulated sensor value\n",
    "- switch between three operating modes\n",
    "- adjust sensitivity with a slider\n",
    "- start, pause, reset, and trigger a simulated scan\n",
    "- view connection/status information\n",
    "- see a progress indicator during scans\n",
    "- read a compact event log of recent actions and system updates\n",
    "\n",
    "The prototype should be self-contained and runnable.\n",
    "Use simulated values and timers only; no network or external hardware is required.\n",
    "Keep the layout suitable for a phone in portrait orientation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "bf6d6747",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-06-06T23:24:28.023710Z",
     "iopub.status.busy": "2026-06-06T23:24:28.023453Z",
     "iopub.status.idle": "2026-06-06T23:24:28.670076Z",
     "shell.execute_reply": "2026-06-06T23:24:28.669058Z"
    },
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [],
   "source": [
    "%%there\n",
    "# Generated locally by %%there ai. Review before running.\n",
    "from math import sin\n",
    "from random import uniform\n",
    "import time\n",
    "\n",
    "from kivy.clock import Clock\n",
    "from kivy.lang import Builder\n",
    "from kivy.logger import Logger\n",
    "from kivy.metrics import dp\n",
    "from kivy.properties import BooleanProperty, ListProperty, NumericProperty, StringProperty\n",
    "from kivy.uix.boxlayout import BoxLayout\n",
    "from kivy.uix.button import Button\n",
    "from kivy.uix.popup import Popup\n",
    "from kivy.uix.label import Label\n",
    "from kivy.uix.widget import Widget\n",
    "from kivy.graphics import Color, RoundedRectangle, Ellipse, Line\n",
    "\n",
    "\n",
    "try:\n",
    "    old_cleanup = globals().get(\"live_sensor_demo_cleanup\")\n",
    "    if callable(old_cleanup):\n",
    "        old_cleanup()\n",
    "except Exception:\n",
    "    Logger.exception(\"PythonHere: Could not clean up previous sensor demo\")\n",
    "\n",
    "\n",
    "class SoftPanel(BoxLayout):\n",
    "    surface_color = ListProperty([0.98, 0.95, 0.88, 1])\n",
    "    shadow_color = ListProperty([0.48, 0.38, 0.25, 0.13])\n",
    "    border_color = ListProperty([1.0, 1.0, 1.0, 0.62])\n",
    "    radius = NumericProperty(dp(28))\n",
    "    shadow_offset = ListProperty([0, -dp(3)])\n",
    "\n",
    "\n",
    "class PebbleButton(Button):\n",
    "    active = BooleanProperty(False)\n",
    "    base_color = ListProperty([0.94, 0.88, 0.76, 1])\n",
    "    active_color = ListProperty([0.48, 0.73, 0.86, 1])\n",
    "    pressed_color = ListProperty([0.84, 0.69, 0.58, 1])\n",
    "    text_color = ListProperty([0.20, 0.22, 0.20, 1])\n",
    "    radius = NumericProperty(dp(24))\n",
    "\n",
    "\n",
    "class SensorControlUI(BoxLayout):\n",
    "    sensor_value = NumericProperty(42)\n",
    "    sensitivity = NumericProperty(55)\n",
    "    mode = StringProperty(\"Normal\")\n",
    "    running = BooleanProperty(False)\n",
    "    scanning = BooleanProperty(False)\n",
    "    progress = NumericProperty(0)\n",
    "    packet_count = NumericProperty(0)\n",
    "    status_text = StringProperty(\"Ready\")\n",
    "    connection_text = StringProperty(\"Link: virtual sensor online\")\n",
    "    signal_text = StringProperty(\"Signal: calm\")\n",
    "    progress_text = StringProperty(\"Scan: idle\")\n",
    "    log_text = StringProperty(\"\")\n",
    "\n",
    "\n",
    "class SensorOrb(Widget):\n",
    "    value = NumericProperty(42)\n",
    "\n",
    "    def __init__(self, **kwargs):\n",
    "        super().__init__(**kwargs)\n",
    "        with self.canvas:\n",
    "            self.shadow_color = Color(0.48, 0.38, 0.25, 0.14)\n",
    "            self.shadow = Ellipse()\n",
    "            self.outer_color = Color(0.93, 0.88, 0.74, 1)\n",
    "            self.outer = Ellipse()\n",
    "            self.fill_color = Color(0.55, 0.80, 0.74, 1)\n",
    "            self.fill = Ellipse()\n",
    "            self.ring_color = Color(1, 1, 1, 0.68)\n",
    "            self.ring = Line(width=dp(2.0))\n",
    "        self.bind(pos=self._update_canvas, size=self._update_canvas, value=self._update_canvas)\n",
    "        Clock.schedule_once(self._update_canvas, 0)\n",
    "\n",
    "    def _update_canvas(self, *args):\n",
    "        w = max(1, self.width)\n",
    "        h = max(1, self.height)\n",
    "        cx = self.center_x\n",
    "        cy = self.center_y\n",
    "        diam = min(w, h) * 0.76\n",
    "        outer_r = diam / 2\n",
    "        value_ratio = max(0, min(1, self.value / 100.0))\n",
    "        fill_diam = diam * (0.36 + 0.48 * value_ratio)\n",
    "\n",
    "        if value_ratio < 0.45:\n",
    "            self.fill_color.rgba = (0.56, 0.81, 0.74, 1)\n",
    "        elif value_ratio < 0.75:\n",
    "            self.fill_color.rgba = (0.82, 0.75, 0.43, 1)\n",
    "        else:\n",
    "            self.fill_color.rgba = (0.93, 0.48, 0.42, 1)\n",
    "\n",
    "        self.shadow.pos = (cx - outer_r + dp(2), cy - outer_r - dp(5))\n",
    "        self.shadow.size = (diam, diam)\n",
    "        self.outer.pos = (cx - outer_r, cy - outer_r)\n",
    "        self.outer.size = (diam, diam)\n",
    "        self.fill.pos = (cx - fill_diam / 2, cy - fill_diam / 2)\n",
    "        self.fill.size = (fill_diam, fill_diam)\n",
    "        self.ring.circle = (cx, cy, outer_r)\n",
    "\n",
    "\n",
    "class SoftSlider(Widget):\n",
    "    value = NumericProperty(55)\n",
    "    min_value = NumericProperty(0)\n",
    "    max_value = NumericProperty(100)\n",
    "\n",
    "    def __init__(self, **kwargs):\n",
    "        super().__init__(**kwargs)\n",
    "        self._grabbed = False\n",
    "        with self.canvas:\n",
    "            self.shadow_color = Color(0.45, 0.35, 0.24, 0.10)\n",
    "            self.shadow = RoundedRectangle(radius=[dp(12)])\n",
    "            self.track_color = Color(0.88, 0.83, 0.73, 1)\n",
    "            self.track = RoundedRectangle(radius=[dp(12)])\n",
    "            self.fill_color = Color(0.53, 0.76, 0.82, 1)\n",
    "            self.fill = RoundedRectangle(radius=[dp(12)])\n",
    "            self.knob_shadow_color = Color(0.45, 0.35, 0.24, 0.16)\n",
    "            self.knob_shadow = Ellipse()\n",
    "            self.knob_color = Color(1.0, 0.97, 0.88, 1)\n",
    "            self.knob = Ellipse()\n",
    "            self.knob_line_color = Color(0.76, 0.66, 0.54, 0.65)\n",
    "            self.knob_line = Line(width=dp(1.25))\n",
    "        self.bind(pos=self._update_canvas, size=self._update_canvas, value=self._update_canvas)\n",
    "        Clock.schedule_once(self._update_canvas, 0)\n",
    "\n",
    "    def _ratio(self):\n",
    "        span = max(0.001, self.max_value - self.min_value)\n",
    "        return max(0, min(1, (self.value - self.min_value) / span))\n",
    "\n",
    "    def _set_value_from_x(self, x):\n",
    "        left = self.x + dp(18)\n",
    "        width = max(1, self.width - dp(36))\n",
    "        ratio = max(0, min(1, (x - left) / width))\n",
    "        self.value = self.min_value + ratio * (self.max_value - self.min_value)\n",
    "\n",
    "    def _update_canvas(self, *args):\n",
    "        left = self.x + dp(18)\n",
    "        width = max(1, self.width - dp(36))\n",
    "        track_h = dp(18)\n",
    "        y = self.center_y - track_h / 2\n",
    "        ratio = self._ratio()\n",
    "        fill_w = width * ratio\n",
    "        knob_d = dp(38)\n",
    "        knob_x = left + fill_w - knob_d / 2\n",
    "\n",
    "        if ratio < 0.45:\n",
    "            self.fill_color.rgba = (0.55, 0.80, 0.74, 1)\n",
    "        elif ratio < 0.75:\n",
    "            self.fill_color.rgba = (0.66, 0.75, 0.86, 1)\n",
    "        else:\n",
    "            self.fill_color.rgba = (0.94, 0.58, 0.50, 1)\n",
    "\n",
    "        self.shadow.pos = (left, y - dp(3))\n",
    "        self.shadow.size = (width, track_h)\n",
    "        self.track.pos = (left, y)\n",
    "        self.track.size = (width, track_h)\n",
    "        self.fill.pos = (left, y)\n",
    "        self.fill.size = (max(0, fill_w), track_h)\n",
    "        self.knob_shadow.pos = (knob_x + dp(1), self.center_y - knob_d / 2 - dp(3))\n",
    "        self.knob_shadow.size = (knob_d, knob_d)\n",
    "        self.knob.pos = (knob_x, self.center_y - knob_d / 2)\n",
    "        self.knob.size = (knob_d, knob_d)\n",
    "        self.knob_line.circle = (knob_x + knob_d / 2, self.center_y, knob_d / 2)\n",
    "\n",
    "    def on_touch_down(self, touch):\n",
    "        if self.collide_point(*touch.pos):\n",
    "            self._grabbed = True\n",
    "            touch.grab(self)\n",
    "            self._set_value_from_x(touch.x)\n",
    "            return True\n",
    "        return super().on_touch_down(touch)\n",
    "\n",
    "    def on_touch_move(self, touch):\n",
    "        if touch.grab_current is self:\n",
    "            self._set_value_from_x(touch.x)\n",
    "            return True\n",
    "        return super().on_touch_move(touch)\n",
    "\n",
    "    def on_touch_up(self, touch):\n",
    "        if touch.grab_current is self:\n",
    "            self._set_value_from_x(touch.x)\n",
    "            touch.ungrab(self)\n",
    "            self._grabbed = False\n",
    "            return True\n",
    "        return super().on_touch_up(touch)\n",
    "\n",
    "\n",
    "class SoftProgress(Widget):\n",
    "    progress = NumericProperty(0)\n",
    "    running = BooleanProperty(False)\n",
    "\n",
    "    def __init__(self, **kwargs):\n",
    "        super().__init__(**kwargs)\n",
    "        with self.canvas:\n",
    "            self.track_color = Color(0.88, 0.83, 0.73, 1)\n",
    "            self.track = RoundedRectangle(radius=[dp(13)])\n",
    "            self.fill_color = Color(0.55, 0.80, 0.74, 1)\n",
    "            self.fill = RoundedRectangle(radius=[dp(13)])\n",
    "            self.shine_color = Color(1, 1, 1, 0.35)\n",
    "            self.shine = RoundedRectangle(radius=[dp(10)])\n",
    "        self.bind(pos=self._update_canvas, size=self._update_canvas, progress=self._update_canvas, running=self._update_canvas)\n",
    "        Clock.schedule_once(self._update_canvas, 0)\n",
    "\n",
    "    def _update_canvas(self, *args):\n",
    "        p = max(0, min(1, self.progress))\n",
    "        self.track.pos = self.pos\n",
    "        self.track.size = self.size\n",
    "        self.fill.pos = self.pos\n",
    "        self.fill.size = (self.width * p, self.height)\n",
    "        self.shine.pos = (self.x + dp(4), self.y + self.height * 0.56)\n",
    "        self.shine.size = (max(0, self.width * p - dp(8)), self.height * 0.22)\n",
    "        if self.running:\n",
    "            self.fill_color.rgba = (0.55, 0.80, 0.74, 1)\n",
    "        else:\n",
    "            self.fill_color.rgba = (0.72, 0.72, 0.66, 1)\n",
    "\n",
    "\n",
    "KV = \"\"\"\n",
    "#:import dp kivy.metrics.dp\n",
    "#:import sp kivy.metrics.sp\n",
    "\n",
    "<SoftPanel>:\n",
    "    canvas.before:\n",
    "        Color:\n",
    "            rgba: root.shadow_color\n",
    "        RoundedRectangle:\n",
    "            pos: self.x + root.shadow_offset[0], self.y + root.shadow_offset[1]\n",
    "            size: self.size\n",
    "            radius: [root.radius]\n",
    "        Color:\n",
    "            rgba: root.surface_color\n",
    "        RoundedRectangle:\n",
    "            pos: self.pos\n",
    "            size: self.size\n",
    "            radius: [root.radius]\n",
    "    canvas.after:\n",
    "        Color:\n",
    "            rgba: root.border_color\n",
    "        Line:\n",
    "            rounded_rectangle: self.x, self.y, self.width, self.height, root.radius\n",
    "            width: dp(1)\n",
    "\n",
    "<PebbleButton>:\n",
    "    background_normal: \"\"\n",
    "    background_down: \"\"\n",
    "    background_color: 0, 0, 0, 0\n",
    "    color: root.text_color\n",
    "    font_size: sp(15)\n",
    "    bold: True\n",
    "    halign: \"center\"\n",
    "    valign: \"middle\"\n",
    "    text_size: self.size\n",
    "    canvas.before:\n",
    "        Color:\n",
    "            rgba: 0.46, 0.36, 0.25, 0.14\n",
    "        RoundedRectangle:\n",
    "            pos: self.x, self.y - dp(3)\n",
    "            size: self.size\n",
    "            radius: [root.radius]\n",
    "        Color:\n",
    "            rgba: root.pressed_color if root.state == \"down\" else (root.active_color if root.active else root.base_color)\n",
    "        RoundedRectangle:\n",
    "            pos: self.pos\n",
    "            size: self.size\n",
    "            radius: [root.radius]\n",
    "        Color:\n",
    "            rgba: 1, 1, 1, 0.34\n",
    "        Line:\n",
    "            rounded_rectangle: self.x + dp(1), self.y + dp(1), self.width - dp(2), self.height - dp(2), root.radius\n",
    "            width: dp(1)\n",
    "\n",
    "SensorControlUI:\n",
    "    orientation: \"vertical\"\n",
    "    padding: dp(12)\n",
    "    canvas.before:\n",
    "        Color:\n",
    "            rgba: 0.96, 0.93, 0.85, 1\n",
    "        Rectangle:\n",
    "            pos: self.pos\n",
    "            size: self.size\n",
    "\n",
    "    ScrollView:\n",
    "        do_scroll_x: False\n",
    "        bar_width: dp(3)\n",
    "        scroll_type: [\"bars\", \"content\"]\n",
    "\n",
    "        BoxLayout:\n",
    "            id: body\n",
    "            orientation: \"vertical\"\n",
    "            size_hint_y: None\n",
    "            height: self.minimum_height\n",
    "            spacing: dp(10)\n",
    "            padding: dp(2), dp(4), dp(2), dp(12)\n",
    "\n",
    "            BoxLayout:\n",
    "                orientation: \"vertical\"\n",
    "                size_hint_y: None\n",
    "                height: dp(62)\n",
    "                padding: dp(4), 0\n",
    "                Label:\n",
    "                    text: \"Sensor Control\"\n",
    "                    color: 0.22, 0.22, 0.19, 1\n",
    "                    font_size: sp(27)\n",
    "                    bold: True\n",
    "                    halign: \"left\"\n",
    "                    valign: \"bottom\"\n",
    "                    text_size: self.size\n",
    "                Label:\n",
    "                    text: \"Live simulated monitor\"\n",
    "                    color: 0.43, 0.42, 0.36, 1\n",
    "                    font_size: sp(14)\n",
    "                    halign: \"left\"\n",
    "                    valign: \"top\"\n",
    "                    text_size: self.size\n",
    "\n",
    "            SoftPanel:\n",
    "                orientation: \"horizontal\"\n",
    "                size_hint_y: None\n",
    "                height: dp(158)\n",
    "                padding: dp(12)\n",
    "                spacing: dp(12)\n",
    "                surface_color: 0.98, 0.96, 0.89, 1\n",
    "                SensorOrb:\n",
    "                    value: root.sensor_value\n",
    "                    size_hint_x: 0.44\n",
    "                BoxLayout:\n",
    "                    orientation: \"vertical\"\n",
    "                    spacing: dp(3)\n",
    "                    Label:\n",
    "                        text: \"Sensor value\"\n",
    "                        color: 0.42, 0.40, 0.34, 1\n",
    "                        font_size: sp(14)\n",
    "                        halign: \"left\"\n",
    "                        valign: \"bottom\"\n",
    "                        text_size: self.size\n",
    "                    Label:\n",
    "                        text: \"{} units\".format(int(root.sensor_value))\n",
    "                        color: 0.18, 0.20, 0.18, 1\n",
    "                        font_size: sp(34)\n",
    "                        bold: True\n",
    "                        halign: \"left\"\n",
    "                        valign: \"middle\"\n",
    "                        text_size: self.size\n",
    "                    Label:\n",
    "                        text: \"Mode: \" + root.mode\n",
    "                        color: 0.32, 0.35, 0.31, 1\n",
    "                        font_size: sp(15)\n",
    "                        halign: \"left\"\n",
    "                        valign: \"middle\"\n",
    "                        text_size: self.size\n",
    "                    Label:\n",
    "                        text: root.status_text\n",
    "                        color: 0.50, 0.43, 0.36, 1\n",
    "                        font_size: sp(13)\n",
    "                        halign: \"left\"\n",
    "                        valign: \"top\"\n",
    "                        text_size: self.size\n",
    "\n",
    "            SoftPanel:\n",
    "                orientation: \"vertical\"\n",
    "                size_hint_y: None\n",
    "                height: dp(94)\n",
    "                padding: dp(12), dp(10)\n",
    "                spacing: dp(8)\n",
    "                surface_color: 0.92, 0.95, 0.89, 1\n",
    "                Label:\n",
    "                    text: \"Operating mode\"\n",
    "                    color: 0.35, 0.37, 0.32, 1\n",
    "                    font_size: sp(14)\n",
    "                    bold: True\n",
    "                    size_hint_y: None\n",
    "                    height: dp(20)\n",
    "                    halign: \"left\"\n",
    "                    valign: \"middle\"\n",
    "                    text_size: self.size\n",
    "                BoxLayout:\n",
    "                    spacing: dp(8)\n",
    "                    PebbleButton:\n",
    "                        id: mode_eco\n",
    "                        text: \"Eco\"\n",
    "                    PebbleButton:\n",
    "                        id: mode_normal\n",
    "                        text: \"Normal\"\n",
    "                    PebbleButton:\n",
    "                        id: mode_boost\n",
    "                        text: \"Boost\"\n",
    "\n",
    "            SoftPanel:\n",
    "                orientation: \"vertical\"\n",
    "                size_hint_y: None\n",
    "                height: dp(98)\n",
    "                padding: dp(12), dp(10)\n",
    "                spacing: dp(5)\n",
    "                surface_color: 0.94, 0.93, 0.86, 1\n",
    "                BoxLayout:\n",
    "                    size_hint_y: None\n",
    "                    height: dp(25)\n",
    "                    Label:\n",
    "                        text: \"Sensitivity\"\n",
    "                        color: 0.35, 0.34, 0.30, 1\n",
    "                        font_size: sp(14)\n",
    "                        bold: True\n",
    "                        halign: \"left\"\n",
    "                        valign: \"middle\"\n",
    "                        text_size: self.size\n",
    "                    Label:\n",
    "                        text: \"{} percent\".format(int(root.sensitivity))\n",
    "                        color: 0.35, 0.34, 0.30, 1\n",
    "                        font_size: sp(14)\n",
    "                        bold: True\n",
    "                        halign: \"right\"\n",
    "                        valign: \"middle\"\n",
    "                        text_size: self.size\n",
    "                SoftSlider:\n",
    "                    id: sensitivity_slider\n",
    "                    value: root.sensitivity\n",
    "                    size_hint_y: None\n",
    "                    height: dp(48)\n",
    "\n",
    "            SoftPanel:\n",
    "                orientation: \"vertical\"\n",
    "                size_hint_y: None\n",
    "                height: dp(142)\n",
    "                padding: dp(12)\n",
    "                spacing: dp(10)\n",
    "                surface_color: 0.98, 0.94, 0.88, 1\n",
    "                Label:\n",
    "                    text: \"Controls\"\n",
    "                    color: 0.35, 0.34, 0.30, 1\n",
    "                    font_size: sp(14)\n",
    "                    bold: True\n",
    "                    size_hint_y: None\n",
    "                    height: dp(20)\n",
    "                    halign: \"left\"\n",
    "                    valign: \"middle\"\n",
    "                    text_size: self.size\n",
    "                GridLayout:\n",
    "                    cols: 2\n",
    "                    spacing: dp(9)\n",
    "                    PebbleButton:\n",
    "                        id: start_button\n",
    "                        text: \"Start\"\n",
    "                        active_color: 0.54, 0.78, 0.63, 1\n",
    "                    PebbleButton:\n",
    "                        id: pause_button\n",
    "                        text: \"Pause\"\n",
    "                        active_color: 0.86, 0.70, 0.50, 1\n",
    "                    PebbleButton:\n",
    "                        id: scan_button\n",
    "                        text: \"Scan\"\n",
    "                        active_color: 0.54, 0.74, 0.88, 1\n",
    "                    PebbleButton:\n",
    "                        id: reset_button\n",
    "                        text: \"Reset\"\n",
    "                        active_color: 0.94, 0.62, 0.55, 1\n",
    "\n",
    "            SoftPanel:\n",
    "                orientation: \"vertical\"\n",
    "                size_hint_y: None\n",
    "                height: dp(132)\n",
    "                padding: dp(12)\n",
    "                spacing: dp(8)\n",
    "                surface_color: 0.90, 0.94, 0.94, 1\n",
    "                BoxLayout:\n",
    "                    size_hint_y: None\n",
    "                    height: dp(47)\n",
    "                    spacing: dp(8)\n",
    "                    BoxLayout:\n",
    "                        orientation: \"vertical\"\n",
    "                        Label:\n",
    "                            text: \"Connection\"\n",
    "                            color: 0.39, 0.41, 0.38, 1\n",
    "                            font_size: sp(12)\n",
    "                            bold: True\n",
    "                            halign: \"left\"\n",
    "                            valign: \"bottom\"\n",
    "                            text_size: self.size\n",
    "                        Label:\n",
    "                            text: root.connection_text\n",
    "                            color: 0.22, 0.24, 0.22, 1\n",
    "                            font_size: sp(13)\n",
    "                            halign: \"left\"\n",
    "                            valign: \"top\"\n",
    "                            text_size: self.size\n",
    "                    BoxLayout:\n",
    "                        orientation: \"vertical\"\n",
    "                        size_hint_x: 0.52\n",
    "                        Label:\n",
    "                            text: \"Packets\"\n",
    "                            color: 0.39, 0.41, 0.38, 1\n",
    "                            font_size: sp(12)\n",
    "                            bold: True\n",
    "                            halign: \"right\"\n",
    "                            valign: \"bottom\"\n",
    "                            text_size: self.size\n",
    "                        Label:\n",
    "                            text: str(int(root.packet_count))\n",
    "                            color: 0.22, 0.24, 0.22, 1\n",
    "                            font_size: sp(20)\n",
    "                            bold: True\n",
    "                            halign: \"right\"\n",
    "                            valign: \"top\"\n",
    "                            text_size: self.size\n",
    "                Label:\n",
    "                    text: root.signal_text + \"  \" + root.progress_text\n",
    "                    color: 0.33, 0.38, 0.36, 1\n",
    "                    font_size: sp(13)\n",
    "                    size_hint_y: None\n",
    "                    height: dp(20)\n",
    "                    halign: \"left\"\n",
    "                    valign: \"middle\"\n",
    "                    text_size: self.size\n",
    "                SoftProgress:\n",
    "                    progress: root.progress\n",
    "                    running: root.scanning\n",
    "                    size_hint_y: None\n",
    "                    height: dp(24)\n",
    "\n",
    "            SoftPanel:\n",
    "                orientation: \"vertical\"\n",
    "                size_hint_y: None\n",
    "                height: dp(150)\n",
    "                padding: dp(12)\n",
    "                spacing: dp(6)\n",
    "                surface_color: 0.97, 0.92, 0.86, 1\n",
    "                Label:\n",
    "                    text: \"Recent log\"\n",
    "                    color: 0.35, 0.34, 0.30, 1\n",
    "                    font_size: sp(14)\n",
    "                    bold: True\n",
    "                    size_hint_y: None\n",
    "                    height: dp(22)\n",
    "                    halign: \"left\"\n",
    "                    valign: \"middle\"\n",
    "                    text_size: self.size\n",
    "                ScrollView:\n",
    "                    id: log_scroll\n",
    "                    do_scroll_x: False\n",
    "                    bar_width: dp(2)\n",
    "                    Label:\n",
    "                        id: event_log\n",
    "                        text: root.log_text\n",
    "                        color: 0.31, 0.30, 0.27, 1\n",
    "                        font_size: sp(12)\n",
    "                        line_height: 1.12\n",
    "                        halign: \"left\"\n",
    "                        valign: \"top\"\n",
    "                        text_size: self.width, None\n",
    "                        size_hint_y: None\n",
    "                        height: self.texture_size[1] + dp(8)\n",
    "\"\"\"\n",
    "\n",
    "\n",
    "class SensorDemoController:\n",
    "    def __init__(self, ui):\n",
    "        self.ui = ui\n",
    "        self.phase = 0.0\n",
    "        self.logs = []\n",
    "        self.sensor_event = None\n",
    "        self.scan_event = None\n",
    "        self.cleaned = False\n",
    "        self.modes = {\n",
    "            \"Eco\": {\"base\": 34, \"speed\": 0.75},\n",
    "            \"Normal\": {\"base\": 52, \"speed\": 1.0},\n",
    "            \"Boost\": {\"base\": 70, \"speed\": 1.35},\n",
    "        }\n",
    "\n",
    "        ui.ids.start_button.bind(on_release=self.start)\n",
    "        ui.ids.pause_button.bind(on_release=self.pause)\n",
    "        ui.ids.reset_button.bind(on_release=self.reset)\n",
    "        ui.ids.scan_button.bind(on_release=self.trigger_scan)\n",
    "        ui.ids.mode_eco.bind(on_release=lambda instance: self.set_mode(\"Eco\"))\n",
    "        ui.ids.mode_normal.bind(on_release=lambda instance: self.set_mode(\"Normal\"))\n",
    "        ui.ids.mode_boost.bind(on_release=lambda instance: self.set_mode(\"Boost\"))\n",
    "        ui.ids.sensitivity_slider.bind(value=self.on_sensitivity)\n",
    "\n",
    "        self.sensor_event = Clock.schedule_interval(self.update_sensor, 0.22)\n",
    "        self.set_mode(\"Normal\", log_event=False)\n",
    "        self.add_log(\"Demo ready\")\n",
    "        self.store_state()\n",
    "\n",
    "    def cleanup(self):\n",
    "        self.cleaned = True\n",
    "        if self.sensor_event is not None:\n",
    "            self.sensor_event.cancel()\n",
    "            self.sensor_event = None\n",
    "        if self.scan_event is not None:\n",
    "            self.scan_event.cancel()\n",
    "            self.scan_event = None\n",
    "\n",
    "    def add_log(self, message):\n",
    "        stamp = time.strftime(\"%H:%M:%S\")\n",
    "        self.logs.insert(0, stamp + \"  \" + message)\n",
    "        self.logs = self.logs[:8]\n",
    "        self.ui.log_text = \"\\n\".join(self.logs)\n",
    "        self.store_state()\n",
    "\n",
    "    def store_state(self):\n",
    "        globals()[\"live_sensor_demo_state\"] = {\n",
    "            \"ok\": True,\n",
    "            \"running\": bool(self.ui.running),\n",
    "            \"scanning\": bool(self.ui.scanning),\n",
    "            \"sensor_value\": round(float(self.ui.sensor_value), 2),\n",
    "            \"sensitivity\": round(float(self.ui.sensitivity), 2),\n",
    "            \"mode\": str(self.ui.mode),\n",
    "            \"progress\": round(float(self.ui.progress), 3),\n",
    "            \"status\": str(self.ui.status_text),\n",
    "            \"connection\": str(self.ui.connection_text),\n",
    "            \"signal\": str(self.ui.signal_text),\n",
    "            \"packets\": int(self.ui.packet_count),\n",
    "            \"recent_log\": list(self.logs),\n",
    "        }\n",
    "\n",
    "    def update_buttons(self):\n",
    "        self.ui.ids.mode_eco.active = self.ui.mode == \"Eco\"\n",
    "        self.ui.ids.mode_normal.active = self.ui.mode == \"Normal\"\n",
    "        self.ui.ids.mode_boost.active = self.ui.mode == \"Boost\"\n",
    "        self.ui.ids.start_button.active = self.ui.running and not self.ui.scanning\n",
    "        self.ui.ids.pause_button.active = not self.ui.running and not self.ui.scanning\n",
    "        self.ui.ids.scan_button.active = self.ui.scanning\n",
    "        self.ui.ids.reset_button.active = False\n",
    "        self.ui.ids.scan_button.text = \"Scanning\" if self.ui.scanning else \"Scan\"\n",
    "\n",
    "    def set_mode(self, mode_name, log_event=True):\n",
    "        if mode_name not in self.modes:\n",
    "            return\n",
    "        self.ui.mode = mode_name\n",
    "        self.ui.status_text = \"Mode set to \" + mode_name\n",
    "        self.update_buttons()\n",
    "        if log_event:\n",
    "            self.add_log(\"Mode changed to \" + mode_name)\n",
    "        self.store_state()\n",
    "\n",
    "    def on_sensitivity(self, slider, value):\n",
    "        self.ui.sensitivity = max(0, min(100, value))\n",
    "        self.ui.status_text = \"Sensitivity adjusted\"\n",
    "        if int(value) % 10 == 0:\n",
    "            self.store_state()\n",
    "        self.update_buttons()\n",
    "\n",
    "    def start(self, *args):\n",
    "        self.ui.running = True\n",
    "        self.ui.status_text = \"Monitoring active\"\n",
    "        self.ui.connection_text = \"Link: virtual sensor online\"\n",
    "        self.ui.signal_text = \"Signal: streaming\"\n",
    "        self.update_buttons()\n",
    "        self.add_log(\"Monitoring started\")\n",
    "\n",
    "    def pause(self, *args):\n",
    "        self.ui.running = False\n",
    "        self.ui.status_text = \"Monitoring paused\"\n",
    "        self.ui.signal_text = \"Signal: holding\"\n",
    "        self.update_buttons()\n",
    "        self.add_log(\"Monitoring paused\")\n",
    "\n",
    "    def reset(self, *args):\n",
    "        if self.scan_event is not None:\n",
    "            self.scan_event.cancel()\n",
    "            self.scan_event = None\n",
    "        self.ui.running = False\n",
    "        self.ui.scanning = False\n",
    "        self.ui.progress = 0\n",
    "        self.ui.progress_text = \"Scan: idle\"\n",
    "        self.ui.sensor_value = 42\n",
    "        self.ui.packet_count = 0\n",
    "        self.ui.sensitivity = 55\n",
    "        self.ui.ids.sensitivity_slider.value = 55\n",
    "        self.phase = 0.0\n",
    "        self.set_mode(\"Normal\", log_event=False)\n",
    "        self.ui.status_text = \"Reset complete\"\n",
    "        self.ui.signal_text = \"Signal: calm\"\n",
    "        self.update_buttons()\n",
    "        self.add_log(\"System reset\")\n",
    "\n",
    "    def trigger_scan(self, *args):\n",
    "        if self.ui.scanning:\n",
    "            self.add_log(\"Scan already running\")\n",
    "            return\n",
    "        self.ui.scanning = True\n",
    "        self.ui.progress = 0\n",
    "        self.ui.progress_text = \"Scan: 0 percent\"\n",
    "        self.ui.status_text = \"Scan running\"\n",
    "        self.ui.signal_text = \"Signal: sampling\"\n",
    "        if self.scan_event is not None:\n",
    "            self.scan_event.cancel()\n",
    "        self.scan_event = Clock.schedule_interval(self.update_scan, 0.08)\n",
    "        self.update_buttons()\n",
    "        self.add_log(\"Simulated scan started\")\n",
    "\n",
    "    def update_scan(self, dt):\n",
    "        if self.cleaned:\n",
    "            return False\n",
    "        self.ui.progress = min(1, self.ui.progress + dt / 4.0)\n",
    "        self.ui.progress_text = \"Scan: {} percent\".format(int(self.ui.progress * 100))\n",
    "        if self.ui.progress >= 1:\n",
    "            self.ui.progress = 1\n",
    "            self.ui.scanning = False\n",
    "            self.ui.status_text = \"Scan complete\"\n",
    "            self.ui.signal_text = \"Signal: stable\"\n",
    "            self.ui.progress_text = \"Scan: complete\"\n",
    "            if self.scan_event is not None:\n",
    "                self.scan_event.cancel()\n",
    "                self.scan_event = None\n",
    "            self.update_buttons()\n",
    "            self.add_log(\"Scan completed\")\n",
    "            return False\n",
    "        self.store_state()\n",
    "        return True\n",
    "\n",
    "    def update_sensor(self, dt):\n",
    "        if self.cleaned:\n",
    "            return False\n",
    "        if not self.ui.running and not self.ui.scanning:\n",
    "            self.store_state()\n",
    "            return True\n",
    "\n",
    "        mode_info = self.modes.get(self.ui.mode, self.modes[\"Normal\"])\n",
    "        self.phase += dt * mode_info[\"speed\"] * (0.8 + self.ui.sensitivity / 80.0)\n",
    "\n",
    "        sensitivity_ratio = self.ui.sensitivity / 100.0\n",
    "        wave = sin(self.phase) * (8 + 18 * sensitivity_ratio)\n",
    "        fine_wave = sin(self.phase * 2.7) * (2 + 5 * sensitivity_ratio)\n",
    "        jitter = uniform(-1.2, 1.2) * (0.4 + sensitivity_ratio)\n",
    "        scan_lift = 6 * sin(self.ui.progress * 3.14159) if self.ui.scanning else 0\n",
    "\n",
    "        value = mode_info[\"base\"] + wave + fine_wave + jitter + scan_lift\n",
    "        self.ui.sensor_value = max(0, min(100, value))\n",
    "        self.ui.packet_count += 1\n",
    "\n",
    "        if self.ui.scanning:\n",
    "            self.ui.status_text = \"Scanning sensor field\"\n",
    "            self.ui.signal_text = \"Signal: sampling\"\n",
    "        elif self.ui.running:\n",
    "            if self.ui.sensor_value > 82:\n",
    "                self.ui.status_text = \"High reading\"\n",
    "                self.ui.signal_text = \"Signal: lively\"\n",
    "            elif self.ui.sensor_value < 25:\n",
    "                self.ui.status_text = \"Low reading\"\n",
    "                self.ui.signal_text = \"Signal: quiet\"\n",
    "            else:\n",
    "                self.ui.status_text = \"Monitoring active\"\n",
    "                self.ui.signal_text = \"Signal: stable\"\n",
    "\n",
    "        self.store_state()\n",
    "        return True\n",
    "\n",
    "\n",
    "def build_live_sensor_demo():\n",
    "    ui = Builder.load_string(KV)\n",
    "    if ui is None:\n",
    "        raise RuntimeError(\"Builder.load_string returned None for sensor demo UI\")\n",
    "\n",
    "    controller = SensorDemoController(ui)\n",
    "\n",
    "    def cleanup_live_sensor_demo():\n",
    "        controller.cleanup()\n",
    "\n",
    "    globals()[\"live_sensor_demo_ui\"] = ui\n",
    "    globals()[\"live_sensor_demo_controller\"] = controller\n",
    "    globals()[\"live_sensor_demo_cleanup\"] = cleanup_live_sensor_demo\n",
    "\n",
    "    root.clear_widgets()\n",
    "    root.add_widget(ui)\n",
    "    return ui\n",
    "\n",
    "\n",
    "try:\n",
    "    build_live_sensor_demo()\n",
    "except Exception as exc:\n",
    "    Logger.exception(\"PythonHere: Could not build live sensor demo\")\n",
    "    globals()[\"pythonhere_last_error\"] = {\n",
    "        \"stage\": \"build_live_sensor_demo\",\n",
    "        \"error\": f\"{type(exc).__name__}: {exc}\",\n",
    "    }\n",
    "    popup = Popup(\n",
    "        title=\"Sensor demo error\",\n",
    "        content=Label(\n",
    "            text=\"Could not build the sensor demo.\\n\" + f\"{type(exc).__name__}: {exc}\",\n",
    "            halign=\"center\",\n",
    "            valign=\"middle\",\n",
    "        ),\n",
    "        size_hint=(0.88, 0.42),\n",
    "    )\n",
    "    popup.open()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "36d15943",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-06-06T23:24:28.674576Z",
     "iopub.status.busy": "2026-06-06T23:24:28.674206Z",
     "iopub.status.idle": "2026-06-06T23:24:30.879046Z",
     "shell.execute_reply": "2026-06-06T23:24:30.878633Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/jpeg": "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",
      "image/png": "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",
      "text/plain": [
       "<PIL.Image.Image image mode=RGB size=250x491>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%there -d 1 screenshot -w 250"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c9cbe1bd",
   "metadata": {},
   "source": [
    "## Override the session stack\n",
    "\n",
    "Use `set_ai_prompts(...)` when a notebook should use a different base prompt\n",
    "stack for every request in the current kernel session:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "c59c2781",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-06-06T23:24:30.880972Z",
     "iopub.status.busy": "2026-06-06T23:24:30.880819Z",
     "iopub.status.idle": "2026-06-06T23:24:30.883069Z",
     "shell.execute_reply": "2026-06-06T23:24:30.882792Z"
    }
   },
   "outputs": [],
   "source": [
    "from herethere.there.ai import clear_ai_prompts, set_ai_prompts\n",
    "\n",
    "set_ai_prompts(\"default\", \"kivy-runtime\", \"style\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f7867878",
   "metadata": {},
   "source": [
    "Clear the session override to return to the configured default stack:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "94241483",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-06-06T23:24:30.884691Z",
     "iopub.status.busy": "2026-06-06T23:24:30.884456Z",
     "iopub.status.idle": "2026-06-06T23:24:30.886393Z",
     "shell.execute_reply": "2026-06-06T23:24:30.886100Z"
    }
   },
   "outputs": [],
   "source": [
    "clear_ai_prompts()"
   ]
  }
 ],
 "metadata": {
  "jupytext": {
   "default_lexer": "yaml"
  },
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "there-ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
