Skip to content

chore(python): migrate the Python SDK to ai-openshell/sdk-python #5287

Open

Description

@pimlock

User Story

As a maintainer of the Python SDK, I want to move it out of core into ai-openshell/sdk-python the way the Go SDK moved (#5031), so that it gets its own CI, reviews and releases without changing anything for the people who pip install openshell.

Problem Statement

RFC 0019 (#4426) moves the SDKs out of core first. The Python SDK still lives in core, spread across several paths:

  • python/openshell/, plus its SDK tests in python/;
  • the repository-root pyproject.toml, which is the SDK's package definition;
  • tasks/python.toml;
  • tasks/scripts/generate_python_proto.py and verify-python-wheel.py.

Core CI builds, lints and type-checks the SDK on every PR. Core's release workflows build the wheel and publish it to PyPI through wheel-publish.yml, and the openshell PyPI project trusts only that workflow. Core's e2e/python suites import the SDK from the working tree. The root uv.lock serves both the SDK and core's own Python tooling.

Impact / Why This Matters

  • SDK maintainers own CI, reviews and releases without core review bandwidth, which is the goal of RFC 0019.
  • Users see no change. The package name openshell, the import paths and the API stay the same, including openshell._proto. Public code on GitHub depends on that module: Airflow's sandbox provider, dify-agent, NeMo Gym and others import it directly. So the move must not be combined with a breaking change to the generated bindings.
  • Core stops building and publishing the Python wheel. Its e2e suites consume the SDK as a pinned dependency.

Proposed Design

Follow the Go SDK's phases (#5031, and the lessons in discussion 5273), adapted to Python:

  1. Prerequisites.
    • Confirm the sdk team and the sdk-python repository settings.
    • Plan the PyPI trusted-publisher handover and the version scheme. The first release from sdk-python must sort after the last core-built wheel.
    • Announce the freeze at a release tag and merge the SDK PRs that are ready before it.
  2. Import.
    • Extract the SDK paths with history, using git filter-repo --paths-from-file: the package moves to src/openshell/, the tests to tests/ and the scripts to scripts/. Core-only tests stay in core, and #N references are rewritten to NVIDIA/OpenShell#N.
    • A second PR makes the package build on its own: bindings generated from protos fetched at the pinned core tag and committed, vendored test fixtures with drift checks, and standalone CI with a Python 3.11–3.14 test matrix.
  3. Cutover in core.
    • Switch e2e/python to the SDK as a pinned dependency.
    • Remove the python job and build:python:wheel from PR gating.
    • Add a required check that fails on changes to the moved paths, and port the open SDK PRs.
    • Move the open SDK issues. GitHub can't transfer issues between organizations, so gh issue transfer from NVIDIA/OpenShell to ai-openshell isn't available.
    • Route new reports to sdk-python. Point core's issue templates (the config.yml contact links) and CONTRIBUTING at sdk-python for Python SDK reports.
  4. Automation in sdk-python. As planned for sdk-go: bump PRs for each core release, E2E against that release's gateway, release tagging and a nightly drift check.
  5. Retire in core.
    • Ship a final core-built wheel with a deprecation note.
    • Remove the SDK paths, tasks/python.toml SDK tasks, CodeQL entries, the wheel build and publish-pypi jobs, wheel-publish.yml, and core's PyPI trusted publisher.
    • Update docs/sdk/python.mdx, AGENTS.md, CONTRIBUTING and the skills.
  6. Release. Publish the first openshell release from sdk-python.

Progress:

Acceptance Criteria

  • ai-openshell/sdk-python builds, tests and packages the SDK without a core checkout or network access at build time.
  • The first release from sdk-python installs as a drop-in replacement for the last core-built wheel: same exports and the same openshell._proto modules.
  • Core CI, releases and e2e/python no longer build the SDK from python/, and core proto PRs no longer regenerate Python bindings.
  • PyPI publishes openshell only from sdk-python.
  • No open Python SDK issues remain in core: each is closed as fixed, obsolete, or moved, with a link to its sdk-python copy. Core's issue templates send new Python SDK reports to sdk-python.
  • The Python-specific lessons are added to the migration playbook for the next repository move.

Alternatives Considered

  • Bootstrap from a copy without history (feat!: package sdk with public Buf protos ai-openshell/sdk-python#1). This loses blame and authorship, and the Go move kept history.
  • Generate bindings at build time from the Buf Schema Registry with remote plugins. Every wheel or sdist build would then need network access, which breaks sdist rebuilds, and it pairs with a runtime change that breaks users of openshell._proto.
  • Keep the SDK in core and delegate through CODEOWNERS. RFC 0019 already weighs this option.

Agent Investigation

An agent mapped the SDK's footprint in core (paths, mise tasks, workflows, CodeQL, PyPI publishing, e2e consumers), rehearsed the history extraction and the standalone build in a private repository, and surveyed public GitHub code that imports the SDK. Rehearsal results:

  • 76 commits from 24 authors, with a tree hash that matches core.
  • 34 imported commits are older core squash merges without Signed-off-by, so the import PR needs a DCO override.

Activity

  1. pimlock commented on Nov 8, 2026

    @pimlock
    CollaboratorAuthor

    Status

    This comment is kept up to date. Last updated 2026-11-09.

    Merged 2026-11-09

    Open PRs

    PR What State
    ai-openshell/sdk-python#13 Core sync (sdk-python#5): hourly bump PRs for new core tags, nightly drift check against core main ⬜ Needs review. CI passes. Based on main now that #12 has merged.
    ai-openshell/sdk-python#14 Release workflow (sdk-python#8): tag, PyPI trusted publishing, GitHub release when a stable pin lands ⬜ Needs review. CI passes. The pypi environment now exists (#10), so nothing blocks the merge.
    #5350 Deprecate the Python SDK in core: stop the PyPI publish and the release wheel, add the Python SDK Freeze branch check ⬜ Needs review. Must merge before core tags v0.1.8 (Tuesday 2026-11-10), or core publishes 0.1.8 to PyPI first.

    Phases

    Tracked in sdk-python

    Issue What Owner Blocked on
    ai-openshell/sdk-python#5 Bump PRs for new core releases (core-watch), nightly drift against core main (core-drift) @pimlock ⬜ In review as sdk-python#13. Unblocked: #7 is done.
    ai-openshell/sdk-python#6 E2E against the published gateway of the pinned core version @pimlock ✅ Done (closed, sdk-python#12)
    ai-openshell/sdk-python#7 GitHub App and sdk-bot environment @SDAChess ✅ Done (closed)
    ai-openshell/sdk-python#8 Release tagging and PyPI publishing with trusted publishing @pimlock ⬜ In review as sdk-python#14. Unblocked: #10 is done.
    ai-openshell/sdk-python#9 PyPI and TestPyPI trusted publisher for sdk-python @pimlock ✅ PyPI publisher added (release.yml, environment pypi); ⬜ TestPyPI not set up
    ai-openshell/sdk-python#10 pypi and testpypi environments @SDAChess ✅ Done (closed)
    ai-openshell/sdk-python#11 CI checks shared across the SDK repositories, starting with license headers

    Decisions

    • History: imported with git filter-repo and kept, as for sdk-go. The extraction and verification scripts aren't on main. They're kept at the tag migration/v0.1.7.
    • Bindings: generated with grpcio-tools from core's protos at the pinned tag (OPENSHELL_CORE_REF) and committed. openshell._proto stays as it is. Switching to Protobuf-Py (feat!: package sdk with public Buf protos ai-openshell/sdk-python#1) is a separate breaking release after the move.
    • Versions: the first release from sdk-python is 0.1.8. Core's 0.1.7 wheel is the last one core builds.
    • Release cadence: the SDK releases with core every Tuesday, from the bump PR for that core tag. No SDK-only releases in between. If an urgent fix ever needs one, a post-release (X.Y.Z.post1) is the likely option.
    • Publishing: runs from main when a stable bump PR merges, not from a pushed tag. The pypi environment allows only main, as in core.
    • No dev releases in either SDK. To try unreleased changes, install from the repository: pip install "openshell @ git+https://github.com/ai-openshell/sdk-python@main", or go get github.com/ai-openshell/sdk-go@main. sdk-python can do this because its bindings are committed, and setuptools-scm gives such a build a dev version (X.Y.Z.devN+g<sha>). Core's rolling dev release and dev wheel stay until python/ leaves core.
    • GitHub releases stay for sdk-python, mainly for the release notes: the bump PR's description plus "Matches OpenShell core vX.Y.Z", as in sdk-go. They also carry the wheel, sdist and checksums.
    • Immutable releases: decided later. Not enabled for now, since it may be too constraining while the release flows are new. No rolling dev release means we can turn it on later; sdk-python's flow (sdk-python#8) already creates a draft release, attaches the files and publishes it last, so only the repository setting would change.
    • Sync with core: copy sdk-go's approach. A bump PR for each stable core tag and for the newest pre-release; main is only checked nightly for drift. Dependabot is an alternative to evaluate later; if we switch, sdk-go switches too.
    • E2E split: SDK-focused suites move to sdk-python (test_sandbox_api, test_workspace_api, test_sandbox_exec_python, test_exec_admission; OIDC later). The enforcement suites stay in core and get ported to the Rust testkit.
    • Freeze in core: python/ plus tasks/scripts/generate_python_proto.py and verify-python-wheel.py, exactly the imported tree. Core-only tests moved out of python/. Deletions are allowed.
    • License headers: new files need only SPDX-License-Identifier: Apache-2.0. Existing headers keep their SPDX-FileCopyrightText line (sdk-python#11).

    Next

    • ⬜ Review and merge chore(python): deprecate the Python SDK in core #5350 before Tuesday's v0.1.8 tag. CI is green; no review yet.
    • ⬜ Review sdk-python#13 (sync) and sdk-python#14 (release). Both are based on main and pass CI. Bump PRs from Example: Run worldsim from a sandbox #13 run E2E against the proposed core version.
    • ⬜ Release 0.1.8: merge sdk-python#14. Once core tags v0.1.8, open the bump PR (mise run core:bump -- v0.1.8) and merge it; release.yml publishes. The version stays free as long as core doesn't publish it.
    • ⬜ Set up the TestPyPI publisher (sdk-python#9) if we want it.
    • ⬜ File the core cutover issue for e2e/python.

    Also open in sdk-python: Dependabot bumps (sdk-python#16–#22) and a docs PR for the usage guide and package metadata (sdk-python#23).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions