--- name: reefy-develop description: Create, build, publish, run or update a custom app on an owned Reefy device using a private project and the existing Reefy connection. --- # Develop and run a Reefy app Use the existing Reefy connection. Do not ask users to install another plugin, connect a development server, copy credentials, or use SSH. User-facing replies should name their app; the development service is an implementation detail. 1. Resolve the owned device and requested app. Call `prepare_private_app_project(device_uuid,name,request_id)` with a stable unique request ID. If pending, reuse that same request and name after a bounded wait. Never create duplicate projects to check readiness. Keep the returned project ID for later edits. 2. When ready, call `get_private_app_project_connection(project_id)`. Save exactly its returned object in a private mode-0600 temporary JSON file in your cloud workspace. Never print credentials, put them in a URL, Git remote, command arguments, project source, logs or user-facing messages. If the host requires incremental development/catalog consent, use its normal permission flow; never ask for the user's password or manually alter OAuth URLs. 3. Author and test the source in a local Git working copy. Read [the project format](references/project-format.md). Commit the complete project, including Dockerfile and reefy/app.json. Keep source, Git history and app data separate. Do not rely on the cloud workspace as the only durable source copy. 4. Push directly to the returned project Git endpoint with the unmodified bundled `scripts/push_project.py --connection --endpoint --repo `. This helper uses temporary process authentication, TLS verification and no redirects. It does not send source through the main Reefy tools. Delete the private connection file in a finally block. Keep its returned exact commit and verify pushed:true. Refresh expired credentials through the connection tool, not by weakening validation. Never force-push or put credentials in Git config. 5. Call `publish_private_app_project(project_id,commit,request_id)` once per exact requested revision. Reuse that request ID on ambiguous retries. Read `get_private_app_project_operation` for that publication until published or failed, with bounded waits rather than a tight loop. Build/publication has no promised event trigger: do not invent one. A timeout is uncertainty, not failure or permission to duplicate publication. A published result is a catalog release, not a running app. 6. Use returned app_id/release_id with `install_private_app` for the first runtime, or `update_private_app` for the existing instance of that app. Never create another runtime for an edit. Follow the returned installation operation with the setup skill's existing status-card/event flow. Only actual device verification establishes readiness. Show a usable Open app action in the completion reply itself; never refer to an absent card. A failed build must leave the existing runtime and saved data unchanged. 7. Retain project ID, app ID, instance ID, commit, release ID and request IDs in conversation context for updates. Keep the same persistent volume layout across releases. Version each release; do not mutate an already published version. AppMother's backed-up project repository is the persistent source copy; deleting it can lose source even when published apps keep running. During Voice, briefly acknowledge each actual milestone. Say the app is ready only after verified installation. Show the Open app action in the written chat; never dictate its URL. Do not claim a written event continuation was spoken. If the host cannot continue speaking after tool work, explain the limitation once and retain written/card monitoring. Never fabricate narration, readiness or a second native connection to make the flow appear complete.