Problem
Extensions cannot use fs or os at runtime — the extension host rejects any require() other than @papi/* and crypto:
Error: Requiring other than papi is not allowed in extensions! Rejected require('fs').
Try using papi.storage or bundling the module into your code with a build tool like webpack
This makes it impossible for an extension to read a file written by a companion process (e.g. a local AI gateway, a language server, a data sync daemon) to discover what port that process is listening on.
Motivating Example
paratext-copilot bundles an AI chat panel that delegates to llm-gateway, a local FastAPI server. The gateway can start on any available port. We want the extension to find it automatically without the user configuring a port number.
What we tried: llm-gateway writes ~/.platform.bible/llm-gateway.port on startup; paratext-copilot reads that file. Blocked — require('fs') is rejected at runtime.
Current workaround: probe a list of candidate ports via fetch() with a short timeout. This works but is fragile (port collisions, unnecessary network probes, latency when the gateway is on a non-default port).
Proposed Solution
A papi.ipc (or papi.registry) namespace that lets companion processes advertise named endpoints, and lets extensions look them up:
// Companion process advertises itself (via a small Node helper or agreed protocol)
await papiCompanion.registry.advertise('llm-gateway', { port: 8432 });
// Extension looks it up
const { port } = await papi.registry.lookup('llm-gateway');
The registry could be backed by:
- A well-known file or directory that papi itself reads on behalf of extensions (so extensions never touch
fs directly), or
- A named pipe / Unix domain socket managed by Platform.Bible, or
- A simple HTTP endpoint on the Platform.Bible host process that companion processes POST their metadata to.
Why This Matters
Extensions paired with a companion process are common for resource-heavy workloads (ML inference, language servers, database servers) that shouldn't run inside the extension host. Right now there is no standard way for these processes to find each other — each team invents its own workaround, leading to port conflicts and poor UX.
A Platform.Bible-managed registry would give companion processes a standard, sandboxing-compatible rendezvous mechanism.
Problem
Extensions cannot use
fsorosat runtime — the extension host rejects anyrequire()other than@papi/*andcrypto:This makes it impossible for an extension to read a file written by a companion process (e.g. a local AI gateway, a language server, a data sync daemon) to discover what port that process is listening on.
Motivating Example
paratext-copilot bundles an AI chat panel that delegates to llm-gateway, a local FastAPI server. The gateway can start on any available port. We want the extension to find it automatically without the user configuring a port number.
What we tried: llm-gateway writes
~/.platform.bible/llm-gateway.porton startup; paratext-copilot reads that file. Blocked —require('fs')is rejected at runtime.Current workaround: probe a list of candidate ports via
fetch()with a short timeout. This works but is fragile (port collisions, unnecessary network probes, latency when the gateway is on a non-default port).Proposed Solution
A
papi.ipc(orpapi.registry) namespace that lets companion processes advertise named endpoints, and lets extensions look them up:The registry could be backed by:
fsdirectly), orWhy This Matters
Extensions paired with a companion process are common for resource-heavy workloads (ML inference, language servers, database servers) that shouldn't run inside the extension host. Right now there is no standard way for these processes to find each other — each team invents its own workaround, leading to port conflicts and poor UX.
A Platform.Bible-managed registry would give companion processes a standard, sandboxing-compatible rendezvous mechanism.