Development
Use this page when extending the bridge protocol itself. Application developers building a TypeScript shell usually need only the process bridge overview and runtime configuration.
Command handling is registry-based.
BridgeBackend accepts an explicit command-handler tuple and defaults to
BRIDGE_COMMAND_HANDLERS; each command handler declares the command class it
handles and owns that command’s side effects. Native events use
RunEvent.to_dict() directly. They need no separate Python encoder registry.
Add a Command
-
Add the command name to
CommandTypeinpackages/process_bridge/src/agentlane_process_bridge/_protocol.py. -
Add a
COMMAND_*constant for the new command name inpackages/process_bridge/src/agentlane_process_bridge/_protocol.py. -
Add the command constant to
COMMAND_TYPES. -
Add a frozen command dataclass with a literal
typefield inpackages/process_bridge/src/agentlane_process_bridge/_protocol.py. -
Add the dataclass to the
BridgeCommandunion. -
Add one
BridgeCommandParserimplementation inpackages/process_bridge/src/agentlane_process_bridge/_protocol.py. -
Add the parser instance to
COMMAND_PARSERS. -
Add one
BridgeCommandHandlerimplementation inpackages/process_bridge/src/agentlane_process_bridge/_backend.py. -
Add the handler instance to
BRIDGE_COMMAND_HANDLERS. -
Re-export the command dataclass and any public handler type from
packages/process_bridge/src/agentlane_process_bridge/__init__.pywhen apps should import it. -
Add the matching command name to
KNOWN_COMMAND_TYPESand the command shape toBridgeCommandinpackages/process_bridge_ts/src/protocol.ts. -
Add or update Python protocol/backend tests and TypeScript protocol/channel tests.
-
Run:
uv run pytest packages/process_bridge/tests -q /usr/bin/make lint-ts /usr/bin/make test-ts
Add Runtime Config Handling
- Define the app-owned config document shape in Python and TypeScript. Every announced document must be JSON-serializable. The app owns schema validation; the bridge sends the complete document without a size cap.
- Validate raw patches into a named app patch type at the Python boundary. Do not thread generic dict lookups through the store’s application logic.
- Implement
RuntimeConfigStore.snapshot()to return the full current document. - Implement
RuntimeConfigStore.apply(patch)to validate the whole patch before mutating state, then return the full applied document. - Raise
ConfigRejectedErrorfor user-fixable problems such as unknown model ids, attributes, or options. Let unexpected exceptions raise normally; the bridge reports them as internal failures with a fresh snapshot. - Pass the store as
AgentBackend(config=store)orrun_stdio(config=store). - In TypeScript, call
createAgentSession<TConfig, TConfigPatch>({ decodeConfig, ... })when the patch shape differs from backend truth, and render fromsession.configplusonConfigChanged. - Apply changes through
await session.configure(patch). Do not predict local state; the resolved document and callback are backend truth. - Add Python store/handler tests and TypeScript session tests for success, rejection, reset re-announcement, and bad config decoding.
Add Run-Event Handling
-
Add the upstream run event to
agentlane.harness.RunEventKindand the concrete run-event dataclass in AgentLane core first. -
Verify that
to_dict()preserves every source field and rejects unsupported values. The bridge delivers the record insiderun_event.eventautomatically. -
Add typed payload validation to
NATIVE_EVENT_SCHEMASinpackages/process_bridge_ts/src/protocol-native.ts. Retain extra fields at every nested object level. Unknown native kinds already reachonEvent. -
Add session presentation only when a callback needs it. Keep the raw record intact. Derive display fields from source data and preserve lineage.
-
Update Python-generated fixtures in
packages/process_bridge/fixtures/protocol/events.jsonand TypeScript parity tests. Assert exact field retention across the language boundary. -
Add lifecycle tests if the event affects approval or presentation state. Model completion and errors must not settle the run or command promises.
-
Run:
uv run pytest packages/process_bridge/tests -q /usr/bin/make lint-ts /usr/bin/make test-ts
Regenerate the shared protocol fixture from native Python records before the parity tests:
uv run python -m packages.process_bridge.tests.native_fixtures
Add Bridge-Only Event Handling
- Add the wire event name to
BridgeEventTypeinpackages/process_bridge/src/agentlane_process_bridge/_protocol.py. - Emit it from the command handler or backend operation that owns the side effect.
- Add the TypeScript event shape to
packages/process_bridge_ts/src/protocol.ts. - Add the matching strict schema entry to
BRIDGE_EVENT_SCHEMASinpackages/process_bridge_ts/src/protocol.ts. - Add a representative event object to
packages/process_bridge/fixtures/protocol/events.json. - Add or update Python protocol/backend tests and TypeScript decoder/parity tests.
Developer Experience
A command has one parser, one backend handler, and one TypeScript command shape. A native event uses the core serializer, a TypeScript payload schema for known fields, and a representative fixture. Unknown native kinds remain available to raw consumers before presentation support is added.
Parity tests compare Python records and TypeScript-decoded values. TypeScript
process wiring reports malformed frames as BridgeDecodeError values without
delivering them to app reducers. Update both packages and their callers together:
protocol 1.0 does not distinguish the previous flat contract from native events.
Synthetic Payload Measurement
Run from the repository root:
uv run python -m packages.process_bridge.tests.measure_native_events
One local sample on 2026-09-12 used 30 repetitions per case. Delivery includes
conversion, EventWriter, and queue drain into a StringIO sink. This measures
neither OS pipe throughput nor provider latency. Frame sizes can vary slightly
with the timestamp.
| Synthetic record | Frame bytes | Median conversion (ms) | Median delivery (ms) |
|---|---|---|---|
| Text delta | 391 | 0.007 | 0.143 |
| Agent end, 10 history entries | 4,224 | 0.022 | 0.166 |
| Agent end, 100 history entries | 38,694 | 0.101 | 0.437 |
| Agent end, 1,000 history entries | 384,294 | 0.874 | 2.951 |
Full history increases payload size and conversion cost. The protocol retains all fields; apps control display limits. Measure representative app workloads before choosing downstream storage and forwarding policies.