agentsclimarketplace

Pythonide appui

Skill Python-IDE/pythonide-skills/pythonide-appui

Official Agent Skills for building PythonIDE AppUI MiniApps, widgets, automations, and native iOS integrations with Codex, Cursor, and Claude Code.

Install
npx -y skills add Python-IDE/pythonide-skills --skill pythonide-appui

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 5 stars5 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Build or modify PythonIDE AppUI MiniApps with native navigation, forms, lists, search, tabs, toolbars, presentation, storage, and AppUI media bridges. Use when the user wants an interactive iOS MiniApp, settings screen, list/detail app, or native UI that may also need photos, camera, location, maps, video, or share.

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

8.4 KB, as published. Nobody here has run it

PythonIDE AppUI

Execution rulebook for native AppUI MiniApps. Pair with pythonide-native whenever the workflow touches iOS permissions, sensors, media capture, networking side effects, or secure storage.

Read Before Coding

  1. appui quickstart
  2. AppUI module
  3. UI patterns
  4. AppUI schema and appui.pyi for signatures
  5. llms-full.txt when unsure about exported symbols
  6. Load pythonide-native before importing any photos, location, permission, notification, etc.

Chinese module pages on pythonide.xin are valid deep references for scenarios and examples.

Workflow

  1. Confirm AppUI is the right runtime (pythonide router). Do not use AppUI for widgets or frame-loop games.
  2. Choose structure first: Form, List, TabView, NavigationStack, dashboard ScrollView.
  3. Define module-level appui.State or ReactiveState.
  4. Write named zero-argument callbacks; callbacks mutate state or call native APIs.
  5. Keep body() pure: return a view tree only. No permissions, network, storage writes, notifications, timers started, or navigation side effects inside body().
  6. End with exactly one appui.run(body, state=state, presentation=...).
  7. For editable business data, use storage.get_json(..., default) only for small settings; use database for queryable records, caches, favorites, history, playlists, or large lists.

Entry Pattern

import appui

state = appui.State(count=0, status="Ready")


def increment():
    state.count += 1
    state.status = "Updated"


def body():
    return appui.NavigationStack(
        appui.Form([
            appui.Section("Counter", [
                appui.LabeledContent("Value", value=str(state.count)),
                appui.Button("+1", action=increment).button_style("bordered_prominent"),
            ], footer=state.status),
        ]).navigation_title("Counter")
    )


appui.run(body, state=state, presentation="fullscreen_with_close")

Presentation

Use casepresentation
Full app / tool with close affordancefullscreen_with_close
Lightweight utilitysheet
Default when unsure for a real appfullscreen_with_close

Structure Rules

  • Settings, account, checkout, profile: Form + Section
  • Dynamic rows: List + ForEach with stable key
  • Master-detail: NavigationStack + NavigationLink
  • Product areas: TabView + Tab, each tab owns a NavigationStack
  • Continuing bottom tasks: TabView + .tab_view_bottom_accessory(...) + .sheet(...)
  • Use .tab_view_bottom_accessory for the compact persistent row and .sheet(detents=..., drag_indicator=...) for the full panel. Do not invent an expandable bottom accessory API.
  • Search: native .searchable(...); do not hand-roll search bars
  • Toolbar actions in fullscreen apps; fullscreen_with_close already provides close
  • Stable item IDs; mutate by id, never by filtered index
  • Do not nest List inside ScrollView, Section, or another scrolling container

Layout And Styling

  • Target iPhone width ~390 pt; avoid fixed widths above 360 pt
  • Padding usually 8–20 pt
  • Use semantic system colors: systemBackground, label, secondaryLabel, systemBlue, etc.
  • Do not hard-code hex/RGB unless the API requires it
  • Ordinary rows/settings/todos should stay List/Form native-first; reserve custom dashboard layouts for true dashboard/media surfaces
  • Use .tab_view_bottom_accessory plus .sheet for persistent playback, podcast, recording, download, timer, or navigation state instead of making that ongoing task a dedicated tab

Native Integration

Also load pythonide-native for any capability below.

Hard Rules

  • nativeCallsStayOutOfAppUIBody: permission prompts, GPS, capture, notifications, and network side effects belong in named callbacks, .refreshable, or .task — never in body()
  • Prefer AppUI bridge components before imperative modules when the control is inline in the UI
  • AppUI embedded video: PlayerController + VideoPlayer; do not use import avplayer unless the user explicitly wants script-level playback
  • Secrets → keychain; small settings → storage; queryable records → database
  • Do not import CPython sqlite3 directly in MiniApps; use database

AppUI Bridge Components

<!-- BEGIN GENERATED: appui-bridge-table -->
BridgeAppUI componentRelated modulesDoc
camera_pickerappui.CameraPickerphotoscamera-module
file_importerappui.FileImporter-file-picker-module
map_viewappui.MapViewlocation, permissionlocation-module
photo_pickerappui.PhotoPickerphotosphotos-module
player_controllerappui.PlayerControlleravplayerappui-ref-media
share_linkappui.ShareLink-share-module
video_playerappui.VideoPlayeravplayerappui-ref-media
web_viewappui.WebView-appui-ref-media
<!-- END GENERATED: appui-bridge-table -->

Bridge Vs Module

NeedPrefer
Inline photo pick in a formappui.PhotoPicker
Inline camera capture buttonappui.CameraPicker
Map preview in a screenappui.MapView + pythonide-native for location callbacks
Share a file or textappui.ShareLink
Batch asset processing, save to library, background fetchimport photos in callback
GPS updates, geocoding, headingimport location in callback
Local notificationsimport notification in callback

Callbacks And Runtime

  • Prefer named zero-argument callbacks
  • Wrong: Button(action=open(item)) or row.on_tap(save(i)) — runs during view construction
  • Row callbacks should capture stable item IDs
  • Timers at module scope with action= at construction; never Timer(action=None) then assign later
  • High-frequency sensors, camera streams, waveforms → consider Aurora realtime docs; do not rebuild the whole tree every frame in a tight loop

Hard Stops

  • No HTML/WebView unless the user explicitly needs web content
  • No lambda callbacks in deliverable code
  • No children= for VStack/HStack; pass child lists positionally
  • No NavigationStack([...]); one root view only
  • No ScrollView(VStack(...)) for ordinary lists → use List(ForEach(...))
  • No dedicated playback/download/recording tab when the expected product pattern is a compact bottom bar that expands into a full panel
  • No Image(...).on_tap(...) as a button → use Button
  • No guessed SwiftUI-only APIs; verify against schema/stubs
  • No tkinter, PyQt, Flask, Streamlit, or browser frameworks

Common Mistakes

SymptomFix
Dead buttonNamed zero-arg callback instead of eager invocation
Wrong row after search/filterStable ids + ForEach(..., key=...)
Permission dialog on launchMove native call into button callback
Blank previewEnsure body() returns a View and appui.run(...) is present
Shared search across tabsSeparate per-tab query state

Examples

  • examples/counter/ — minimal Form + persistence-ready structure
  • examples/photo_notes/ — AppUI shell + PhotoPicker + storage

Validation

Done means: runnable AppUI code, documented APIs only, appui.run(...) present, named callbacks for side effects, and honest reporting if editor-side preview cannot be executed.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.