shire Docs
Docs/Plugin API/Architecture

Architecture

Three layers

┌──────────────────────────── Shire process (private) ────────────────────────────┐
│                                                                                 │
│  private Core                                                                   │
│  hooks, game adapters, entity/scene/marker readers, teleport, config, renderer  │
│        │                                                                        │
│        │  copies of public data only (no pointers, offsets or handles)          │
│        ▼                                                                        │
│  Shire API Host                                                                 │
│  named-pipe server · JSON-RPC dispatcher · permissions · rate limits            │
│  storage · logs · event bus · UI descriptors · process/job manager              │
│        │                                                                        │
└────────┼────────────────────────────────────────────────────────────────────────┘
         │  local named pipe, newline-delimited JSON-RPC 2.0
         │  per-plugin token, capability checks, bounded queues
         ▼
┌────────────────────────── plugin process (isolated) ───────────────────────────┐
│  SDK (Python / Node / C++ / Rust / C#) or a language-neutral protocol client  │
│  plugin code · own memory · own files · no Shire pointers                      │
└───────────────────────────────────────────────────────────────────────────────┘

Private Core

The Core is the existing Shire payload. It keeps offsets, game pointers, hook engines, feature state and the proprietary implementation. None of that is published in an SDK or included in the JSON contract.

The Core exposes a narrow private adapter (plugin_core.cpp + PluginCore* functions in the feature translation units) that returns copies of public values:

  • local player position and scene id;
  • an entity summary (opaque id, config id, type, position, distance);
  • marker name/category/position/distance from the static area catalogue;
  • a validated teleport request.

The adapter uses structured exception handling around game reads. A stale scene or a missing entity returns not_available, not a pointer.

Shire API Host

The Host is the only component allowed to talk to the Core. It owns:

  • one named pipe per Shire session (\\.\pipe\shire-<random>), with a new per-launch token per plugin;
  • JSON-RPC parsing, method dispatch and response framing;
  • permission checks on every call, not only at install time;
  • rate limiting (300 calls/second per plugin, burst included), line size limits and bounded queues;
  • plugin registry, private storage, logs, package install/remove;
  • process launch, job-object memory limit, restricted token when available, process-exit detection and connection teardown;
  • event sampling and outbound notifications with backpressure;
  • the UI descriptor store consumed by the Plugin Manager.

The Host contains no game offsets and no ImGui context. The UI file is linked only into the payload; the same Host and protocol compile into the standalone mock host with a fake Core.

Public SDK

The SDKs contain only:

  • the pipe transport;
  • JSON-RPC framing and request ids;
  • the public method names and event names;
  • typed helpers for UI descriptors and settings.

They do not contain offsets, addresses, private structs, game function RVAs or administrative secrets. A plugin receives a token for its own launch; the token is not a Shire-wide secret and grants only that plugin's capability-checked session.

Why a process instead of a native plugin DLL?

Loading third-party native code inside the Core would give the plugin the same address space, the same handles and the same game pointers. A crash would take Shire down; a malicious plugin could walk the process. The Host instead starts a child process, assigns it to a job object and talks to it over a pipe. A plugin crash closes one pipe; the Shire renderer and other plugins keep running.

Mobile and other platforms

The current Host is Windows-only because Shire is a Windows payload and the transport is a Windows named pipe. The JSON-RPC contract itself is portable; a future Host can provide a Unix-domain-socket or WebSocket transport for other platforms without changing the method semantics.

Adding a new native operation

  1. Add a private Core adapter that returns a copy or performs a validated action.
  2. Add a method entry to plugin_protocol.cpp (MethodPermission) and to the Host dispatcher in plugin_host.cpp.
  3. Add the same method to sdk/contract/api.json, the docs generator and the SDK helpers.
  4. Add a contract test in tests/plugin/test_contract.py.
  5. Add the permission to the manifest schema if the operation needs a new capability.

The contract test compares the live handshake and api.info lists against sdk/contract/api.json, so documentation cannot silently drift from the Host.

Shire Plugin API 1.0 · Written in English. Documentation home · API status · Changelog

Independent project. Not affiliated with HoYoverse. Never put secrets in a plugin, manifest or package.