Skip to content

Latest commit

 

History

History
188 lines (142 loc) · 6.58 KB

File metadata and controls

188 lines (142 loc) · 6.58 KB

Plugin Development Guide

Coding Pet is built around a plugin system. The desktop app ships with reference plugins (see official plugins below for the current list) — but everything they do is available through the same interfaces exposed to third-party plugins.

What a plugin can provide

A plugin is a PetPlugin object with an id, a displayName, and a setup(host) method. Inside setup you call registration methods on PetHostApi:

Method What it registers
registerPackageAdapter(adapter) Support for a new pet package format
registerDiscoverySource(source) A source that lists installable pets
registerAnimationResolver(resolver) Maps animation state names to sprite sequences
registerActionCatalog(catalog) The set of actions/states the runtime exposes
registerPetProvider(provider) Built-in pets that need no package directory
registerSnapshotSourceFactory(factory) A new source of RuntimeSnapshot events
registerNotificationResolver(resolver) Maps session projections to notification levels
registerLayoutResolver(resolver) Controls overlay/tray layout geometry

You can register any combination. A plugin that only adds a new pet package format registers just a PackageAdapter. One that only adds a new tool integration registers just a RuntimeSnapshotSourceFactory.

Minimal plugin skeleton

import type { PetPlugin } from '@coding-pet/runtime-core';

export function createMyPlugin(): PetPlugin {
  return {
    id: 'my-plugin',
    displayName: 'My Plugin',
    setup(host) {
      host.registerDiscoverySource({
        id: 'my-discovery',
        displayName: 'My Pets',
        listPets() {
          return [
            { id: 'my-pet', displayName: 'My Pet', petDir: '/path/to/my-pet' }
          ];
        },
      });
    },
  };
}

Adding a new pet package format

Implement CompatiblePetPackageAdapter:

import type { CompatiblePetPackageAdapter } from '@coding-pet/runtime-core';

const myAdapter: CompatiblePetPackageAdapter = {
  id: 'my-format-v1',
  supports(formatId) { return formatId === 'my-format-v1'; },
  load({ petDir, manifest, manifestPath, resolveFileUrl }) {
    const spritesheetPath = path.join(petDir, manifest.spritesheet ?? 'spritesheet.png');
    return {
      id: String(manifest.id),
      displayName: String(manifest.displayName),
      description: String(manifest.description ?? ''),
      spritesheetPath,
      spritesheetUrl: resolveFileUrl?.(spritesheetPath) ?? spritesheetPath,
      manifestPath,
      formatId: 'my-format-v1',
    };
  },
};

Adding a new tool/runtime integration (Host Bridge)

A Host Bridge listens to events from an external tool and writes a RuntimeSnapshot to a file, then registers that path in stateFiles. The simplest approach is to write a standalone file (no npm package needed) that the tool can load directly. See the bundled bridges under packages/*-host-bridge/ for reference implementations.

The snapshot schema:

interface RuntimeSnapshot {
  state: string;   // animation state name, e.g. "running", "idle", "failed"
  title: string;   // shown in the speech bubble title
  body: string;    // shown in the speech bubble body
}

Write it as JSON to ~/.coding-pet/<tool>-state.json, then add the path to stateFiles in the desktop app config:

{
  "adapter": "file",
  "stateFiles": [
    "~/.coding-pet/<tool>-state.json"
  ]
}

How the desktop app relates to this plugin system

The desktop app (apps/desktop) is plain JavaScript and does not load TypeScript plugins at runtime. It implements its own equivalent directly in preload.js and renderer.js.

This means:

  • The PetPlugin / PetHostApi system is for programmatic embedding — building your own runtime in TypeScript that uses runtime-core.
  • To connect your work to the desktop app, use the config-level equivalents:
What you built How to connect it to the desktop
A new pet package (any format) Add its directory to discoverySources in config.json, or point petDir at it directly
A host bridge for a new tool Write a RuntimeSnapshot JSON to a file; set adapter: "file" and add the path to stateFiles

There is no plugin loading step for the desktop — adding a path to discoverySources is the entire integration.

Testing your plugin locally

Test the TypeScript plugin API in isolation — write a script and run it with tsx:

// my-plugin-test.ts
import { PetRuntimeRegistry } from '@coding-pet/runtime-core';
import { createMyPlugin } from './my-plugin.ts';

const registry = new PetRuntimeRegistry();
createMyPlugin().setup(registry);

const pets = registry.discoverySources.flatMap(s => s.listPets());
console.log('Discovered pets:', pets);
npx tsx my-plugin-test.ts

Test a new pet package in the desktop — place the package directory anywhere, then add it to apps/desktop/config.json:

{
  "discoverySources": ["./sample-data/codex-pet-adapter", "/path/to/my-new-pet-dir"]
}

Restart the desktop and open the selector — your pet should appear.

Test a host bridge in the desktop — write a snapshot file to disk and add it to stateFiles in the config:

{
  "adapter": "file",
  "stateFiles": [
    "~/.coding-pet/my-tool-state.json"
  ]
}

Then write the file from your tool or manually:

{ "state": "running", "title": "Working", "body": "test" }

The pet updates within one second.

Using programmatically (without the desktop app)

import { createCodexPetAdapterPlugin } from '@coding-pet/plugin-codex-pet-adapter';
import { PetRuntimeRegistry } from '@coding-pet/runtime-core';

const registry = new PetRuntimeRegistry();
createCodexPetAdapterPlugin().setup(registry);

// List all discovered pets
const pets = registry.discoverySources.flatMap(s => s.listPets());

// Load a specific pet package
const adapter = registry.packageAdapters.find(a => a.supports('codex-pet-v1'));
const pkg = adapter?.load({ petDir: '/path/to/pet', manifest, manifestPath });

Official plugins

Package What it does
@coding-pet/plugin-codex-pet-adapter codex-pet-v1 format support + ~/.codex/pets/ discovery
@coding-pet/plugin-opencode-host-bridge Bridges OpenCode session events to RuntimeSnapshot
@coding-pet/plugin-claude-code-host-bridge Claude Code hooks bridge
@coding-pet/plugin-gemini-cli-host-bridge Gemini CLI hooks bridge
@coding-pet/plugin-qwen-code-host-bridge Qwen Code hooks bridge

See each package's own README for detailed API documentation.