Skip to content

feat(interop): add filesystem ABI handles#1353

Merged
chaliy merged 15 commits intomainfrom
feat/fs-capsule-external-interop
Apr 30, 2026
Merged

feat(interop): add filesystem ABI handles#1353
chaliy merged 15 commits intomainfrom
feat/fs-capsule-external-interop

Conversation

@chaliy
Copy link
Copy Markdown
Contributor

@chaliy chaliy commented Apr 22, 2026

What

Add a feature-gated filesystem interop ABI owned by the core crate and expose it through Python and Node bindings.

Why

Fixes #1352. Downstream native extensions need a supported way to create filesystem implementations that bashkit can mount without sharing addon-private Rust object layouts or PyO3 class identity.

How

  • add bashkit::interop::fs behind the interop cargo feature
  • define a versioned repr(C) filesystem handle + vtable for cross-addon/native-extension interop
  • expose Python FileSystem.from_capsule() / to_capsule() using the core ABI
  • keep Node FileSystem.fromExternal() / toExternal() using the same core ABI
  • remove the standalone bashkit-fs-interop crate
  • update docs, specs, and regression tests for Python and Node roundtrips

Example

Downstream package wrapper:

# github_fs/__init__.py
from bashkit import FileSystem
from ._native import create_filesystem_capsule


def create_filesystem(config: dict) -> FileSystem:
    return FileSystem.from_capsule(create_filesystem_capsule(config))

Downstream PyO3 extension:

use bashkit::interop::fs::export_filesystem;
use bashkit::FileSystem;
use pyo3::exceptions::PyRuntimeError;
use pyo3::prelude::*;
use pyo3::types::PyCapsule;
use std::sync::Arc;

const FILESYSTEM_CAPSULE_NAME: &std::ffi::CStr = c"bashkit.FileSystem.v1";

#[pyfunction]
fn create_filesystem_capsule(py: Python<'_>, config: Bound<'_, PyAny>) -> PyResult<Py<PyCapsule>> {
    let fs: Arc<dyn FileSystem> = Arc::new(MyRemoteFs::from_config(config)?);
    let handle = export_filesystem(fs).map_err(|err| PyRuntimeError::new_err(err.to_string()))?;
    let capsule = PyCapsule::new(py, handle, Some(FILESYSTEM_CAPSULE_NAME.to_owned()))?;
    Ok(capsule.unbind())
}

#[pymodule]
fn _native(module: &Bound<'_, PyModule>) -> PyResult<()> {
    module.add_function(wrap_pyfunction!(create_filesystem_capsule, module)?)?;
    Ok(())
}

End-user code:

from bashkit import Bash
from github_fs import create_filesystem

fs = create_filesystem({"repo": "everruns/bashkit", "token": "..."})

bash = Bash()
bash.mount("/workspace", fs)

result = bash.execute_sync("cat /workspace/README.md")
print(result.stdout)

Risk

  • Medium
  • The new ABI is public native-extension surface area; versioning and handle ownership are the main compatibility risks
  • Binding APIs are additive, while Node wrapper internals changed to route filesystem handles through opaque native state

Checklist

  • Tests added or updated
  • Backward compatibility considered

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Apr 22, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
bashkit ad3d96d Commit Preview URL

Branch Preview URL
Apr 30 2026, 05:48 AM

Comment thread crates/bashkit-js/src/lib.rs Fixed
Comment thread crates/bashkit-js/src/lib.rs Fixed
@chaliy chaliy force-pushed the feat/fs-capsule-external-interop branch from ec711ba to 5c470d2 Compare April 30, 2026 02:51
@chaliy chaliy requested a review from Copilot April 30, 2026 04:08
@chaliy chaliy changed the title feat(bindings): add filesystem interop handles feat(interop): add filesystem ABI handles Apr 30, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a stable, cross-addon filesystem handle contract and exposes it through the Python and Node.js bindings so downstream native extensions can construct and mount bashkit-owned filesystem handles.

Changes:

  • Introduce bashkit::interop::fs (behind the interop cargo feature) implementing a versioned repr(C) filesystem handle + vtable contract.
  • Add Python FileSystem.to_capsule() / FileSystem.from_capsule() plus regression test coverage and docs.
  • Add Node.js standalone FileSystem wrapper with toExternal() / fromExternal() and support for mounting FileSystem objects into Bash/BashTool, plus tests and docs/spec updates.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
specs/vfs.md Documents filesystem concepts parity and binding-specific interop APIs/contracts.
crates/bashkit/src/lib.rs Exposes interop module behind the interop feature.
crates/bashkit/src/interop/mod.rs Adds interop module root.
crates/bashkit/src/interop/fs.rs Implements the stable ABI handle/vtable, import/export, and Rust-side roundtrip tests.
crates/bashkit/Cargo.toml Adds interop feature (tokio multi-thread runtime support).
crates/bashkit-python/tests/_bashkit_categories.py Adds capsule roundtrip + mount integration regression test.
crates/bashkit-python/src/lib.rs Implements FileSystem.from_capsule() and to_capsule() in PyO3 binding.
crates/bashkit-python/bashkit/_bashkit.pyi Adds type stubs for capsule interop APIs.
crates/bashkit-python/README.md Documents native-extension interop usage and API list updates.
crates/bashkit-python/Cargo.toml Enables bashkit interop feature for the Python binding crate.
crates/bashkit-js/wrapper.ts Adds JS FileSystem class, external interop, and overloads mount() to accept FileSystem.
crates/bashkit-js/src/lib.rs Adds NAPI exports for standalone FS ops, external import/export, and filesystem mounting.
crates/bashkit-js/test/vfs.spec.ts Adds external roundtrip + mount regression test.
crates/bashkit-js/README.md Documents standalone FileSystem, mounting, and addon interop.
crates/bashkit-js/Cargo.toml Enables bashkit interop feature for the Node binding crate.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/bashkit/src/interop/fs.rs
Comment thread crates/bashkit-js/src/lib.rs Outdated
Comment thread crates/bashkit-js/src/lib.rs
Comment thread crates/bashkit-js/wrapper.ts
Comment thread crates/bashkit-js/wrapper.ts
Comment thread crates/bashkit/src/interop/fs.rs Outdated
@chaliy chaliy force-pushed the feat/fs-capsule-external-interop branch from 5c470d2 to 6c5398e Compare April 30, 2026 04:59
Comment thread crates/bashkit-js/src/lib.rs Fixed
@chaliy chaliy force-pushed the feat/fs-capsule-external-interop branch from c7b2ae0 to ad3d96d Compare April 30, 2026 05:47
@chaliy chaliy merged commit 8f21392 into main Apr 30, 2026
34 checks passed
@chaliy chaliy deleted the feat/fs-capsule-external-interop branch April 30, 2026 05:59
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 30, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add FileSystem.from_capsule() for custom FsBackend integration from downstream extensions

3 participants