Skip to content

How Pedelec Works

Pedelec connects a browser page to an AI agent without giving the page direct access to local processes. The connection is split into several components, each with a narrow responsibility.

Your application creates the Pedelec client and session objects. It renders messages and status, accepts user input, and implements any frontend tools made available to the agent.

The application is responsible for:

  • deciding when to create, resume, or end a session;
  • displaying provider and connection state;
  • accumulating streamed text into messages;
  • validating tool arguments before changing application state;
  • cleaning up event handlers and pending UI interactions; and
  • deciding whether an event still belongs to the current page, route, canvas, or editor instance.

@kaoruisaac/pedelec provides the public browser API:

  • Pedelec manages the extension connection and request/response bridge.
  • PedelecSession represents one agent session.
  • defineTool() preserves useful TypeScript types while defining a serializable tool manifest.
  • event callbacks normalize chat, status, tool, error, and ended events for the application.

The SDK must be instantiated in a browser page. It is not a Node.js client and is not a server-side transport.

The extension accepts external SDK connections from allowed web origins. It:

  • identifies the requesting origin;
  • asks the user to approve an origin before session creation or resume;
  • stores approved origins locally in extension storage;
  • forwards requests through Chrome Native Messaging; and
  • routes runtime events back to the correct SDK channel and session.

The extension is also responsible for page-disconnect behavior such as automatically ending a page-scoped session when its last SDK route disappears.

The native host is the Chrome-approved bridge from the extension into the installed desktop application. The web page does not connect to this executable directly.

If the host is missing or not registered, SDK operations that need the desktop runtime fail with errors such as NATIVE_HOST_UNAVAILABLE.

The Pedelec Desktop App owns the Core Runtime. It:

  • creates and tracks sessions;
  • stores provider settings and three effort profiles;
  • prepares a workspace for a session;
  • launches or resumes the selected provider process;
  • converts provider output into normalized events;
  • injects tool guidance and the tool index into the initial provider prompt; and
  • waits for tool results before continuing the agent turn.

The browser application does not need to know the Core IPC protocol or provider-specific command-line details.

A provider is the agent backend selected for a session, such as codex, antigravity, opencode, cursor, claude, or ollama.

Provider availability depends on the user’s machine. CLI-backed providers usually require the relevant command to be installed, present in PATH, and authenticated. Ollama sessions use Pedelec’s bundled agent executable with the configured Ollama-compatible endpoint (default http://127.0.0.1:11434), a non-empty API key (ollama for local Ollama), and an installed model.

When a provider needs to execute JavaScript or TypeScript from guidance, a template, an agent-generated script, or an existing workspace file, the bootstrap makes Pedelec’s local pedelec-deno helper the canonical runtime. The agent decides whether execution is needed; the web application and SDK only provide guidance, templates, and workspace files. The helper is invoked with the session thread id and a workspace-relative script path, and it is not browser-side code execution or a general remote-code-execution API. If the helper is unavailable, the agent reports the failure instead of silently falling back to Node.js, Bun, raw Deno, or another runtime.

Pedelec Desktop ships its own pinned, permission-restricted Deno runtime, so users do not need to preinstall Node.js, Bun, or Deno for local workspace scripts. The raw deno executable remains an internal bundled resource; pedelec-deno is the only agent-facing command:

pedelec-deno --thread-id <pedelec_thread_id> run <workspace-relative-script-path> -- <script-args...>

This distributed runtime is a Desktop capability, not an SDK or browser API for arbitrary remote code execution. It permits local workspace JS/TS execution while denying network, environment, subprocess, FFI, and system capabilities.

A typical explicit-provider session follows this flow:

  1. The application calls pedelec.createSession({ provider, effortLevel, skills }).
  2. The SDK validates the basic input and serializes the skills manifest. Inline handler functions remain in the browser and are not sent to Core.
  3. The extension checks whether the page origin is approved. If it is not, the session request waits while the extension popup asks the user.
  4. The extension opens a Native Messaging connection when needed.
  5. The desktop runtime resolves and validates the selected effort profile, snapshots its argv tokens, creates the session and workspace, then returns a sessionId.
  6. The extension subscribes the current SDK route to that session.
  7. The SDK returns a PedelecSession object.

Creating a session does not necessarily launch a long-running provider process immediately. Provider execution is managed by the desktop runtime when the session is prepared or receives a turn.

Without workspace.path, the desktop runtime creates a temporary managed workspace under ~/.pedelec/workspaces/<threadId> and owns its cleanup. An application can instead pass an absolute workspace.path to select an application-managed workspace. Pedelec creates .pedelec-runtime/{assets,logs,skills,tmp}/, preserves existing project content and private data, and never deletes an explicit workspace. Multiple active sessions may share one explicit path; filesystem write coordination remains the application’s responsibility. Explicit paths cannot overlap the managed workspace root.

sendText(text)
SDK marks the session running
Extension forwards send_text
Desktop runtime starts/resumes provider work
Provider emits assistant output and/or a tool call
SDK dispatches onChat(), onChatDelta(), onStatus(), or onTool()
Runtime emits the operation-scoped completion and observable status events
sendText() resolves

The SDK assigns a local turnId after accepting a turn. This helps the UI group callbacks, but it is not a provider session identifier and must not be parsed.

Only one active turn is allowed per session. A second sendText() while the first is active rejects with SESSION_BUSY.

  1. The application included a tool definition in skills.tools.
  2. Core injects skills.guidance, tool names, descriptions, and calling instructions into the first provider prompt. The initial prompt omits complete argument schemas.
  3. When it needs a schema, the agent runs pedelec-cli --thread-id <pedelec_thread_id> tool-spec <tool-name>; it calls a tool with pedelec-cli --thread-id <pedelec_thread_id> tool-call <tool-name> '<json_args>'.
  4. Core emits a normalized tool event and waits for a result.
  5. The SDK sets the session status to waiting_tool_result.
  6. The SDK selects a handler in this order: named handler, inline handler, generic fallback.
  7. The handler runs in the browser page and returns a JSON-serializable result.
  8. The SDK submits the result through the extension and desktop runtime.
  9. The agent continues and the session eventually returns to idle, ends, or errors.

The SDK handles the transport, but the application owns the semantics and safety of the operation. For example, a tool named delete_layer should still check that the requested layer exists and that the current editor generation is valid.

ToolRegistry is the runtime source of truth. Core can generate per-tool spec artifacts as an implementation detail, but a normal Web App integration and agent flow never need to locate or read tools.md.

Session requests, events, and tool results use the control/event path:

Web App → SDK → Chrome Extension → Native Host → Core IPC → Desktop Runtime

Asset bodies use a separate internal data path:

Web App fetch(PUT/GET) → Desktop-managed 127.0.0.1 loopback asset transfer server → session `.pedelec-runtime/assets/`

The SDK obtains and uses upload and download tickets internally through session.uploadAsset() and session.readAsset(). Applications must not create a localhost server or depend on transfer URLs, ports, tokens, or ticket lifecycles. Asset bodies do not pass through the Extension message body, Native Messaging payload, or Core IPC message body.

Concern Owner
Message and status UI Web application
Validation of agent-generated tool arguments Web application
Origin approval Extension and user
Browser-to-native transport Extension and native host
Session and provider lifecycle Desktop runtime
Provider authentication and network behavior Selected provider and user configuration
Determining whether a late callback is stale Web application

The SDK does not require your web application to expose a local port. The extension uses Native Messaging, and the native host talks to the desktop runtime over Pedelec’s local Core IPC. Those internal transports are implementation details and should not be called directly by normal SDK integrations.

For exact browser and origin constraints, continue to Requirements and browser support.