Skip to content

feat(ocap-kernel): add IO kernel service for vat I/O streams#840

Open
FUDCo wants to merge 1 commit intomainfrom
feat/io-kernel-service
Open

feat(ocap-kernel): add IO kernel service for vat I/O streams#840
FUDCo wants to merge 1 commit intomainfrom
feat/io-kernel-service

Conversation

@FUDCo
Copy link
Contributor

@FUDCo FUDCo commented Feb 13, 2026

Summary

Implements IO kernel services (#831) that enable piping data from the outside world into and out of vats via configurable IO channels.

  • Adds IOChannel / IOChannelFactory abstractions and IOManager for per-subcluster channel lifecycle management
  • Implements Unix domain socket channel (makeSocketIOChannel) in the Node.js package with line-delimited framing and single-client acceptance
  • Integrates IO channels into Kernel, SubclusterManager, and KernelServiceManager (including new unregisterKernelServiceObject)
  • Adds io config property to ClusterConfig for declaring named IO channels, wired as kernel services to bootstrap vats
  • MVP scope: socket type only, line unit, direction defaults to inout

Changes

  • packages/ocap-kernel/src/types.tsIOSpec, IOConfig types and io field on ClusterConfigStruct
  • packages/ocap-kernel/src/io/ — New IOManager, makeIOService, IOChannel/IOChannelFactory types
  • packages/ocap-kernel/src/KernelServiceManager.tsunregisterKernelServiceObject() method
  • packages/ocap-kernel/src/Kernel.tsioChannelFactory option, IOManager creation
  • packages/ocap-kernel/src/vats/SubclusterManager.ts — IO channel create/destroy in launch/terminate
  • packages/nodejs/src/io/makeSocketIOChannel (Unix domain socket), makeIOChannelFactory
  • packages/nodejs/src/kernel/make-kernel.ts — Accepts and defaults ioChannelFactory

Test plan

  • Unit tests for makeIOService (9 tests) — direction enforcement, read/write delegation
  • Unit tests for IOManager (6 tests) — create/destroy lifecycle, rollback on failure, error handling
  • Unit tests for unregisterKernelServiceObject (5 tests) — cleanup of krefs, KV entries, pins
  • Unit tests for makeSocketIOChannel (12 tests) — connection, line framing, disconnect, cleanup
  • Integration test for end-to-end IO through a vat (blocked by pre-existing @chainsafe/libp2p-quic missing package issue)

Closes #831

🤖 Generated with Claude Code


Note

Medium Risk
Touches kernel/subcluster lifecycle and service registration, so mis-ordering or cleanup bugs could leak resources or break service availability. The behavior is guarded by injection/optionality and has broad test coverage, reducing risk.

Overview
Adds a new IO kernel service layer that lets subclusters expose named IO endpoints to vats via standard kernel services. Cluster configs can now declare io channels with direction/unit metadata; the kernel creates per-subcluster channels at launch, registers them as services (wrapped by makeIOService), and tears them down on subcluster termination.

Introduces a Node.js implementation backed by Unix domain sockets (makeSocketIOChannel) plus a dispatching makeIOChannelFactory, wires this factory into makeKernel by default, and expands KernelServiceManager with unregisterKernelServiceObject for lifecycle cleanup. Adds unit tests for IO manager/service/socket behavior and an end-to-end kernel/vat integration test exercising read/write over a socket channel.

Written by Cursor Bugbot for commit 453ff26. This will update automatically on new commits. Configure here.

@FUDCo FUDCo force-pushed the feat/io-kernel-service branch 2 times, most recently from 2380261 to 95e5017 Compare February 13, 2026 22:25
Add IO channels as kernel services with read()/write() methods, configured
via a new `io` property on ClusterConfig. IO channels are ephemeral, created
at subcluster launch and destroyed at termination. MVP implements socket type
(Unix domain socket) with line unit only.

- Add IOSpec/IOConfig types and ClusterConfig.io field
- Add IOChannel/IOChannelFactory interfaces (platform-agnostic)
- Add makeIOService() exo factory with direction enforcement
- Add IOManager for per-subcluster channel lifecycle
- Add KernelServiceManager.unregisterKernelServiceObject()
- Add makeSocketIOChannel() Unix domain socket implementation (Node.js)
- Integrate IOManager into Kernel and SubclusterManager
- Wire makeIOChannelFactory into nodejs makeKernel()
- Add unit tests for io-service, IOManager, socket-channel, unregister
- Add integration test vat and test (io-vat, io.test.ts)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@FUDCo FUDCo force-pushed the feat/io-kernel-service branch from 95e5017 to 453ff26 Compare February 13, 2026 22:34
@github-actions
Copy link
Contributor

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 78.18%
⬆️ +0.18%
6479 / 8287
🔵 Statements 78.14%
⬆️ +0.18%
6582 / 8423
🔵 Functions 76.06%
⬆️ +0.11%
1624 / 2135
🔵 Branches 78.04%
⬆️ +0.04%
2393 / 3066
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/kernel-test/src/vats/io-vat.ts 0% 0% 0% 0% 20-36
packages/nodejs/src/index.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
packages/nodejs/src/io/index.ts 25% 0% 50% 25% 16-22
packages/nodejs/src/io/socket-channel.ts 93.42% 83.33% 100% 93.33% 75-76, 96, 144, 154
packages/nodejs/src/kernel/make-kernel.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
packages/ocap-kernel/src/Kernel.ts 87.61%
⬆️ +0.24%
79.41%
⬆️ +2.75%
80.43%
🟰 ±0%
87.61%
⬆️ +0.24%
129, 277-280, 297, 321, 389-399, 491, 559, 625-628, 641, 651-652, 695
packages/ocap-kernel/src/KernelServiceManager.ts 94.64%
⬆️ +0.77%
90.9%
⬆️ +0.90%
100%
🟰 ±0%
94.64%
⬆️ +0.77%
202-207
packages/ocap-kernel/src/index.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
packages/ocap-kernel/src/types.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
packages/ocap-kernel/src/io/IOManager.ts 100% 100% 100% 100%
packages/ocap-kernel/src/io/index.ts 100% 100% 100% 100%
packages/ocap-kernel/src/io/io-service.ts 100% 100% 100% 100%
packages/ocap-kernel/src/io/types.ts 100% 100% 100% 100%
packages/ocap-kernel/src/vats/SubclusterManager.ts 96.72%
⬇️ -0.71%
90.19%
⬇️ -0.92%
100%
🟰 ±0%
96.66%
⬇️ -0.73%
163, 223, 289, 295-297
Generated in workflow #3740 for commit 453ff26 by the Vitest Coverage Report Action

@FUDCo FUDCo marked this pull request as ready for review February 13, 2026 22:51
@FUDCo FUDCo requested a review from a team as a code owner February 13, 2026 22:51
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

await this.#ioManager.createChannels(subclusterId, config.io);
}

this.#validateServices(config, isSystem);
Copy link

Choose a reason for hiding this comment

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

Failed launch leaves orphaned IO resources

Medium Severity

launchSubcluster now persists the subcluster and creates IO channels before service validation, but has no rollback path if validation or vat bootstrap fails. A failed launch can leave config persisted and IO channels/services still allocated, causing later duplicate-service errors and resource leaks.

Fix in Cursor Fix in Web

// Destroy IO channels before terminating vats
if (this.#ioManager) {
await this.#ioManager.destroyChannels(subclusterId);
}
Copy link

Choose a reason for hiding this comment

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

Early IO unregister can halt kernel queue

High Severity

terminateSubcluster now unregisters IO services before vat termination. If queued messages still target those service krefs, invokeKernelService hits an unregistered target and throws, which can stop the run loop and leave the kernel non-functional.

Additional Locations (2)

Fix in Cursor Fix in Web

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.

feat(ocap-kernel): introduce IO streams for vats

1 participant