OpenHands · TypeScript · transpile maintenance

Keeping two transpiles alive

The SDK and agent-server are not one-time ports. They are a continuing relationship with the Python OpenHands/software-agent-sdk: one pinned upstream commit, two TypeScript targets, and a repeatable way to discover, classify, port, and prove every bounded change.

The governing rule: hand-write policy, generate discovery, execute evidence, and freeze update history.

1 · The three rings

strictest parity

SDK transpile

enyst/openhands-agent covers the upstream SDK, tools, and workspace packages. Observable Python behavior is the default contract; named deviations are exceptional.

protocol parity

Agent-server transpile

packages/openhands-agent-server preserves the REST/WebSocket boundary. Additive behavior requires an explicit EXT-SERVER-* policy.

product-owned

Coordinator and bridges

SmolPaws owns durable intake, lane ordering, claims, retries, delivery ambiguity, and channel behavior. This layer borrows useful ideas from Automation but is not a transpile.

2 · One pin, bounded intervals

A machine-readable manifest in the SDK package names the exact upstream repository, full commit SHA, source/test/example scopes, and policy hints. The server consumes the vendored copy and verifies its generated Python oracles against the same SHA.

Work is never “sync to HEAD”. A candidate may be discovered from current upstream, but the review unit is immutable: OLD_PIN..NEW_PIN. The pin moves only when every relevant change has a disposition and its required evidence is green.

3 · The update conveyor

scan
Generate commits, changed paths, tests, examples, target buckets, and policy hints.
classify
Assign PORT, NO_TARGET_CHANGE, DEVIATION, EXCLUDED, or DEFERRED.
red
Port or add the upstream test before changing implementation.
green
Implement the smallest compatible behavior and run surrounding suites.
prove
Run generated OpenAPI, wire, integration, build, pack, and smoke evidence.
advance
Freeze the reviewed interval and move both transpiles to the same upstream SHA.

4 · Why the dispositions differ

DispositionMeaningMaintenance effect
PORTTarget behavior or tests must change.Tests first, then implementation.
NO_TARGET_CHANGEThe change was reviewed and needs no TypeScript edit.A concrete reason is required.
DEVIATIONThe area remains relevant, but target policy intentionally differs.Upstream changes still require review against the alternative behavior.
EXCLUDEDThe upstream subsystem is outside declared scope.Changes wholly inside it create no port work unless scope changes.
DEFERREDThe change is in scope but intentionally postponed.Tracking, compatibility consequence, and revisit trigger are mandatory.

5 · Generated oracles

A green target test suite proves implemented behavior, but not that every upstream change was noticed. The maintenance system therefore combines completeness checks with behavioral evidence.

Live LLM calls remain separate. They prove that a provider currently accepts the request, not that TypeScript matches Python.

6 · Weekly rhythm

The SDK fork owns one scheduled watcher. It publishes a generated summary and artifacts for the drift between the canonical pin and the exact observed upstream commit. The watcher is an alarm panel, not a backlog factory: semantic issues are created only after a bounded interval is selected and reviewed.

7 · Documentation precedence

Code and tests describe current factual behavior. Transpilation contracts describe intended policy. Architecture pages explain the current design. Release notes and historical migration studies preserve their moment in time. A conflict between code and contract is investigated; it is not automatically resolved by rewriting whichever side is less convenient.

Sources of truth