Skip to content

Latest commit

 

History

History
626 lines (484 loc) · 34.5 KB

File metadata and controls

626 lines (484 loc) · 34.5 KB

OpenPet Extension Development

OpenPet is moving toward a developer-first local extension platform. An extension can be a small pet command, a long-running companion service, a local dashboard, a writing assistant, a weather announcer, a pet animation tool, or a package that orchestrates local models and generated assets.

This document follows the extension ecosystem boundary design. It is the target author guide for new development. Existing JavaScript SDK plugins remain a compatibility path while the host runtime catches up to the broader extension model.

For lifecycle, safety, and review language, read plugin-ecosystem-rules.md together with this guide.

Author Capability Promise

OpenPet should feel like a welcoming local extension platform, not a closed list of first-party feature slots.

Third-party authors are encouraged to build practical pet experiences such as:

  • a weather announcer where the pet speaks the forecast, plays a matching action, and opens a dashboard;
  • a pet dialogue pack that adds configurable phrases, tone, timing, and fallback lines;
  • a personality injector that changes how a pet responds without modifying OpenPet core code;
  • an action studio that inspects frame folders, validates action metadata, imports new actions, and regenerates sprites through host-mediated creator tools;
  • a local model or image workflow that generates pet action art into package/data locations and asks the host to import the approved result;
  • a service-backed companion that watches RSS, calendar, build status, local files, or third-party APIs and turns them into pet speech/actions.

The current host intentionally gives declaration-only command entries a bounded but useful bridge instead of forcing every author into a JavaScript SDK. Authors can combine their own runtime, local files, external APIs, dashboards, services, and setup flows with OpenPet-owned bridge calls for pet speech, pet actions, pet events, read-only context, action configuration, pack manifest metadata, and action frame import.

This is a permissioned collaboration model:

  • authors may choose JavaScript, Python, shell scripts, compiled binaries, or other local runtimes;
  • OpenPet mediates pet mutations and creator-tool writes through explicit bridge permissions;
  • OpenPet should reject unsafe package structure and hidden install-time execution;
  • OpenPet should not reject useful third-party ideas merely because they are not first-party features yet.

Core Model

OpenPet uses one package model: an extension.

The package root still contains:

plugin.json

plugin.json is the unified manifest for all extension shapes. The word "plugin" remains in file names and some commands for compatibility, but new product and developer language should use "extension" when describing the ecosystem.

OpenPet should treat the manifest as a declaration and operational contract, not as a complete sandbox. It can validate package structure, show the user what the extension declares, start/stop entries, capture logs, and uninstall OpenPet-owned files. It should not claim to fully control everything a local process can do.

Package Layout

An extension may be tiny:

my-extension/
├── plugin.json
├── config.schema.json
└── commands/
    └── announce.js

It may also be a fuller local app:

my-extension/
├── plugin.json
├── config.schema.json
├── commands/
├── service/
├── web/
├── templates/
├── static/
├── assets/
├── bin/
├── models/
└── README.md

OpenPet should preserve structural safety:

  • plugin.json must be at package root.
  • Entry paths and package-relative files must stay inside the installed package.
  • Absolute paths, path traversal, unsafe zip entries, and escaping symlinks are rejected.
  • Installation must not overwrite OpenPet application files.
  • Install only extracts and inspects; extension code should not run during install.

Creator Tools Example: Creator Studio

examples/plugins/creator-studio/ demonstrates a hybrid creator-tools extension. It creates durable pet-generation runs under OPENPET_DATA_DIR, produces a valid codex-pet fixture output, requires explicit approval, and imports the approved output through OpenPet's host-owned pet-pack bridge.

The example intentionally uses a deterministic fixture backend first. Creator Studio now treats model-backed generation as one host-owned provider path while still accepting legacy cloud / local inputs as compatibility aliases. When Creator Studio uses model-backed generation, that generation remains host-managed: the command gets a short-lived bridge token for bounded host routes, OpenPet keeps provider credentials in main-process secret storage, and plugin-managed provider credentials are currently unsupported in the author-facing trust model.

Provider-backed generation evidence proves the host bridge, provider call, and asset QA pipeline are wired. It does not prove final pet visual identity; production-quality generated pets still require human review or a future explicit visual-fidelity gate showing the output stays highly consistent with the user's original image.

Manifest Shape

Use this first-version shape for new extension design:

{
  "id": "weather-morning-report",
  "name": "Weather Morning Report",
  "version": "1.0.0",
  "description": "Weather reports, Web dashboard, and Email delivery for OpenPet.",
  "entries": {
    "commands": [],
    "services": [],
    "dashboards": []
  },
  "manifest": {},
  "config": "config.schema.json",
  "assets": []
}

Important fields:

  • id: stable extension id.
  • name: user-facing name.
  • version: extension version.
  • description: short user-facing purpose.
  • entries: commands, services, and dashboards OpenPet can run, manage, or open.
  • manifest: structured declaration area shown to users.
  • config: optional package-relative configuration schema.
  • assets: meaningful package assets such as templates, static files, model assets, generated pet art, docs, or examples.

Recommended id pattern:

<namespace>.<extension-name>

Examples:

  • community.weather-morning-report
  • com.yourname.pet-action-studio
  • openpet.example.focus-timer

Entries

Entries describe what OpenPet can start, run, or open. They do not create separate package types.

Commands

Commands are explicit short-lived process entries. They are triggered from OpenPet UI or another explicit host action, not during install or enable.

{
  "id": "announce-weather",
  "title": "Announce Weather",
  "command": "node ./commands/announce-weather.js",
  "cwd": "."
}

OpenPet currently:

  • runs the command in the installed extension directory;
  • rejects cwd paths or symlinks that escape the extension directory;
  • spawns the process without shell expansion;
  • passes command context as stdin JSON with pluginId, commandId, payload, config, and paths.extensionDir;
  • captures stdout and stderr snippets into plugin logs;
  • parses the final stdout JSON line as the command result when possible;
  • times out stalled command processes.

Commands may be written in JavaScript, Python, shell scripts, compiled binaries, or any runtime the user has installed. JavaScript is supported as one ordinary process option, not as the only extension runtime.

Services

Services are long-running local process entries managed by OpenPet.

{
  "id": "companion",
  "name": "Weather Companion Service",
  "command": "npm run service:start",
  "cwd": ".",
  "platforms": {
    "darwin": { "command": "npm run service:start" },
    "win32": { "command": "npm run service:start:win" },
    "linux": { "command": "npm run service:start" }
  },
  "health": {
    "type": "http",
    "url": "http://127.0.0.1:8787/health"
  }
}

OpenPet can explicitly run command and setup entries from Control Center, capture stdout/stderr snippets, show setup runtime state, explicitly start and stop services, show service runtime state, stop services on plugin disable, send stop signals on app quit, manually check declared loopback health endpoints, and optionally schedule host-managed periodic checks for running services from Control Center. It can attempt best-effort process-group cleanup when stopping services, wait for confirmed child exit before reporting a clean stop, escalate once to a host-side force stop if a service ignores the grace-period shutdown request, and try a host-owned process-tree cleanup path before falling back to direct child kill. Services remain the strongest cleanup shape because they combine process-group signalling, process-tree fallback, bounded force-stop escalation, and a service-scoped bridge for long-running pet/context integration. Declaration-only command runs also receive a short-lived command bridge URL/token so they can call pet.say, pet.action, pet.event, creator-tool routes, and fetch a bounded read-only context during the active run. Service runs receive a separate service bridge URL/token for context and pet routes only; service bridge tokens expire when the service leaves running or stop is requested. Command and setup cleanup keep stop intent visible until child exit confirmation and now also try the same host-owned tree cleanup before direct child kill fallback, but they still do not add service-style process groups or force-stop escalation. Command, setup, and service processes do not run during install or enable; services never auto-start; periodic health checks only run for already running services when the user enables the host policy; and the host spawns command, setup, and service processes without shell expansion. OpenPet still does not claim universal process-tree cleanup guarantees across every host/runtime combination. The service model should not require a specific language, a self-contained package, or a full process sandbox.

Dashboards

Dashboards are user-facing URLs or local service pages.

{
  "id": "main",
  "title": "Weather Dashboard",
  "url": "http://127.0.0.1:8787"
}

First-version behavior should stay simple: OpenPet shows an "Open Dashboard" action and opens the URL externally or in a separate app window. OpenPet does not need to host, iframe, theme, or inspect the dashboard.

Context Passing

OpenPet should use language-neutral context passing.

Current command entries receive context on stdin and run with a minimal host environment. Declaration-only command runs now also receive a short-lived command bridge URL/token pair plus host-owned OPENPET_DATA_DIR, OPENPET_CACHE_DIR, and OPENPET_LOG_DIR paths. Declaration-only service runs receive the same host-owned directory paths plus a separate service bridge URL/token pair. OpenPet still does not inject generated config files or result-file paths into command or service processes.

Current standard environment variables:

Variable Purpose
OPENPET_BRIDGE_URL Short-lived local bridge endpoint for the active declaration-only command run.
OPENPET_BRIDGE_TOKEN Bearer token for the active declaration-only command bridge.
OPENPET_SERVICE_BRIDGE_URL Runtime-scoped local bridge endpoint for the active declaration-only service run.
OPENPET_SERVICE_BRIDGE_TOKEN Bearer token for the active declaration-only service bridge.
OPENPET_DATA_DIR Host-owned persistent data directory for the active declaration-only command or service run.
OPENPET_CACHE_DIR Host-owned cache directory for the active declaration-only command or service run.
OPENPET_LOG_DIR Host-owned log directory for the active declaration-only command or service run.

Reserved future variables only:

Variable Purpose
OPENPET_EXTENSION_ID Current extension id.
OPENPET_EXTENSION_DIR Installed package directory.
OPENPET_CONFIG_PATH Optional generated config JSON path.
OPENPET_RESULT_PATH Command result JSON output path.

Commands receive JSON on stdin:

{
  "pluginId": "weather-morning-report",
  "commandId": "announce-weather",
  "payload": {},
  "config": {},
  "paths": {
    "extensionDir": "..."
  }
}

Current command result:

  • write JSON as the final stdout line.

Current bridge routes:

  • GET /context
  • POST /pet/say
  • POST /pet/action
  • POST /pet/event
  • GET /creator/actions
  • POST /creator/actions/validate
  • POST /creator/actions/apply
  • POST /creator/trigger-proposals/submit
  • GET /creator/pack-manifest
  • POST /creator/pack-manifest/validate
  • POST /creator/pack-manifest/apply
  • POST /creator/assets/inspect-frames
  • POST /creator/assets/import-frames
  • POST /creator/assets/pick-frames/inspect
  • POST /creator/assets/pick-frames/import
  • POST /creator/pet-pack/inspect-output
  • POST /creator/pet-pack/import-output
  • GET /creator/model-settings
  • POST /creator/model-health-check
  • POST /creator/model-image-generate
  • POST /creator/hatch-pet/plan
  • POST /creator/hatch-pet/evaluate

The bridge is loopback-only for command runs, token-gated, and valid only while the command run is active. The service bridge uses a separate URL/token pair and is valid only while the service runtime is active; it expires immediately when stop is requested.

OpenPet may interpret common result keys:

{
  "ok": true,
  "message": "Report sent.",
  "petSay": "今天有雨,邮件已发送。",
  "petAction": "umbrella",
  "dashboardUrl": "http://127.0.0.1:8787/reports/latest"
}

Optional Bridge

For deeper pet integration, OpenPet now provides minimal optional local bridges for explicit declaration-only command and service runs. These bridges are not a heavy SDK and should not become a full permission broker in the first version.

Injected values:

  • OPENPET_BRIDGE_URL
  • OPENPET_BRIDGE_TOKEN
  • OPENPET_SERVICE_BRIDGE_URL
  • OPENPET_SERVICE_BRIDGE_TOKEN
  • OPENPET_DATA_DIR
  • OPENPET_CACHE_DIR
  • OPENPET_LOG_DIR

Current endpoint set:

  • GET /context
  • POST /pet/say
  • POST /pet/action
  • POST /pet/event
  • GET /creator/actions
  • POST /creator/actions/validate
  • POST /creator/actions/apply
  • POST /creator/trigger-proposals/submit
  • GET /creator/pack-manifest
  • POST /creator/pack-manifest/validate
  • POST /creator/pack-manifest/apply
  • POST /creator/assets/inspect-frames
  • POST /creator/assets/import-frames
  • POST /creator/assets/pick-frames/inspect
  • POST /creator/assets/pick-frames/import
  • POST /creator/pet-pack/inspect-output
  • POST /creator/pet-pack/import-output
  • GET /creator/model-settings
  • POST /creator/model-health-check
  • POST /creator/model-image-generate
  • POST /creator/hatch-pet/plan
  • POST /creator/hatch-pet/evaluate

Bridge rules:

  • command bridge exists only during an explicit declaration-only command run;
  • service bridge exists only during an explicit declaration-only service run;
  • the command or service must belong to an enabled, policy-allowed local extension;
  • command requests must use Authorization: Bearer <OPENPET_BRIDGE_TOKEN>;
  • service requests must use Authorization: Bearer <OPENPET_SERVICE_BRIDGE_TOKEN>;
  • pet:say, pet:action, pet:event, actions:read, actions:write, trigger-proposals:write, pack-manifest:read, pack-manifest:write, assets:inspect, assets:generate, pet-pack:import, and model:image-generate permissions are enforced per route;
  • all pet mutations still flow through PetService;
  • service bridge exposes only /context, /pet/say, /pet/action, and /pet/event; services do not receive creator-tool bridge routes;
  • creator-tools action reads and writes flow through the host action service boundary, while pack manifest metadata reads and writes flow through the host pet-pack service boundary;
  • pack-manifest:read / pack-manifest:write only expose the current active installed user pack metadata workflow and do not permit arbitrary pet-pack writes, arbitrary pack targeting, or raw filesystem access;
  • creator-tools frame inspection is read-only, package-local, and confined to the extension directory;
  • creator-tools frame import/sprite generation is host-mediated, package-local, resource-limited, and does not grant raw filesystem writes or plugin-selected output paths;
  • creator-tools picker frame inspection/import is host-mediated and user-approved: the command can request a native folder picker, but selected absolute paths stay in the main process and are not returned to the bridge caller;
  • creator-tools full pet-pack import is host-mediated through PetPackService: the extension supplies a package-local or OPENPET_DATA_DIR relative approved output path, then OpenPet inspects, imports, applies policy checks, and optionally activates the pack;
  • creator-tools model settings, model health checks, and model image generation stay host-managed through the short-lived bridge; OpenPet-owned secrets remain in the main process, and plugin-managed provider credentials are not part of the current supported trust model;
  • setup entries, install, enable, and background health paths do not receive bridge access.

Current service bridge endpoint set:

  • GET /context
  • POST /pet/say
  • POST /pet/action
  • POST /pet/event

Example bridge requests:

curl -X POST "$OPENPET_BRIDGE_URL/pet/say" \
  -H "Authorization: Bearer $OPENPET_BRIDGE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"text":"今天上海有雨,带伞。","ttlMs":6000}'
curl "$OPENPET_BRIDGE_URL/context" \
  -H "Authorization: Bearer $OPENPET_BRIDGE_TOKEN"
curl "$OPENPET_BRIDGE_URL/creator/actions" \
  -H "Authorization: Bearer $OPENPET_BRIDGE_TOKEN"
curl -X POST "$OPENPET_BRIDGE_URL/creator/assets/inspect-frames" \
  -H "Authorization: Bearer $OPENPET_BRIDGE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"relativePath":"assets/actions/wave","actionId":"wave"}'
curl -X POST "$OPENPET_BRIDGE_URL/creator/assets/import-frames" \
  -H "Authorization: Bearer $OPENPET_BRIDGE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"relativePath":"assets/actions/wave","actionId":"wave","label":"Wave Hello"}'
curl -X POST "$OPENPET_BRIDGE_URL/creator/assets/pick-frames/inspect" \
  -H "Authorization: Bearer $OPENPET_BRIDGE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"actionId":"picked-wave"}'
curl -X POST "$OPENPET_BRIDGE_URL/creator/assets/pick-frames/import" \
  -H "Authorization: Bearer $OPENPET_BRIDGE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"actionId":"picked-wave","label":"Picked Wave"}'

Example command behavior:

  1. Read command context from stdin.
  2. Fetch weather using the extension's own network stack.
  3. Optionally call bridge routes such as POST /pet/say, POST /pet/action, or POST /pet/event.
  4. Write final result JSON to stdout.

Configuration

config points to an optional package-relative schema that can power Control Center forms.

{
  "title": "Weather Morning Report Settings",
  "type": "object",
  "properties": {
    "city": {
      "type": "string",
      "title": "City",
      "default": "Shanghai"
    },
    "sendEmail": {
      "type": "boolean",
      "title": "Send Email",
      "default": false
    }
  },
  "required": ["city"]
}

OpenPet-managed config is useful for friendly setup, but it is not the only place an extension may keep settings. Extensions may also maintain their own files, databases, dashboards, .env files, external accounts, or local model caches. If an extension manages secrets outside OpenPet, disclose that clearly in manifest.

Manifest Declarations

Use manifest to disclose facts OpenPet should show to the user.

{
  "network": {
    "declaredHosts": ["api.weather.example.com", "smtp.example.com"]
  },
  "dataLocations": [
    {
      "path": "OPENPET_DATA_DIR",
      "description": "Report history, scheduler state, and generated summaries."
    },
    {
      "path": "~/.weather-morning-report",
      "description": "Optional developer-managed local configuration."
    }
  ],
  "externalAccounts": ["Weather API provider", "SMTP provider"],
  "setupNotes": "Run the setup command before starting the companion service.",
  "cleanupNotes": "Cleanup can remove the local report database but cannot revoke external accounts."
}

OpenPet should display these declarations honestly. It should not treat them as proof that every runtime behavior is enforced.

Permissioned Pet And Creator Capabilities

Use manifest permissions to request host-mediated capabilities only when the extension needs them. Keep the request small and explain the user value in description, manifest, or README.md.

Current bridge-backed capabilities:

Capability Typical author use Boundary
pet:say Weather reports, reminders, dialogue packs, personality text Goes through PetService; no renderer or raw window access.
pet:action Play an existing action after a forecast, event, or local workflow Action id must be meaningful to the installed pet/action set.
pet:event Emit bounded pet events for host-visible integration Event payload stays command-run scoped.
actions:read Action studio reads current action configuration Read through host action service.
actions:write Add or update bounded action configuration Validated and applied by the host; no raw config-file write.
trigger-proposals:write Submit candidate trigger rules from a creator workflow Writes to the host-owned trigger proposal inbox only; no direct trigger-rule mutation.
pack-manifest:read Read active installed user pack metadata Active installed user pack only.
pack-manifest:write Update bounded user pack metadata No built-in pack edits or arbitrary pack targeting.
assets:inspect Inspect package-local or user-approved action frame folders No raw filesystem grant; paths stay host-confined.
assets:generate Import frames and regenerate sprites/action metadata Host-mediated, resource-limited, no plugin-selected output path.
pet-pack:import Import approved full pet-pack output from a creator workflow Host inspects/imports through PetPackService; no direct write to OpenPet pet-pack storage.
model:image-generate Read host image model settings, run health checks, and generate images through the bridge Host-managed provider flow only; OpenPet-owned credentials stay in the main process and outputs stay host-confined.

Example permission shape:

{
  "permissions": [
    "pet:say",
    "pet:action",
    "actions:read",
    "assets:inspect",
    "assets:generate",
    "pet-pack:import"
  ]
}

Recommended mapping:

  • Weather announcer: pet:say, optionally pet:action, plus any extension-owned network/API disclosure in manifest.
  • Pet dialogue/personality pack: pet:say, optionally pet:event, with config schema for tone, verbosity, and quiet hours.
  • Pet action studio: actions:read, actions:write, assets:inspect, assets:generate.
  • Trigger suggestion helper: trigger-proposals:write, optionally actions:read, when the workflow proposes triggers without directly mutating host rules.
  • Pack metadata helper: pack-manifest:read, optionally pack-manifest:write.
  • Full pet creator workflow: assets:inspect, assets:generate, and pet-pack:import; add pet:say only when the workflow announces status through the pet.
  • Host-managed image workflow: model:image-generate, optionally assets:inspect, assets:generate, or pet-pack:import, when the extension wants OpenPet to own provider credentials and image outputs.
  • Dashboard-only extension: no pet/creator permission unless it actually calls the bridge.

If a desired capability is not available yet, authors should still be able to submit the package as a local/community extension with the gap clearly disclosed. Maintainers should classify the missing capability as backlog instead of rejecting the idea outright when the package is structurally safe and honest about its limits.

Setup And Dependencies

Extensions may declare explicit setup commands:

{
  "id": "setup",
  "title": "Install Dependencies",
  "command": "npm install",
  "cwd": "."
}

Setup behavior:

  • install only extracts and inspects;
  • the extension remains disabled by default;
  • setup runs only when the user explicitly presses the setup action in Control Center;
  • OpenPet records setup status and logs;
  • setup may be rerun.

Production packages should prefer self-contained dependencies when practical, but the ecosystem should not require every package to be self-contained.

Data And Secrets

OpenPet manages:

  • extension installation metadata;
  • enabled state;
  • service process state;
  • setup state;
  • OpenPet-created data/cache/log directories;
  • health and log summaries;
  • configuration the user enters through OpenPet UI.

Third-party extensions may manage:

  • their own databases;
  • SMTP credentials;
  • API tokens;
  • .env files;
  • external accounts;
  • model caches;
  • generated files;
  • user content.

Do not imply that OpenPet can enumerate, audit, or delete every third-party secret or data file. Instead, disclose likely locations, provide cleanup commands when useful, and make local behavior understandable.

Pet Integration Ideas

Extensions should be able to build practical pet experiences, not just text commands.

Good extension shapes include:

  • weather morning reports where the pet speaks, changes action, and opens a dashboard;
  • pet action packs that add or regenerate animation frame lists;
  • pet personality injectors that alter speaking style through local config;
  • writing assistants where the pet summarizes progress;
  • local model workflows that generate pet sprites or dialogue variants;
  • scheduled companions that announce calendar, RSS, build, or system status;
  • dashboards for configuring extension-specific workflows.

Pet action tooling should prefer package-local assets and generated outputs under OPENPET_DATA_DIR or a declared asset directory. Creator-tools commands should use the host bridge for bounded action reads/writes, active installed pack metadata edits, package-local frame inspection/import, or user-approved native picker frame inspection/import. Do not modify cat_anime/ directly unless the user is intentionally working on core app assets.

Packaging And Submission

Current repository commands still use the historical "plugin" name:

npm run validate:plugin -- <extension-dir-or-zip>
npm run create-plugin-submission-bundle -- <extension-dir-or-zip> --output-dir plugin-submission-bundle
npm run validate-plugin-submission-bundle -- plugin-submission-bundle --require-ready
npm run create-plugin-real-world-submission-rehearsal -- --source examples/plugins/weather-status --output-dir docs/release-evidence/plugin-real-world-submission-rehearsal/<session>
npm run create-plugin-remote-source-submission-rehearsal -- --archive-url https://codeload.github.com/dengyie/OpenPet/zip/refs/heads/main --plugin-path examples/plugins/weather-status --output-dir docs/release-evidence/plugin-remote-source-submission-rehearsal/<session>
npm run create-plugin-community-source-intake-report -- --archive-url <https-archive> --plugin-path <path-inside-archive> --community-source-url <public-source-url> --submitter "<submitter>" --output-dir docs/release-evidence/plugin-community-source-intake-report/<session>
npm run create-plugin-community-source-evidence-from-intake -- --intake-summary docs/release-evidence/plugin-community-source-intake-report/<session>/plugin-community-source-intake-report-summary.json --source-relation independent-third-party --independence-notes "..." --output-dir docs/release-evidence/plugin-community-source-submission-evidence/<session>
npm run create-plugin-community-source-submission-evidence -- --archive-url <https-archive> --plugin-path <path-inside-archive> --community-source-url <public-source-url> --submitter "<submitter>" --source-relation independent-third-party --independence-notes "..." --output-dir docs/release-evidence/plugin-community-source-submission-evidence/<session>
npm run create-plugin-maintainer-approval -- plugin-submission-bundle --reviewer "OpenPet Maintainer" --decision approved --notes "Manifest, permissions, package hash, and submission artifacts reviewed."
npm run validate-plugin-maintainer-approval -- plugin-submission-bundle --require-approved

These commands are useful for structural validation and reviewer handoff, but some checks still reflect the legacy short-lived JavaScript SDK plugin model. The host now supports explicit setup execution, visible setup runtime status, explicit language-neutral command execution, explicit service start/stop, manual and opt-in periodic loopback service health checks, exit-confirmed cleanup for explicit setup/command/service stop flows, bounded service-side force stop, a broader process-tree cleanup fallback for explicit stop paths, creator-tools action reads and bounded writes through the short-lived bridge, active installed pack metadata reads / validation / bounded writes through pack-manifest:read and pack-manifest:write, package-local creator frame inspection through assets:inspect, package-local frame import/sprite generation through assets:generate, user-approved native picker frame inspection/import through the host, and a separate maintainer approval artifact layered on top of a ready-for-review submission bundle. Approval remains human-authored and does not prove signing trust, catalog publication, runtime safety, or release readiness. Arbitrary raw filesystem grants, arbitrary pet-pack writes, broader bridge flows, and universal process-tree cleanup guarantees are still implementation gaps to reconcile with the extension boundary design when developing the next host runtime.

For a local author rehearsal:

npm run create-plugin-author-rehearsal -- --output-dir docs/release-evidence/plugin-author-rehearsal/<session> --submission-template ai

The rehearsal writes an author README, command list, submission checklist, package zip, and validated submission bundle. The next maintainer step is now:

npm run create-plugin-maintainer-approval -- <submission-bundle-dir> --reviewer "OpenPet Maintainer" --decision approved --notes "..."
npm run validate-plugin-maintainer-approval -- <submission-bundle-dir> --require-approved

This is still review evidence, not catalog approval or signing trust.

For an existing-plugin rehearsal, use create-plugin-real-world-submission-rehearsal. The current archived example uses examples/plugins/weather-status to exercise package validation, network allowlist review, submission bundle generation, and maintainer approval in one local evidence chain. It is workflow evidence, not proof of external community provenance.

For a remote-source rehearsal, use create-plugin-remote-source-submission-rehearsal. The current archived example uses https://codeload.github.com/dengyie/OpenPet/zip/refs/heads/main to exercise archive URL capture, final URL capture, archive SHA-256 recording, archive size recording, plugin-path selection, extracted file hashing, package validation, submission bundle generation, and maintainer approval in one local evidence chain. It is remote-source workflow evidence, not proof of independent public ecosystem trust.

For a public candidate source that may or may not already match the current OpenPet package model, use create-plugin-community-source-intake-report first. It records the public source URL, submitter label, archive provenance, candidate plugin path, extracted file hashes, and a compatibility verdict before the source enters the stricter community-evidence flow. Compatible candidates are marked ready-for-community-evidence; neighboring repositories that do not contain a valid root plugin.json package are archived as incompatible-package-model instead of being overstated as OpenPet plugin submissions.

The latest archived GitHub-topic rerun at docs/release-evidence/plugin-community-source-discovery-report/2026-07-06T15-46-14Z-openpets-model-divergence-rerun/ keeps the full current GitHub openpets topic plus prior intake-backed candidates in scope, the newer npm-package rerun at docs/release-evidence/plugin-community-source-discovery-report/2026-07-06T16-17-27Z-npm-package-model-rerun/ inspects 13 published @openpets/* tarballs, and the direct GitHub code-search rerun at docs/release-evidence/plugin-community-source-discovery-report/2026-07-06T16-45-00Z-github-code-search-rerun/ finds zero public current-model hits for characteristic root plugin.json signatures. Together they make the neighboring ecosystem split explicit: current public OpenPets docs, starter materials, published packages, and public code search are still centered on openpets.plugin.json or package.json-based SDK v3 layouts rather than the current OpenPet root plugin.json package model. A targeted invitation draft also now exists at docs/release-evidence/plugin-community-source-invitation-kit/2026-07-06T15-46-14Z-openpets-plugin-starter-outreach/, but the public ecosystem still has not yielded a compatible third-party current plugin.json package.

If an intake summary is already ready-for-community-evidence, prefer create-plugin-community-source-evidence-from-intake for the next step. It reuses the archived Phase 100 intake metadata instead of asking maintainers to manually retype archive URL, plugin path, source URL, or submitter values before Phase 99 evidence is created.

For a stricter community-source evidence archive, use create-plugin-community-source-submission-evidence after the intake step for public sources. It wraps the remote-source rehearsal with a public community source URL, submitter label, source-relationship classification, and required maintainer independence notes. The command can archive provenance even when relationship is still unknown, but it only marks communityEvidenceReady when the maintainer classifies the source as independent-third-party or external-community. This is still provenance and review traceability, not signing trust, catalog publication, runtime safety, or release readiness.

Legacy JavaScript SDK Compatibility

Existing examples remain useful for the current implementation:

Legacy packages use fields such as main, permissions, network.allowlist, and commands, then export activate(ctx) with APIs such as ctx.pet, ctx.storage, ctx.network, and ctx.ai.

That path is still valid for compatibility, but it should not define the future ceiling of the ecosystem. New platform work should adapt the host toward the unified extension model described above.