You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maka.apache.org by wy...@apache.org on 2026/08/26 16:44:23 UTC

(maka) 01/01: feat(desktop): onboard experimental direct peer hosts

This is an automated email from the ASF dual-hosted git repository.

M4n5ter pushed a commit to branch feat/runtime-host-direct-peer-desktop
in repository https://gitbox.apache.org/repos/asf/maka.git

commit 0775061140437a383d82540ec965c22258da619a
Author: Wang <m4...@gmail.com>
AuthorDate: Thu Aug 27 00:44:05 2026 +0800

    feat(desktop): onboard experimental direct peer hosts
    
    Manage the peer listener through the existing SSH channel while keeping SSH and Direct as separate Host profiles. Ship the native peer client in Desktop artifacts and verify the complete managed flow.
    
    Generated-by: OpenAI Codex
---
 .github/workflows/release-windows-check.yml        |   8 ++
 .github/workflows/release.yml                      |   3 +
 apps/desktop/electron-builder.config.mjs           |   8 ++
 .../main/__tests__/runtime-host-management.test.ts | 111 +++++++++++++++
 .../__tests__/runtime-host-profile-service.test.ts |  43 ++++++
 apps/desktop/src/main/runtime-host-boot.ts         |   9 ++
 apps/desktop/src/main/runtime-host-management.ts   | 126 +++++++++++++++++
 apps/desktop/src/main/runtime-host-peer-client.ts  |  59 ++++++++
 .../src/main/runtime-host-profile-service.ts       | 119 +++++++++++++++-
 apps/desktop/src/main/runtime-host-ssh-terminal.ts |  47 +++++++
 apps/desktop/src/preload/bridge-contract.d.ts      |  14 ++
 apps/desktop/src/preload/preload.ts                |  15 ++
 .../src/renderer/locales/settings-projects-copy.ts |  55 ++++++++
 .../settings/runtime-host-management-dialog.tsx    | 155 +++++++++++++++++++++
 .../settings/runtime-host-profiles-section.tsx     |  97 +++++++------
 .../src/renderer/styles/settings/runtime-host.css  |   3 +-
 docs/runtime-host-remote-access.md                 |   9 +-
 docs/runtime-host-remote-access.zh-CN.md           |   7 +-
 .../__tests__/runtime-host-service-manager.test.ts |   2 +
 packages/cli/src/cli-core.ts                       |   1 +
 packages/cli/src/runtime-host-cli.ts               |   3 +
 .../src/runtime-host-peer-management-command.ts    |  53 ++++---
 .../src/__tests__/peer-management-frame.test.ts    |  44 ++++++
 packages/runtime-host/src/operator/index.ts        |   8 ++
 .../src/operator/peer-management-frame.ts          | 105 ++++++++++++++
 scripts/ci-test-plan.test.mjs                      |   1 +
 scripts/package-macos-arm64.mjs                    |   2 +
 scripts/package-windows-x64.mjs                    |   2 +
 scripts/verify-packaged-app.mjs                    |   9 ++
 scripts/verify-packaged-app.test.mjs               |   1 +
 scripts/verify-windows-x64.mjs                     |   1 +
 31 files changed, 1053 insertions(+), 67 deletions(-)

diff --git a/.github/workflows/release-windows-check.yml b/.github/workflows/release-windows-check.yml
index b9af2e82a..27f00430d 100644
--- a/.github/workflows/release-windows-check.yml
+++ b/.github/workflows/release-windows-check.yml
@@ -32,7 +32,12 @@ on:
     paths:
       - 'apps/desktop/electron-builder.config.mjs'
       - 'apps/desktop/package.json'
+      - 'native/runtime-host-peer/**'
+      - 'packages/cli/RUNTIME_HOST_PEER_DEPENDENCIES.rust.tsv'
+      - 'packages/cli/RUNTIME_HOST_PEER_THIRD_PARTY_NOTICES.txt'
       - 'scripts/package-windows-x64.mjs'
+      - 'scripts/generate-runtime-host-peer-dependencies.mjs'
+      - 'scripts/generate-runtime-host-peer-notices.mjs'
       - 'scripts/verify-windows-x64.mjs'
       - 'scripts/verify-windows-sandbox-e2e.mjs'
       - 'scripts/verify-windows-installer-lifecycle.mjs'
@@ -119,6 +124,9 @@ jobs:
       - name: Install dependencies
         run: npm ci
 
+      - name: Update stable Rust for Desktop native artifacts
+        run: rustup update stable --no-self-update
+
       - name: Package the Windows installer and ZIP
         run: npm run package:windows-x64
 
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 32d10e180..bf7e5eb18 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -137,6 +137,9 @@ jobs:
       - name: Audit shipped desktop closure
         run: node scripts/audit-shipped-dependencies.mjs
 
+      - name: Update stable Rust for Desktop native artifacts
+        run: rustup update stable --no-self-update
+
       - name: Write App Store Connect API key
         if: matrix.platform == 'macos'
         env:
diff --git a/apps/desktop/electron-builder.config.mjs b/apps/desktop/electron-builder.config.mjs
index 9560169bd..5ab19612c 100644
--- a/apps/desktop/electron-builder.config.mjs
+++ b/apps/desktop/electron-builder.config.mjs
@@ -89,6 +89,14 @@ export default {
       from: 'resources/workers/filesystem-worker.js',
       to: 'workers/filesystem-worker.js',
     },
+    {
+      from: '../../native/runtime-host-peer/target/release/maka_runtime_host_peer.node',
+      to: 'runtime-host-peer/maka_runtime_host_peer.node',
+    },
+    {
+      from: '../../packages/cli/RUNTIME_HOST_PEER_THIRD_PARTY_NOTICES.txt',
+      to: 'licenses/runtime-host-peer/THIRD_PARTY_NOTICES.txt',
+    },
     ...(process.platform === 'win32'
       ? [
           {
diff --git a/apps/desktop/src/main/__tests__/runtime-host-management.test.ts b/apps/desktop/src/main/__tests__/runtime-host-management.test.ts
index 2c30c6da1..abba0a097 100644
--- a/apps/desktop/src/main/__tests__/runtime-host-management.test.ts
+++ b/apps/desktop/src/main/__tests__/runtime-host-management.test.ts
@@ -73,6 +73,7 @@ test('identifies, rotates, and revokes managed credentials without exposing secr
       removeHandler: (channel) => handlers.delete(channel),
     },
     profiles: {
+      ...unusedDirectPeerProfileDependencies(),
       resolveManagedService: async () => ({ profile, service, state: 'active' as const }),
       resolveManagedAccess: async () => ({
         profile,
@@ -215,6 +216,7 @@ test('manages only the service identity bound by Desktop onboarding', async () =
       removeHandler: (channel) => handlers.delete(channel),
     },
     profiles: {
+      ...unusedDirectPeerProfileDependencies(),
       resolveManagedService: async (profileId) =>
         profileId === managedProfile.id
           ? { profile: managedProfile, service: managedService, state: 'active' as const }
@@ -361,6 +363,7 @@ test('publishes update progress and waits for the managed profile to reconnect',
       removeHandler: (channel) => handlers.delete(channel),
     },
     profiles: {
+      ...unusedDirectPeerProfileDependencies(),
       resolveManagedService: async () =>
         bindingPresent ? { profile, service, state: 'active' as const } : undefined,
       resolveManagedAccess: async () => undefined,
@@ -370,6 +373,8 @@ test('publishes update progress and waits for the managed profile to reconnect',
       clearManagedServiceBinding: async () => undefined,
     },
     runServiceManagement: async () => assert.fail('ordinary management is not expected'),
+    runPeerManagement: async () => assert.fail('direct peer management is not expected'),
+    directPeerClientAvailable: false,
     runUpdate: async (input, onProgress) => {
       updates.push(input);
       onProgress('staging');
@@ -481,6 +486,7 @@ test('configures Project roots with CAS and reconnects only after a committed cu
       removeHandler: (channel) => handlers.delete(channel),
     },
     profiles: {
+      ...unusedDirectPeerProfileDependencies(),
       resolveManagedService: async () => ({ profile, service, state: 'active' as const }),
       resolveManagedAccess: async () => undefined,
       rotateManagedCredential: async () => assert.fail('credential rotation is not expected'),
@@ -588,6 +594,7 @@ test('manages one Host update policy and reconciles it through the bound operato
       removeHandler: (channel) => handlers.delete(channel),
     },
     profiles: {
+      ...unusedDirectPeerProfileDependencies(),
       resolveManagedService: async () => ({ profile, service, state: 'active' as const }),
       resolveManagedAccess: async () => undefined,
       rotateManagedCredential: async () => assert.fail('credential rotation is not expected'),
@@ -733,6 +740,7 @@ test('resumes deployment cleanup without invoking the removed operator', async (
       removeHandler: (channel) => handlers.delete(channel),
     },
     profiles: {
+      ...unusedDirectPeerProfileDependencies(),
       resolveManagedService: async () => ({ profile, service, state }),
       resolveManagedAccess: async () => undefined,
       markManagedServiceUninstalling: async (binding) => {
@@ -785,6 +793,7 @@ test('rechecks uninstall intent before retrying the remote service', async () =>
       removeHandler: (channel) => handlers.delete(channel),
     },
     profiles: {
+      ...unusedDirectPeerProfileDependencies(),
       resolveManagedService: async () => ({
         profile: {
           id: 'office',
@@ -834,6 +843,94 @@ test('rechecks uninstall intent before retrying the remote service', async () =>
   assert.equal(marked, true);
 });
 
+test('keeps the SSH profile while adding and removing its managed Direct peer', async () => {
+  const handlers = new Map<string, (...args: unknown[]) => unknown>();
+  const profile = {
+    id: 'office',
+    name: 'Office',
+    kind: 'remote' as const,
+    rootId: 'a'.repeat(64),
+    transport: {
+      kind: 'ssh' as const,
+      destination: 'operator@example.com',
+      remotePort: 7443,
+      websocketPath: '/runtime-host',
+    },
+  };
+  const service = {
+    id: 'b'.repeat(64),
+    rootPath: '/srv/maka',
+    operatorPath: '/home/operator/.local/share/maka/operator',
+  };
+  let peerProfileExists = false;
+  const actions: string[] = [];
+
+  createDesktopRuntimeHostManagement({
+    ...unusedUpdateDependencies(),
+    ipcMain: {
+      handle: (channel, handler) => handlers.set(channel, handler as (...args: unknown[]) => unknown),
+      removeHandler: (channel) => handlers.delete(channel),
+    },
+    profiles: {
+      ...unusedDirectPeerProfileDependencies(),
+      resolveManagedService: async () => ({ profile, service, state: 'active' as const }),
+      resolveManagedAccess: async () => undefined,
+      rotateManagedCredential: async () => assert.fail('credential rotation is not expected'),
+      markManagedServiceUninstalling: async (binding) => binding,
+      markManagedServiceCleanupPending: async (binding) => binding,
+      clearManagedServiceBinding: async () => undefined,
+      resolveManagedDirectPeerProfile: async () => ({
+        profileId: 'direct-office',
+        exists: peerProfileExists,
+        enabled: false,
+      }),
+      upsertManagedDirectPeerProfile: async (_profileId, descriptor) => {
+        assert.equal(descriptor.rootId, profile.rootId);
+        assert.deepEqual(descriptor.routeHints, ['/ip4/192.0.2.8/udp/44001/quic-v1']);
+        peerProfileExists = true;
+        return 'direct-office';
+      },
+      removeManagedDirectPeerProfile: async () => {
+        peerProfileExists = false;
+      },
+    },
+    directPeerClientAvailable: true,
+    runServiceManagement: async () => assert.fail('service management is not expected'),
+    runAccessManagement: async () => assert.fail('access management is not expected'),
+    runPeerManagement: async (input) => {
+      actions.push(input.action);
+      return {
+        kind: 'result',
+        action: input.action,
+        status: input.action === 'disable'
+          ? {
+              state: 'not_configured',
+              serviceState: 'running',
+              routeHints: [],
+              coordinationRelays: [],
+            }
+          : {
+              state: 'enabled',
+              serviceState: 'running',
+              peerId: '12D3KooWpeer',
+              rootId: profile.rootId,
+              routeHints: ['/ip4/192.0.2.8/udp/44001/quic-v1'],
+              coordinationRelays: [],
+            },
+      };
+    },
+    cleanupManagedDeployment: async () => assert.fail('cleanup is not expected'),
+  });
+
+  const configure = handlers.get('runtime-host-management:configure-direct-peer');
+  assert.ok(configure);
+  const enabled = await configure({}, profile.id, true, []);
+  assert.equal((enabled as { profilePresent: boolean }).profilePresent, true);
+  const disabled = await configure({}, profile.id, false, []);
+  assert.equal((disabled as { profilePresent: boolean }).profilePresent, false);
+  assert.deepEqual(actions, ['enable', 'disable']);
+});
+
 function serviceResult(
   action: DesktopRuntimeHostSshManagementInput['action'],
   operatorAccess = false,
@@ -884,6 +981,9 @@ function unusedUpdateDependencies() {
     runUpdatePolicy: async (): Promise<never> => assert.fail('update policy is not expected'),
     runUpdateReconciliation: async (): Promise<never> =>
       assert.fail('update reconciliation is not expected'),
+    runPeerManagement: async (): Promise<never> =>
+      assert.fail('direct peer management is not expected'),
+    directPeerClientAvailable: false,
     resolveUpdatePackage: () => ({ kind: 'npm', specifier: 'maka-agent@1.2.3' } as const),
     currentHostEpoch: () => undefined,
     awaitUpdatedConnection: async () => undefined,
@@ -891,6 +991,17 @@ function unusedUpdateDependencies() {
   };
 }
 
+function unusedDirectPeerProfileDependencies() {
+  return {
+    resolveManagedDirectPeerProfile: async (): Promise<never> =>
+      assert.fail('direct peer profile inspection is not expected'),
+    upsertManagedDirectPeerProfile: async (): Promise<never> =>
+      assert.fail('direct peer profile creation is not expected'),
+    removeManagedDirectPeerProfile: async (): Promise<never> =>
+      assert.fail('direct peer profile removal is not expected'),
+  };
+}
+
 function accessCredential(
   credentialId: string,
   principalId: string,
diff --git a/apps/desktop/src/main/__tests__/runtime-host-profile-service.test.ts b/apps/desktop/src/main/__tests__/runtime-host-profile-service.test.ts
index 3ccb04e3f..c2a39810d 100644
--- a/apps/desktop/src/main/__tests__/runtime-host-profile-service.test.ts
+++ b/apps/desktop/src/main/__tests__/runtime-host-profile-service.test.ts
@@ -523,6 +523,49 @@ test("finishes a persisted pairing after Desktop restarts before finalization",
   );
 });
 
+test("adds a removable Direct route without replacing its managed SSH profile", async () => {
+  const root = await clientRoot();
+  const catalog = createClientRuntimeHostProfileCatalog(root);
+  const managedServices = createDesktopRuntimeHostManagedServiceStore(root);
+  await catalog.create(MANAGED_PROFILE, "owner-token");
+  await managedServices.save(MANAGED_PROFILE, MANAGED_SERVICE);
+  const startup = await resolveDesktopRuntimeHostStartup(root, { catalog });
+  const service = createDesktopRuntimeHostProfileService({
+    clientDataRoot: root,
+    startup,
+    catalog,
+    managedServices,
+    states: () => [connectingLocal()],
+    enable: async () => undefined,
+    disable: async () => undefined,
+    setDefault: () => undefined,
+    finalizePairing: async () => undefined,
+  });
+
+  const directId = await service.upsertManagedDirectPeerProfile(MANAGED_PROFILE.id, {
+    peerId: "12D3KooWpeer",
+    rootId: MANAGED_PROFILE.rootId,
+    routeHints: ["/ip4/192.0.2.8/udp/44001/quic-v1"],
+    coordinationRelays: [],
+  });
+
+  const direct = await catalog.resolve(directId);
+  assert.equal(direct.credential, "owner-token");
+  assert.equal(direct.profile.kind, "remote");
+  if (direct.profile.kind !== "remote") assert.fail("expected a remote Direct profile");
+  assert.deepEqual(direct.profile.transport, {
+    kind: "libp2p-direct",
+    peerId: "12D3KooWpeer",
+    routeHints: ["/ip4/192.0.2.8/udp/44001/quic-v1"],
+    coordinationRelays: [],
+  });
+  assert.equal((await catalog.resolve(MANAGED_PROFILE.id)).credential, "owner-token");
+
+  await service.removeManagedDirectPeerProfile(MANAGED_PROFILE.id);
+
+  assert.deepEqual((await catalog.read()).profiles, [MANAGED_PROFILE]);
+});
+
 test("recovers interrupted managed credential rotation after restart", async () => {
   const root = await clientRoot();
   const catalog = createClientRuntimeHostProfileCatalog(root);
diff --git a/apps/desktop/src/main/runtime-host-boot.ts b/apps/desktop/src/main/runtime-host-boot.ts
index bee614b76..520cdab7a 100644
--- a/apps/desktop/src/main/runtime-host-boot.ts
+++ b/apps/desktop/src/main/runtime-host-boot.ts
@@ -168,6 +168,7 @@ import {
   createDesktopRuntimeHostSshTerminal,
 } from "./runtime-host-ssh-terminal.js";
 import { createRuntimeHostSetupPackageResolver } from "./runtime-host-setup-package.js";
+import { configureDesktopRuntimeHostPeerClient } from './runtime-host-peer-client.js';
 import { createDesktopRuntimeHostOnboarding } from "./runtime-host-onboarding.js";
 import { createDesktopRuntimeHostManagement } from "./runtime-host-management.js";
 import { registerRuntimeHostOAuthIpc } from "./runtime-host-oauth-ipc-main.js";
@@ -213,6 +214,12 @@ await resolveShellEnv();
 const MANAGED_UPDATE_RECONNECT_TIMEOUT_MS = 10_000;
 const buildInfo = resolveBuildInfo(app.isPackaged, app.getAppPath());
 const userDataDir = app.getPath("userData");
+const runtimeHostDirectPeerAvailable = await configureDesktopRuntimeHostPeerClient({
+  isPackaged: app.isPackaged,
+  appPath: app.getAppPath(),
+  resourcesPath: process.resourcesPath,
+  clientDataRoot: userDataDir,
+});
 const runtimeHostClientInstanceId = await loadOrCreateRuntimeHostClientInstanceId(
   join(userDataDir, "runtime-host-client.json"),
 );
@@ -451,6 +458,8 @@ const runtimeHostManagement = createDesktopRuntimeHostManagement({
   ipcMain,
   profiles: runtimeHostProfileService,
   runServiceManagement: runtimeHostSshTerminal.runServiceManagement,
+  runPeerManagement: runtimeHostSshTerminal.runPeerManagement,
+  directPeerClientAvailable: runtimeHostDirectPeerAvailable,
   runUpdate: runtimeHostSshTerminal.runUpdate,
   runUpdatePolicy: runtimeHostSshTerminal.runUpdatePolicy,
   runUpdateReconciliation: runtimeHostSshTerminal.runUpdateReconciliation,
diff --git a/apps/desktop/src/main/runtime-host-management.ts b/apps/desktop/src/main/runtime-host-management.ts
index dbf777e71..772aea575 100644
--- a/apps/desktop/src/main/runtime-host-management.ts
+++ b/apps/desktop/src/main/runtime-host-management.ts
@@ -24,10 +24,13 @@ import {
   runtimeHostAccessCredentialFingerprint,
   type RuntimeHostManagedUpdatePolicy,
   type RuntimeHostAccessManagementFrame,
+  type RuntimeHostPeerManagementFrame,
+  type RuntimeHostPeerStatus,
   type RuntimeHostServiceManagementFrame,
 } from '@maka/runtime-host/operator';
 import type {
   DesktopRuntimeHostAccessSnapshot,
+  DesktopRuntimeHostDirectPeerSnapshot,
   DesktopRuntimeHostManagementAction,
   DesktopRuntimeHostManagementResponse,
   DesktopRuntimeHostManagementProgress,
@@ -41,6 +44,7 @@ import type {
   DesktopRuntimeHostSshCleanupInput,
   DesktopRuntimeHostSshAccessInput,
   DesktopRuntimeHostSshManagementInput,
+  DesktopRuntimeHostSshPeerManagementInput,
   DesktopRuntimeHostSshUpdateInput,
   DesktopRuntimeHostSshUpdatePolicyInput,
   DesktopRuntimeHostSshUpdateReconciliationInput,
@@ -74,6 +78,9 @@ export function createDesktopRuntimeHostManagement(input: {
     | 'markManagedServiceUninstalling'
     | 'markManagedServiceCleanupPending'
     | 'clearManagedServiceBinding'
+    | 'resolveManagedDirectPeerProfile'
+    | 'upsertManagedDirectPeerProfile'
+    | 'removeManagedDirectPeerProfile'
   >;
   readonly runServiceManagement: (
     input: DesktopRuntimeHostSshManagementInput,
@@ -81,6 +88,10 @@ export function createDesktopRuntimeHostManagement(input: {
   readonly runAccessManagement: (
     input: DesktopRuntimeHostSshAccessInput,
   ) => Promise<RuntimeHostAccessManagementFrame>;
+  readonly runPeerManagement: (
+    input: DesktopRuntimeHostSshPeerManagementInput,
+  ) => Promise<RuntimeHostPeerManagementFrame>;
+  readonly directPeerClientAvailable: boolean;
   readonly runUpdate: (
     input: DesktopRuntimeHostSshUpdateInput,
     onProgress: (phase: DesktopRuntimeHostManagementProgress['phase']) => void,
@@ -260,6 +271,94 @@ export function createDesktopRuntimeHostManagement(input: {
     };
   };
 
+  const peerSnapshot = async (
+    profileId: string,
+    status: RuntimeHostPeerStatus,
+  ): Promise<DesktopRuntimeHostDirectPeerSnapshot> => {
+    const profile = await input.profiles.resolveManagedDirectPeerProfile(profileId);
+    return {
+      ...status,
+      profileId: profile.profileId,
+      profilePresent: profile.exists,
+      profileEnabled: profile.enabled,
+      clientAvailable: input.directPeerClientAvailable,
+    };
+  };
+
+  const getDirectPeer = async (
+    profileIdValue: unknown,
+  ): Promise<DesktopRuntimeHostDirectPeerSnapshot> => {
+    const { profileId, managed, transport, expectedTarget } =
+      await managedMutationTarget(profileIdValue);
+    const response = await input.runPeerManagement({
+      destination: transport.destination,
+      ...(transport.sshPort === undefined ? {} : { sshPort: transport.sshPort }),
+      operatorPath: managed.service.operatorPath,
+      action: 'status',
+      expectedTarget,
+    });
+    if (response.kind !== 'result') {
+      throw new Error(
+        response.kind === 'error'
+          ? response.error.message
+          : 'Runtime Host returned an unrelated direct-peer result',
+      );
+    }
+    return peerSnapshot(profileId, response.status);
+  };
+
+  const configureDirectPeer = async (
+    profileIdValue: unknown,
+    enabledValue: unknown,
+    coordinationRelaysValue: unknown,
+  ): Promise<DesktopRuntimeHostDirectPeerSnapshot> => {
+    if (typeof enabledValue !== 'boolean') {
+      throw new Error('Runtime Host direct-peer state is invalid');
+    }
+    const coordinationRelays = requireCoordinationRelays(coordinationRelaysValue);
+    const { profileId, managed, transport, expectedTarget } =
+      await managedMutationTarget(profileIdValue);
+    const peerProfile = await input.profiles.resolveManagedDirectPeerProfile(profileId);
+    if (peerProfile.enabled) {
+      throw new Error('Disable the Direct peer profile before changing its listener');
+    }
+    const response = await input.runPeerManagement({
+      destination: transport.destination,
+      ...(transport.sshPort === undefined ? {} : { sshPort: transport.sshPort }),
+      operatorPath: managed.service.operatorPath,
+      action: enabledValue ? 'enable' : 'disable',
+      ...(enabledValue ? { coordinationRelays } : {}),
+      expectedTarget,
+    });
+    if (response.kind !== 'result') {
+      throw new Error(
+        response.kind === 'error'
+          ? response.error.message
+          : 'Runtime Host returned an unrelated direct-peer result',
+      );
+    }
+    const status = response.status;
+    if (enabledValue) {
+      if (
+        status.state !== 'enabled' ||
+        !status.peerId ||
+        status.rootId !== expectedTarget.rootId ||
+        status.routeHints.length === 0
+      ) {
+        throw new Error('Runtime Host did not return a usable direct-peer descriptor');
+      }
+      await input.profiles.upsertManagedDirectPeerProfile(profileId, {
+        peerId: status.peerId,
+        rootId: status.rootId,
+        routeHints: status.routeHints,
+        coordinationRelays: status.coordinationRelays,
+      });
+    } else {
+      await input.profiles.removeManagedDirectPeerProfile(profileId);
+    }
+    return peerSnapshot(profileId, status);
+  };
+
   const update = async (
     profileIdValue: unknown,
     allowInterruptActiveTasksValue: unknown,
@@ -574,6 +673,8 @@ export function createDesktopRuntimeHostManagement(input: {
     getUpdatePolicy: 'runtime-host-management:get-update-policy',
     setUpdatePolicy: 'runtime-host-management:set-update-policy',
     reconcileUpdate: 'runtime-host-management:reconcile-update',
+    getDirectPeer: 'runtime-host-management:get-direct-peer',
+    configureDirectPeer: 'runtime-host-management:configure-direct-peer',
   } as const;
   input.ipcMain.handle(channels.run, (_event, profileId: unknown, action: unknown) =>
     run(profileId, action));
@@ -613,6 +714,13 @@ export function createDesktopRuntimeHostManagement(input: {
     updatePolicy(profileId, policy));
   input.ipcMain.handle(channels.reconcileUpdate, (_event, profileId: unknown) =>
     reconcileUpdate(profileId));
+  input.ipcMain.handle(channels.getDirectPeer, (_event, profileId: unknown) =>
+    getDirectPeer(profileId));
+  input.ipcMain.handle(
+    channels.configureDirectPeer,
+    (_event, profileId: unknown, enabled: unknown, coordinationRelays: unknown) =>
+      configureDirectPeer(profileId, enabled, coordinationRelays),
+  );
 
   return {
     close() {
@@ -621,6 +729,24 @@ export function createDesktopRuntimeHostManagement(input: {
   };
 }
 
+function requireCoordinationRelays(value: unknown): readonly string[] {
+  if (
+    !Array.isArray(value) ||
+    value.length > 16 ||
+    value.some(
+      (relay) =>
+        typeof relay !== 'string' ||
+        relay.length === 0 ||
+        Buffer.byteLength(relay, 'utf8') > 2 * 1024 ||
+        /[\s\u0000-\u001f\u007f]/u.test(relay),
+    ) ||
+    new Set(value).size !== value.length
+  ) {
+    throw new Error('Runtime Host coordination relay list is invalid');
+  }
+  return value;
+}
+
 function projectUpdatePolicy(
   frame: Extract<RuntimeHostServiceManagementFrame, {
     readonly kind: 'result';
diff --git a/apps/desktop/src/main/runtime-host-peer-client.ts b/apps/desktop/src/main/runtime-host-peer-client.ts
new file mode 100644
index 000000000..395e194f9
--- /dev/null
+++ b/apps/desktop/src/main/runtime-host-peer-client.ts
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { access } from 'node:fs/promises';
+import { join } from 'node:path';
+
+const NATIVE_FILE = 'maka_runtime_host_peer.node';
+
+export async function configureDesktopRuntimeHostPeerClient(input: {
+  readonly isPackaged: boolean;
+  readonly appPath: string;
+  readonly resourcesPath: string;
+  readonly clientDataRoot: string;
+  readonly environment?: NodeJS.ProcessEnv;
+}): Promise<boolean> {
+  const environment = input.environment ?? process.env;
+  const explicitNativePath = environment.MAKA_RUNTIME_HOST_PEER_NATIVE_PATH?.trim();
+  const explicitKeyPath = environment.MAKA_RUNTIME_HOST_PEER_KEY_PATH?.trim();
+  if (explicitNativePath || explicitKeyPath) return Boolean(explicitNativePath && explicitKeyPath);
+  const nativePath = input.isPackaged
+    ? join(input.resourcesPath, 'runtime-host-peer', NATIVE_FILE)
+    : join(
+        input.appPath,
+        '..',
+        '..',
+        'native',
+        'runtime-host-peer',
+        'target',
+        'release',
+        NATIVE_FILE,
+      );
+  try {
+    await access(nativePath);
+  } catch {
+    return false;
+  }
+  environment.MAKA_RUNTIME_HOST_PEER_NATIVE_PATH = nativePath;
+  environment.MAKA_RUNTIME_HOST_PEER_KEY_PATH = join(
+    input.clientDataRoot,
+    'runtime-host-client.peer.key',
+  );
+  return true;
+}
diff --git a/apps/desktop/src/main/runtime-host-profile-service.ts b/apps/desktop/src/main/runtime-host-profile-service.ts
index 92c9aff15..afa522291 100644
--- a/apps/desktop/src/main/runtime-host-profile-service.ts
+++ b/apps/desktop/src/main/runtime-host-profile-service.ts
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-import { randomUUID } from "node:crypto";
+import { createHash, randomUUID } from "node:crypto";
 import { open, readFile, rename, rm } from "node:fs/promises";
 import { dirname, join } from "node:path";
 import {
@@ -99,6 +99,21 @@ export interface DesktopRuntimeHostProfileService {
   resolveManagedAccess(
     profileId: string,
   ): Promise<DesktopRuntimeHostManagedAccess | undefined>;
+  resolveManagedDirectPeerProfile(profileId: string): Promise<{
+    readonly profileId: string;
+    readonly exists: boolean;
+    readonly enabled: boolean;
+  }>;
+  upsertManagedDirectPeerProfile(
+    profileId: string,
+    peer: {
+      readonly peerId: string;
+      readonly rootId: string;
+      readonly routeHints: readonly string[];
+      readonly coordinationRelays: readonly string[];
+    },
+  ): Promise<string>;
+  removeManagedDirectPeerProfile(profileId: string): Promise<void>;
   clearManagedServiceBinding(expected: DesktopRuntimeHostManagedServiceBinding): Promise<void>;
   markManagedServiceUninstalling(
     expected: DesktopRuntimeHostManagedServiceBinding,
@@ -752,6 +767,96 @@ export function createDesktopRuntimeHostProfileService(input: {
           : undefined;
       });
     },
+    resolveManagedDirectPeerProfile(profileId) {
+      return mutate(async () => {
+        const peerProfileId = managedDirectPeerProfileId(profileId);
+        return {
+          profileId: peerProfileId,
+          exists: (await catalog.read()).profiles.some((profile) => profile.id === peerProfileId),
+          enabled: preferences.enabledRemoteProfileIds.includes(peerProfileId),
+        };
+      });
+    },
+    upsertManagedDirectPeerProfile(profileId, peer) {
+      return mutateProfiles(async () => {
+        assertPairingComplete(profileId);
+        const source = await catalog.resolve(profileId);
+        if (
+          source.profile.kind !== 'remote' ||
+          source.profile.transport.kind !== 'ssh' ||
+          !source.credential
+        ) {
+          throw new Error('Direct peer can only be added through a managed SSH Runtime Host');
+        }
+        const managed = findDesktopRuntimeHostManagedServiceBinding(
+          await managedServices.read(),
+          source.profile,
+        );
+        if (!managed || managed.state !== 'active') {
+          throw new Error('This Runtime Host profile is not bound to an active managed service');
+        }
+        if (peer.rootId !== source.profile.rootId || peer.routeHints.length === 0) {
+          throw new Error('Runtime Host returned an invalid direct-peer descriptor');
+        }
+        const peerProfileId = managedDirectPeerProfileId(profileId);
+        if (preferences.enabledRemoteProfileIds.includes(peerProfileId)) {
+          throw new Error('Disable the Direct peer profile before changing its listener');
+        }
+        const profile: RemoteRuntimeHostProfile = {
+          id: peerProfileId,
+          name: directPeerProfileName(source.profile.name),
+          kind: 'remote',
+          rootId: source.profile.rootId,
+          transport: {
+            kind: 'libp2p-direct',
+            peerId: peer.peerId,
+            routeHints: peer.routeHints,
+            coordinationRelays: peer.coordinationRelays,
+          },
+        };
+        const existing = (await catalog.read()).profiles.find(
+          (candidate) => candidate.id === peerProfileId,
+        );
+        if (!existing) {
+          await catalog.create(profile, source.credential);
+          return peerProfileId;
+        }
+        const previous = await catalog.resolve(peerProfileId);
+        if (previous.profile.kind !== 'remote' || previous.profile.rootId !== source.profile.rootId) {
+          throw new Error('The Direct peer profile identity is already in use');
+        }
+        const rebound = await catalog.rebindIfCurrent(previous, profile, source.credential);
+        if (!rebound.rebound) {
+          throw new Error('The Direct peer profile changed before it could be updated');
+        }
+        return peerProfileId;
+      });
+    },
+    removeManagedDirectPeerProfile(profileId) {
+      return mutateProfiles(async () => {
+        assertPairingComplete(profileId);
+        const peerProfileId = managedDirectPeerProfileId(profileId);
+        if (preferences.enabledRemoteProfileIds.includes(peerProfileId)) {
+          throw new Error('Disable the Direct peer profile before changing its listener');
+        }
+        const current = await catalog.resolve(peerProfileId).catch(() => undefined);
+        if (!current) return;
+        const source = await catalog.resolve(profileId);
+        if (
+          source.profile.kind !== 'remote' ||
+          source.profile.transport.kind !== 'ssh' ||
+          current.profile.kind !== 'remote' ||
+          current.profile.transport.kind !== 'libp2p-direct' ||
+          current.profile.rootId !== source.profile.rootId
+        ) {
+          throw new Error('The Direct peer profile identity is already in use');
+        }
+        const removed = await catalog.removeIfCurrent(current);
+        if (!removed.removed) {
+          throw new Error('The Direct peer profile changed before it could be removed');
+        }
+      });
+    },
     markManagedServiceUninstalling(expected) {
       return mutateProfiles(async () => {
         assertPairingComplete(expected.profile.id);
@@ -942,6 +1047,18 @@ export function createDesktopRuntimeHostProfileService(input: {
   };
 }
 
+function managedDirectPeerProfileId(sourceProfileId: string): string {
+  const digest = createHash('sha256').update(sourceProfileId).digest('hex').slice(0, 32);
+  return `direct-${digest}`;
+}
+
+function directPeerProfileName(sourceName: string): string {
+  const suffix = ' · Direct';
+  let name = sourceName;
+  while (Buffer.byteLength(name + suffix, 'utf8') > 128) name = name.slice(0, -1);
+  return `${name}${suffix}`;
+}
+
 async function rollbackCreatedProfile(
   catalog: RuntimeHostProfileCatalog,
   target: ResolvedRuntimeHostProfile,
diff --git a/apps/desktop/src/main/runtime-host-ssh-terminal.ts b/apps/desktop/src/main/runtime-host-ssh-terminal.ts
index beaca6e0c..170e6897f 100644
--- a/apps/desktop/src/main/runtime-host-ssh-terminal.ts
+++ b/apps/desktop/src/main/runtime-host-ssh-terminal.ts
@@ -35,6 +35,7 @@ import {
 } from '@maka/runtime-host/client';
 import {
   decodeRuntimeHostAccessManagementFrame,
+  decodeRuntimeHostPeerManagementFrame,
   decodeRuntimeHostServiceManagementFrame,
   decodeRuntimeHostSetupFrame,
   RUNTIME_HOST_ACCESS_MANAGEMENT_FRAME_PREFIX,
@@ -42,10 +43,13 @@ import {
   RUNTIME_HOST_OPERATOR_CAPABILITY_REQUEST_ENV,
   RUNTIME_HOST_OPERATOR_PROJECT_DIRECTORY_CONFIGURATION_REQUEST_ENV,
   RUNTIME_HOST_OPERATOR_UPDATE_SCHEDULER_CAPABILITY,
+  RUNTIME_HOST_PEER_MANAGEMENT_FRAME_PREFIX,
   RUNTIME_HOST_SERVICE_MANAGEMENT_FRAME_PREFIX,
   RUNTIME_HOST_SETUP_FRAME_PREFIX,
   type RuntimeHostAccessManagementFrame,
   type RuntimeHostManagedUpdatePolicy,
+  type RuntimeHostPeerManagementAction,
+  type RuntimeHostPeerManagementFrame,
   type RuntimeHostServiceManagementAction,
   type RuntimeHostServiceManagementFrame,
   type RuntimeHostServiceUpdatePhase,
@@ -78,6 +82,7 @@ const TERMINAL_OUTPUT_MAX = 64 * 1024;
 const SETUP_FRAME_PENDING_MAX = 20 * 1024;
 const MANAGEMENT_FRAME_PENDING_MAX = 128 * 1024;
 const ACCESS_MANAGEMENT_FRAME_PENDING_MAX = 768 * 1024;
+const PEER_MANAGEMENT_FRAME_PENDING_MAX = 128 * 1024;
 const SETUP_TIMEOUT_MS = 10 * 60_000;
 const MANAGEMENT_TIMEOUT_MS = 2 * 60_000;
 const PROCESS_STOP_GRACE_MS = 2_000;
@@ -140,6 +145,16 @@ export interface DesktopRuntimeHostSshUpdateReconciliationInput {
   readonly signal?: AbortSignal;
 }
 
+export interface DesktopRuntimeHostSshPeerManagementInput {
+  readonly destination: string;
+  readonly sshPort?: number;
+  readonly operatorPath: string;
+  readonly action: Extract<RuntimeHostPeerManagementAction, 'enable' | 'disable' | 'status'>;
+  readonly coordinationRelays?: readonly string[];
+  readonly expectedTarget: DesktopRuntimeHostSshManagementInput['expectedTarget'];
+  readonly signal?: AbortSignal;
+}
+
 export interface DesktopRuntimeHostSshCleanupInput {
   readonly destination: string;
   readonly sshPort?: number;
@@ -227,6 +242,9 @@ export function createDesktopRuntimeHostSshTerminal(input: {
   runAccessManagement(
     input: DesktopRuntimeHostSshAccessInput,
   ): Promise<RuntimeHostAccessManagementFrame>;
+  runPeerManagement(
+    input: DesktopRuntimeHostSshPeerManagementInput,
+  ): Promise<RuntimeHostPeerManagementFrame>;
   cleanupManagedDeployment(input: DesktopRuntimeHostSshCleanupInput): Promise<void>;
   close(): Promise<void>;
 } {
@@ -725,6 +743,17 @@ export function createDesktopRuntimeHostSshTerminal(input: {
         frameAction: (frame) => frame.action,
         label: 'Remote Runtime Host access management',
       }),
+    runPeerManagement: (peerInput) =>
+      runFramedManagement({
+        ...peerInput,
+        remoteCommand: runtimeHostPeerManagementRemoteCommand(peerInput),
+        prefix: RUNTIME_HOST_PEER_MANAGEMENT_FRAME_PREFIX,
+        pendingMaxBytes: PEER_MANAGEMENT_FRAME_PENDING_MAX,
+        decode: decodeRuntimeHostPeerManagementFrame,
+        action: peerInput.action,
+        frameAction: (frame) => frame.action,
+        label: 'Remote Runtime Host direct-peer management',
+      }),
     cleanupManagedDeployment: async (cleanupInput) => {
       if (closed) throw new Error('Runtime Host SSH terminal is closed');
       cleanupInput.signal?.throwIfAborted();
@@ -1186,6 +1215,24 @@ function runtimeHostAccessManagementRemoteCommand(
   return `exec "\${SHELL:-/bin/sh}" -lic ${quotePosix(`exec ${command}`)}`;
 }
 
+function runtimeHostPeerManagementRemoteCommand(
+  input: DesktopRuntimeHostSshPeerManagementInput,
+): string {
+  const command = [
+    input.operatorPath,
+    'peer',
+    input.action,
+    '--framed',
+    ...(input.action === 'enable' && input.coordinationRelays
+      ? input.coordinationRelays.length === 0
+        ? ['--clear-coordination-relays']
+        : input.coordinationRelays.flatMap((relay) => ['--coordination-relay', relay])
+      : []),
+    ...managedServiceTargetArgs(input.expectedTarget),
+  ].map(quotePosix).join(' ');
+  return `exec "\${SHELL:-/bin/sh}" -lic ${quotePosix(`exec ${command}`)}`;
+}
+
 function runtimeHostManagedDeploymentCleanupRemoteCommand(
   input: DesktopRuntimeHostSshCleanupInput,
 ): string {
diff --git a/apps/desktop/src/preload/bridge-contract.d.ts b/apps/desktop/src/preload/bridge-contract.d.ts
index c4bb909aa..3ba1fe060 100644
--- a/apps/desktop/src/preload/bridge-contract.d.ts
+++ b/apps/desktop/src/preload/bridge-contract.d.ts
@@ -459,6 +459,14 @@ export interface DesktopRuntimeHostManagementProgress {
     | import('@maka/runtime-host/operator').RuntimeHostServiceUpdatePhase;
 }
 
+export type DesktopRuntimeHostDirectPeerSnapshot =
+  import('@maka/runtime-host/operator').RuntimeHostPeerStatus & {
+    readonly profileId: string;
+    readonly profilePresent: boolean;
+    readonly profileEnabled: boolean;
+    readonly clientAvailable: boolean;
+  };
+
 type RuntimeHostUpdatePolicyResult = Extract<
   RuntimeHostServiceManagementFrame,
   { kind: 'result'; action: 'update_policy' }
@@ -638,6 +646,12 @@ export interface MakaBridge {
       policy: import('@maka/runtime-host/operator').RuntimeHostManagedUpdatePolicy,
     ): Promise<DesktopRuntimeHostUpdatePolicySnapshot>;
     reconcileUpdate(profileId: string): Promise<DesktopRuntimeHostUpdateReconciliationResponse>;
+    getDirectPeer(profileId: string): Promise<DesktopRuntimeHostDirectPeerSnapshot>;
+    configureDirectPeer(
+      profileId: string,
+      enabled: boolean,
+      coordinationRelays: readonly string[],
+    ): Promise<DesktopRuntimeHostDirectPeerSnapshot>;
     listCredentials(profileId: string): Promise<DesktopRuntimeHostAccessSnapshot>;
     rotateCredential(profileId: string): Promise<DesktopRuntimeHostAccessSnapshot>;
     revokeCredential(
diff --git a/apps/desktop/src/preload/preload.ts b/apps/desktop/src/preload/preload.ts
index 2154ea42b..dc6f56952 100644
--- a/apps/desktop/src/preload/preload.ts
+++ b/apps/desktop/src/preload/preload.ts
@@ -1300,6 +1300,21 @@ const makaBridge = {
     reconcileUpdate(profileId: string) {
       return ipcRenderer.invoke('runtime-host-management:reconcile-update', profileId);
     },
+    getDirectPeer(profileId: string) {
+      return ipcRenderer.invoke('runtime-host-management:get-direct-peer', profileId);
+    },
+    configureDirectPeer(
+      profileId: string,
+      enabled: boolean,
+      coordinationRelays: readonly string[],
+    ) {
+      return ipcRenderer.invoke(
+        'runtime-host-management:configure-direct-peer',
+        profileId,
+        enabled,
+        coordinationRelays,
+      );
+    },
     listCredentials(profileId: string): Promise<DesktopRuntimeHostAccessSnapshot> {
       return ipcRenderer.invoke('runtime-host-management:list-credentials', profileId);
     },
diff --git a/apps/desktop/src/renderer/locales/settings-projects-copy.ts b/apps/desktop/src/renderer/locales/settings-projects-copy.ts
index b8667e7c5..3f7239911 100644
--- a/apps/desktop/src/renderer/locales/settings-projects-copy.ts
+++ b/apps/desktop/src/renderer/locales/settings-projects-copy.ts
@@ -75,12 +75,27 @@ export type SettingsProjectsCopy = {
     credentialHelp: string;
     saveAndEnable: string;
     defaultBadge: string;
+    experimentalBadge: string;
     defaultDisableHelp: string;
     unavailable: string;
     manage: string;
     managementTitle(name: string): string;
     serviceStatus: string;
     serviceState: Record<import('../../preload/bridge-contract.js').DesktopRuntimeHostManagementResult['service']['state'], string>;
+    directPeer: string;
+    directPeerDescription: string;
+    directPeerState: Record<'not_configured' | 'disabled' | 'enabled' | 'unavailable', string>;
+    directPeerUnavailable: string;
+    directPeerClientUnavailable: string;
+    directPeerDisableProfileFirst: string;
+    directPeerId: string;
+    directPeerRoutes: string;
+    directPeerCoordinationRelays: string;
+    directPeerCoordinationRelaysPlaceholder: string;
+    directPeerEnable: string;
+    directPeerDisable: string;
+    directPeerAddProfile: string;
+    directPeerActionFailed: string;
     installedVersion: string;
     operatingSystem: string;
     processId: string;
@@ -291,6 +306,7 @@ const SETTINGS_PROJECTS_COPY_BY_LOCALE = {
       credentialHelp: '在远程机器使用 desktop-client preset 签发',
       saveAndEnable: '保存并启用',
       defaultBadge: '默认',
+      experimentalBadge: '实验性',
       defaultDisableHelp: '先选择另一个默认 Host,才能停用此 Host',
       unavailable: '无法连接',
       manage: '管理',
@@ -303,6 +319,25 @@ const SETTINGS_PROJECTS_COPY_BY_LOCALE = {
         running: '运行中',
         failed: '启动失败',
       },
+      directPeer: 'Direct peer(实验性)',
+      directPeerDescription: '添加一条点对点连接路径;原 SSH 连接会保留。',
+      directPeerState: {
+        not_configured: '未配置',
+        disabled: '已停用',
+        enabled: '已启用',
+        unavailable: '不可用',
+      },
+      directPeerUnavailable: '无法读取 Direct peer 状态',
+      directPeerClientUnavailable: '当前 Desktop 构建不包含 Direct peer 支持。',
+      directPeerDisableProfileFirst: '请先在 Runtime Host 列表中停用 Direct peer。',
+      directPeerId: 'Peer ID',
+      directPeerRoutes: '可用路径',
+      directPeerCoordinationRelays: '连接协调节点(可选)',
+      directPeerCoordinationRelaysPlaceholder: '多个地址用逗号分隔',
+      directPeerEnable: '启用并添加',
+      directPeerDisable: '停用',
+      directPeerAddProfile: '添加到 Desktop',
+      directPeerActionFailed: 'Direct peer 操作失败',
       installedVersion: '版本',
       operatingSystem: '系统',
       processId: '进程 ID',
@@ -513,6 +548,7 @@ const SETTINGS_PROJECTS_COPY_BY_LOCALE = {
       credentialHelp: 'Issue it on the remote machine with the desktop-client preset',
       saveAndEnable: 'Save and enable',
       defaultBadge: 'Default',
+      experimentalBadge: 'Experimental',
       defaultDisableHelp: 'Choose another default Host before disabling this Host',
       unavailable: 'Unavailable',
       manage: 'Manage',
@@ -525,6 +561,25 @@ const SETTINGS_PROJECTS_COPY_BY_LOCALE = {
         running: 'Running',
         failed: 'Failed',
       },
+      directPeer: 'Direct peer (experimental)',
+      directPeerDescription: 'Add a peer-to-peer route while keeping the existing SSH connection.',
+      directPeerState: {
+        not_configured: 'Not configured',
+        disabled: 'Disabled',
+        enabled: 'Enabled',
+        unavailable: 'Unavailable',
+      },
+      directPeerUnavailable: 'Direct peer status is unavailable',
+      directPeerClientUnavailable: 'This Desktop build does not include Direct peer support.',
+      directPeerDisableProfileFirst: 'Disable the Direct peer in the Runtime Host list first.',
+      directPeerId: 'Peer ID',
+      directPeerRoutes: 'Routes',
+      directPeerCoordinationRelays: 'Connection coordination peers (optional)',
+      directPeerCoordinationRelaysPlaceholder: 'Separate multiple addresses with commas',
+      directPeerEnable: 'Enable and add',
+      directPeerDisable: 'Disable',
+      directPeerAddProfile: 'Add to Desktop',
+      directPeerActionFailed: 'Direct peer action failed',
       installedVersion: 'Version',
       operatingSystem: 'System',
       processId: 'Process ID',
diff --git a/apps/desktop/src/renderer/settings/runtime-host-management-dialog.tsx b/apps/desktop/src/renderer/settings/runtime-host-management-dialog.tsx
index 3632c4876..6242134ab 100644
--- a/apps/desktop/src/renderer/settings/runtime-host-management-dialog.tsx
+++ b/apps/desktop/src/renderer/settings/runtime-host-management-dialog.tsx
@@ -36,6 +36,7 @@ import { uiLocaleToIntlLocale, type UiLocale } from '@maka/core/ui-locale';
 import type { RemoteRuntimeHostProfile } from '@maka/runtime-host/client';
 import type {
   DesktopRuntimeHostManagementAction,
+  DesktopRuntimeHostDirectPeerSnapshot,
   DesktopRuntimeHostManagementResult,
   DesktopRuntimeHostManagementProgress,
   DesktopRuntimeHostAccessCredential,
@@ -97,6 +98,9 @@ export function RuntimeHostManagementDialog(props: {
   const [lastUpdateOutcome, setLastUpdateOutcome] =
     useState<DesktopRuntimeHostUpdateReconciliationOutcome>();
   const [directoryPolicyEdit, setDirectoryPolicyEdit] = useState<DirectoryPolicyEdit>();
+  const [directPeer, setDirectPeer] = useState<DesktopRuntimeHostDirectPeerSnapshot>();
+  const [directPeerError, setDirectPeerError] = useState<string>();
+  const [coordinationRelays, setCoordinationRelays] = useState('');
   const nextDirectoryRootId = useRef(1);
   const logsRef = useRef<HTMLPreElement>(null);
 
@@ -117,6 +121,9 @@ export function RuntimeHostManagementDialog(props: {
     setUpdatePolicyError(undefined);
     setLastUpdateOutcome(undefined);
     setDirectoryPolicyEdit(undefined);
+    setDirectPeer(undefined);
+    setDirectPeerError(undefined);
+    setCoordinationRelays('');
     setLoading(true);
     void (async () => {
       let shouldLoadUpdatePolicy = false;
@@ -144,6 +151,14 @@ export function RuntimeHostManagementDialog(props: {
           }
         }
       }
+      if (shouldLoadUpdatePolicy) {
+        try {
+          const peer = await window.maka.runtimeHostManagement.getDirectPeer(profile.id);
+          if (!disposed) applyDirectPeer(peer);
+        } catch (failure) {
+          if (!disposed) setDirectPeerError(settingsActionErrorMessage(failure, locale));
+        }
+      }
       if (!disposed) setLoading(false);
     })();
     return () => {
@@ -195,6 +210,50 @@ export function RuntimeHostManagementDialog(props: {
     }
   }
 
+  function applyDirectPeer(snapshot: DesktopRuntimeHostDirectPeerSnapshot): void {
+    setDirectPeer(snapshot);
+    setCoordinationRelays(snapshot.coordinationRelays.join(', '));
+    setDirectPeerError(undefined);
+  }
+
+  async function reloadDirectPeer(): Promise<void> {
+    if (!profile) return;
+    setLoading(true);
+    setDirectPeerError(undefined);
+    try {
+      applyDirectPeer(await window.maka.runtimeHostManagement.getDirectPeer(profile.id));
+    } catch (failure) {
+      setDirectPeerError(settingsActionErrorMessage(failure, locale));
+    } finally {
+      setLoading(false);
+    }
+  }
+
+  async function configureDirectPeer(enabled: boolean): Promise<void> {
+    if (!profile) return;
+    setLoading(true);
+    setDirectPeerError(undefined);
+    try {
+      const relays = coordinationRelays
+        .split(',')
+        .map((relay) => relay.trim())
+        .filter(Boolean);
+      applyDirectPeer(
+        await window.maka.runtimeHostManagement.configureDirectPeer(
+          profile.id,
+          enabled,
+          relays,
+        ),
+      );
+    } catch (failure) {
+      const message = settingsActionErrorMessage(failure, locale);
+      setDirectPeerError(message);
+      toast.error(copy.directPeerActionFailed, message);
+    } finally {
+      setLoading(false);
+    }
+  }
+
   async function loadAccess(): Promise<void> {
     if (!profile) return;
     setLoading(true);
@@ -607,6 +666,102 @@ export function RuntimeHostManagementDialog(props: {
                       <Fact label={copy.stateRoot} value={service.stateRoot} wide />
                     ) : null}
                   </dl>
+                  {serviceInstalled ? (
+                    <section className="settingsRuntimeHostDirectPeer">
+                      <div className="settingsRuntimeHostUpdatePolicyHeading">
+                        <div>
+                          <Text type="body" weight="semibold">{copy.directPeer}</Text>
+                          <Text type="supporting" color="secondary">
+                            {copy.directPeerDescription}
+                          </Text>
+                        </div>
+                        <Badge
+                          variant={directPeer?.state === 'enabled' ? 'success' : 'neutral'}
+                          label={directPeer
+                            ? copy.directPeerState[directPeer.state]
+                            : copy.directPeerState.unavailable}
+                        />
+                      </div>
+                      {directPeerError ? (
+                        <Banner
+                          status="warning"
+                          title={copy.directPeerUnavailable}
+                          description={directPeerError}
+                        />
+                      ) : null}
+                      {!directPeer ? (
+                        <div className="settingsRuntimeHostUpdatePolicyActions">
+                          <Button
+                            variant="secondary"
+                            size="sm"
+                            label={copy.refresh}
+                            isDisabled={loading}
+                            onClick={() => void reloadDirectPeer()}
+                          />
+                        </div>
+                      ) : null}
+                      {directPeer && !directPeer.clientAvailable ? (
+                        <Banner status="warning" title={copy.directPeerClientUnavailable} />
+                      ) : null}
+                      {directPeer?.profileEnabled ? (
+                        <Banner status="info" title={copy.directPeerDisableProfileFirst} />
+                      ) : null}
+                      {directPeer ? (
+                        <>
+                          {directPeer.peerId ? (
+                            <dl className="settingsRuntimeHostManagementFacts">
+                              <Fact label={copy.directPeerId} value={directPeer.peerId} wide />
+                              <Fact
+                                label={copy.directPeerRoutes}
+                                value={directPeer.routeHints.join(', ') || '—'}
+                                wide
+                              />
+                            </dl>
+                          ) : null}
+                          <TextInput
+                            label={copy.directPeerCoordinationRelays}
+                            value={coordinationRelays}
+                            placeholder={copy.directPeerCoordinationRelaysPlaceholder}
+                            isDisabled={
+                              loading ||
+                              directPeer.profileEnabled ||
+                              directPeer.state === 'enabled'
+                            }
+                            onChange={setCoordinationRelays}
+                          />
+                          <div className="settingsRuntimeHostUpdatePolicyActions">
+                            <Button
+                              variant="secondary"
+                              size="sm"
+                              label={copy.refresh}
+                              isDisabled={loading}
+                              onClick={() => void reloadDirectPeer()}
+                            />
+                            <Button
+                              variant={directPeer.state === 'enabled' ? 'secondary' : 'primary'}
+                              size="sm"
+                              label={directPeer.state === 'enabled' && directPeer.profilePresent
+                                ? copy.directPeerDisable
+                                : directPeer.state === 'enabled'
+                                  ? copy.directPeerAddProfile
+                                  : copy.directPeerEnable}
+                              isDisabled={
+                                loading ||
+                                directPeer.profileEnabled ||
+                                (
+                                  !directPeer.clientAvailable &&
+                                  !(directPeer.state === 'enabled' && directPeer.profilePresent)
+                                )
+                              }
+                              onClick={() => void configureDirectPeer(
+                                !(directPeer.state === 'enabled' && directPeer.profilePresent),
+                              )}
+                            />
+                          </div>
+                        </>
+                      ) : null}
+                    </section>
+                  ) : null}
                   {serviceInstalled ? (
                     <section className="settingsRuntimeHostUpdatePolicy">
                       <div className="settingsRuntimeHostUpdatePolicyHeading">
diff --git a/apps/desktop/src/renderer/settings/runtime-host-profiles-section.tsx b/apps/desktop/src/renderer/settings/runtime-host-profiles-section.tsx
index f66e7a32e..8d1b30578 100644
--- a/apps/desktop/src/renderer/settings/runtime-host-profiles-section.tsx
+++ b/apps/desktop/src/renderer/settings/runtime-host-profiles-section.tsx
@@ -390,49 +390,56 @@ export function RuntimeHostProfilesSection(props: {
                 <ListItem
                   key={profile.id}
                   label={profile.name}
-                description={
-                  profile.transport.kind === "ssh"
-                    ? profile.transport.destination
-                    : profile.transport.kind === "libp2p-direct"
-                      ? profile.transport.peerId
-                      : profile.transport.url
-                }
-                startContent={<Cpu size={ICON_SIZE.control} aria-hidden="true" />}
-                endContent={
-                  <HStack gap={2} align="center">
-                    {entry.isDefault ? <Badge variant="neutral" label={copy.defaultBadge} /> : null}
-                    {entry.readiness === "unavailable" ? <Badge variant="neutral" label={copy.unavailable} /> : null}
-                    <Switch
-                      label={profile.name}
-                      isLabelHidden
-                      value={entry.enabled}
-                      isDisabled={switching || entry.isDefault}
-                      disabledMessage={entry.isDefault ? copy.defaultDisableHelp : undefined}
-                      onChange={(enabled) => void setEnabled(profile.id, enabled)}
-                    />
-                    <MoreMenu
-                      label={copy.moreActions(profile.name)}
-                      size="sm"
-                      items={[
-                        ...(profile.transport.kind === "ssh" && entry.managedService
-                          ? [{
-                              label: copy.manage,
-                              isDisabled: switching,
-                              onClick: () => setManagedProfile(profile),
-                            }]
-                          : []),
-                        {
-                          label: copy.remove,
-                          isDisabled:
-                            switching ||
-                            entry.enabled ||
-                            entry.isDefault,
-                          onClick: () => void remove(profile.id),
-                        },
-                      ]}
-                    />
-                  </HStack>
-                }
+                  description={
+                    profile.transport.kind === "ssh"
+                      ? profile.transport.destination
+                      : profile.transport.kind === "libp2p-direct"
+                        ? abbreviatePeerId(profile.transport.peerId)
+                        : profile.transport.url
+                  }
+                  startContent={<Cpu size={ICON_SIZE.control} aria-hidden="true" />}
+                  endContent={
+                    <HStack gap={2} align="center">
+                      {entry.isDefault ? (
+                        <Badge variant="neutral" label={copy.defaultBadge} />
+                      ) : null}
+                      {profile.transport.kind === 'libp2p-direct' ? (
+                        <Badge variant="warning" label={copy.experimentalBadge} />
+                      ) : null}
+                      {entry.readiness === "unavailable" ? (
+                        <Badge variant="neutral" label={copy.unavailable} />
+                      ) : null}
+                      <Switch
+                        label={profile.name}
+                        isLabelHidden
+                        value={entry.enabled}
+                        isDisabled={switching || entry.isDefault}
+                        disabledMessage={entry.isDefault ? copy.defaultDisableHelp : undefined}
+                        onChange={(enabled) => void setEnabled(profile.id, enabled)}
+                      />
+                      <MoreMenu
+                        label={copy.moreActions(profile.name)}
+                        size="sm"
+                        items={[
+                          ...(profile.transport.kind === "ssh" && entry.managedService
+                            ? [{
+                                label: copy.manage,
+                                isDisabled: switching,
+                                onClick: () => setManagedProfile(profile),
+                              }]
+                            : []),
+                          {
+                            label: copy.remove,
+                            isDisabled:
+                              switching ||
+                              entry.enabled ||
+                              entry.isDefault,
+                            onClick: () => void remove(profile.id),
+                          },
+                        ]}
+                      />
+                    </HStack>
+                  }
                 />
               );
             })}
@@ -459,6 +466,10 @@ export function RuntimeHostProfilesSection(props: {
   );
 }
 
+function abbreviatePeerId(peerId: string): string {
+  return peerId.length <= 20 ? peerId : `${peerId.slice(0, 10)}…${peerId.slice(-6)}`;
+}
+
 function createTransport(draft: ReturnType<typeof createRemoteHostDraft>): RuntimeHostRemoteTransport {
   if (draft.transportKind === "tls") return { kind: "tls", url: draft.url };
   if (draft.transportKind === "plaintext") {
diff --git a/apps/desktop/src/renderer/styles/settings/runtime-host.css b/apps/desktop/src/renderer/styles/settings/runtime-host.css
index f0e7db6ce..a05e7b8d0 100644
--- a/apps/desktop/src/renderer/styles/settings/runtime-host.css
+++ b/apps/desktop/src/renderer/styles/settings/runtime-host.css
@@ -148,7 +148,8 @@
   gap: var(--space-2);
 }
 
-.settingsRuntimeHostUpdatePolicy {
+.settingsRuntimeHostUpdatePolicy,
+.settingsRuntimeHostDirectPeer {
   display: grid;
   gap: var(--space-3);
   padding: var(--space-3);
diff --git a/docs/runtime-host-remote-access.md b/docs/runtime-host-remote-access.md
index e6a07fb16..b0baccc2e 100644
--- a/docs/runtime-host-remote-access.md
+++ b/docs/runtime-host-remote-access.md
@@ -104,9 +104,12 @@ ready; failure restores the previous service.
 
 ### Experimental direct peer
 
-The released CLI includes the native direct-peer transport for CLI and TUI use; the Host does not
-need Rust or a source checkout. Desktop support is not part of this milestone. After managed setup,
-enable it against the exact service target printed by setup:
+The released CLI and Desktop include the native direct-peer transport; the Host does not need Rust
+or a source checkout. For an SSH-managed Host, Desktop can enable it from that computer's management
+dialog and creates a separate experimental profile without deleting the SSH profile. Only one
+profile for the same State Root can be enabled at a time.
+
+The equivalent CLI flow uses the exact service target printed by setup:
 
 ```sh
 maka runtime-host service peer enable \
diff --git a/docs/runtime-host-remote-access.zh-CN.md b/docs/runtime-host-remote-access.zh-CN.md
index ee607cc00..a98625064 100644
--- a/docs/runtime-host-remote-access.zh-CN.md
+++ b/docs/runtime-host-remote-access.zh-CN.md
@@ -92,8 +92,11 @@ service;未指定 WebSocket port 时会保留现有端口。卸载 npm 包前
 
 ### 实验性 direct peer
 
-发布版 CLI 已包含供 CLI 和 TUI 使用的 direct peer native transport,Host 无需安装 Rust 或保留源码;
-Desktop 支持不在本里程碑范围内。完成 managed setup 后,使用 setup 输出的精确 service target 启用:
+发布版 CLI 与 Desktop 已包含 direct peer native transport,Host 无需安装 Rust 或保留源码。对于通过 SSH
+管理的 Host,可以在 Desktop 的电脑管理界面启用;Desktop 会创建独立的实验性 profile,不删除原 SSH
+profile。同一个 State Root 同时只能启用一个 profile。
+
+等价的 CLI 流程使用 setup 输出的精确 service target:
 
 ```sh
 maka runtime-host service peer enable \
diff --git a/packages/cli/src/__tests__/runtime-host-service-manager.test.ts b/packages/cli/src/__tests__/runtime-host-service-manager.test.ts
index b2f993667..c35b2d20f 100644
--- a/packages/cli/src/__tests__/runtime-host-service-manager.test.ts
+++ b/packages/cli/src/__tests__/runtime-host-service-manager.test.ts
@@ -160,6 +160,7 @@ describe('managed Runtime Host service', () => {
         'service',
         'peer',
         'enable',
+        '--framed',
         '--listen',
         '/ip4/0.0.0.0/udp/44001/quic-v1',
         '--clear-coordination-relays',
@@ -174,6 +175,7 @@ describe('managed Runtime Host service', () => {
         kind: 'runtime-host-service-peer',
         action: 'enable',
         json: false,
+        framed: true,
         listenAddresses: ['/ip4/0.0.0.0/udp/44001/quic-v1'],
         coordinationRelays: [],
         expectedTarget: {
diff --git a/packages/cli/src/cli-core.ts b/packages/cli/src/cli-core.ts
index eb3fb53dc..15e5bcab3 100644
--- a/packages/cli/src/cli-core.ts
+++ b/packages/cli/src/cli-core.ts
@@ -352,6 +352,7 @@ export async function runMakaCli(
       return runRuntimeHostPeerManagementCli({
         action: command.action,
         json: command.json,
+        framed: command.framed ?? false,
         clientDataRoot: serviceDataRoots.clientDataRoot,
         defaultRootPath: serviceDataRoots.workspaceRoot,
         nodePath: process.execPath,
diff --git a/packages/cli/src/runtime-host-cli.ts b/packages/cli/src/runtime-host-cli.ts
index 489bbba63..ae107038c 100644
--- a/packages/cli/src/runtime-host-cli.ts
+++ b/packages/cli/src/runtime-host-cli.ts
@@ -100,6 +100,7 @@ export type RuntimeHostCliCommand =
       kind: 'runtime-host-service-peer';
       action: 'enable' | 'disable' | 'status' | 'rotate' | 'descriptor';
       json: boolean;
+      framed?: true;
       clientDataRoot?: string;
       listenAddresses: string[];
       coordinationRelays?: string[];
@@ -480,6 +481,7 @@ function parseServicePeerCommand(argv: string[]): RuntimeHostCliCommand {
   let clearCoordinationRelays = false;
   const options = parseManagedServiceOptions(argv.slice(1), {
     allowConfiguration: false,
+    allowFramed: true,
     flagOptions: {
       '--clear-coordination-relays': () => {
         if (clearCoordinationRelays) return error('Duplicate --clear-coordination-relays');
@@ -528,6 +530,7 @@ function parseServicePeerCommand(argv: string[]): RuntimeHostCliCommand {
     kind: 'runtime-host-service-peer',
     action,
     json: options.json,
+    ...(options.framed ? { framed: true as const } : {}),
     ...(clientDataRoot ? { clientDataRoot } : {}),
     listenAddresses,
     ...(clearCoordinationRelays
diff --git a/packages/cli/src/runtime-host-peer-management-command.ts b/packages/cli/src/runtime-host-peer-management-command.ts
index 70e3ff943..892fee93b 100644
--- a/packages/cli/src/runtime-host-peer-management-command.ts
+++ b/packages/cli/src/runtime-host-peer-management-command.ts
@@ -18,6 +18,11 @@
  */
 
 import { networkInterfaces } from 'node:os';
+import {
+  encodeRuntimeHostPeerManagementFrame,
+  type RuntimeHostPeerManagementFrame,
+  type RuntimeHostPeerStatus,
+} from '@maka/runtime-host/operator';
 import {
   configureRuntimeHostManagedPeer,
   manageRuntimeHostService,
@@ -35,6 +40,7 @@ import { createPlatformRuntimeHostServiceBackend } from './runtime-host-service-
 export interface RuntimeHostPeerManagementCliOptions {
   readonly action: 'enable' | 'disable' | 'status' | 'rotate' | 'descriptor';
   readonly json: boolean;
+  readonly framed?: boolean;
   readonly clientDataRoot: string;
   readonly defaultRootPath: string;
   readonly nodePath: string;
@@ -44,16 +50,6 @@ export interface RuntimeHostPeerManagementCliOptions {
   readonly expectedTarget?: RuntimeHostManagedServiceTarget;
 }
 
-interface RuntimeHostPeerStatus {
-  readonly schemaVersion: 1;
-  readonly state: 'not_configured' | 'disabled' | 'enabled';
-  readonly serviceState: string;
-  readonly peerId?: string;
-  readonly rootId?: string;
-  readonly routeHints: readonly string[];
-  readonly coordinationRelays: readonly string[];
-}
-
 interface RuntimeHostPeerManagementCliDeps {
   readonly createBackend: typeof createPlatformRuntimeHostServiceBackend;
   readonly managerOverrides: RuntimeHostServiceManagerOverrides;
@@ -140,7 +136,17 @@ async function runRuntimeHostPeerManagementLocked(
         deps,
       );
     }
-    if (options.json) {
+    if (options.framed) {
+      writePeerFrame(
+        {
+          kind: 'rotated',
+          action: 'rotate',
+          previousPeerId: result.previousPeerId,
+          peerId: result.peerId,
+        },
+        deps,
+      );
+    } else if (options.json) {
       deps.writeStdout(
         `${JSON.stringify({
           schemaVersion: 1,
@@ -165,10 +171,14 @@ async function runRuntimeHostPeerManagementLocked(
       'Direct peer is not enabled for the managed Runtime Host service',
     );
   }
-  if (options.json) {
-    deps.writeStdout(`${JSON.stringify({ ...status, ok: true, action: options.action })}\n`);
+  if (options.framed) {
+    writePeerFrame({ kind: 'result', action: options.action, status }, deps);
+  } else if (options.json) {
+    deps.writeStdout(
+      `${JSON.stringify({ schemaVersion: 1, ...status, ok: true, action: options.action })}\n`,
+    );
   } else if (options.action === 'descriptor') {
-    deps.writeStdout(`${JSON.stringify(status)}\n`);
+    deps.writeStdout(`${JSON.stringify({ schemaVersion: 1, ...status })}\n`);
   } else {
     deps.writeStdout(formatPeerStatus(status));
   }
@@ -201,6 +211,10 @@ function writePeerFailure(
   message: string,
   deps: RuntimeHostPeerManagementCliDeps,
 ): void {
+  if (options.framed) {
+    writePeerFrame({ kind: 'error', action: options.action, error: { code, message } }, deps);
+    return;
+  }
   if (options.json) {
     deps.writeStdout(
       `${JSON.stringify({
@@ -215,6 +229,13 @@ function writePeerFailure(
   deps.writeStderr(`${message}\n`);
 }
 
+function writePeerFrame(
+  frame: RuntimeHostPeerManagementFrame,
+  deps: Pick<RuntimeHostPeerManagementCliDeps, 'writeStdout'>,
+): void {
+  deps.writeStdout(encodeRuntimeHostPeerManagementFrame(frame));
+}
+
 async function readPeerStatus(
   options: RuntimeHostPeerManagementCliOptions,
   backend: ReturnType<typeof createPlatformRuntimeHostServiceBackend>,
@@ -236,7 +257,6 @@ async function readPeerStatus(
   const peer = result.service.config?.peer;
   if (!peer) {
     return {
-      schemaVersion: 1,
       state: 'not_configured',
       serviceState: result.service.state,
       routeHints: [],
@@ -244,13 +264,12 @@ async function readPeerStatus(
     };
   }
   return {
-    schemaVersion: 1,
     state: peer.enabled ? 'enabled' : 'disabled',
     serviceState: result.service.state,
     peerId: peer.peerId,
     ...(options.expectedTarget ? { rootId: options.expectedTarget.rootId } : {}),
     routeHints: expandWildcardListenAddresses(peer.listenAddresses),
-    coordinationRelays: peer.coordinationRelays,
+    coordinationRelays: [...peer.coordinationRelays],
   };
 }
 
diff --git a/packages/runtime-host/src/__tests__/peer-management-frame.test.ts b/packages/runtime-host/src/__tests__/peer-management-frame.test.ts
new file mode 100644
index 000000000..86377e5e8
--- /dev/null
+++ b/packages/runtime-host/src/__tests__/peer-management-frame.test.ts
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import assert from 'node:assert/strict';
+import { test } from 'node:test';
+import {
+  decodeRuntimeHostPeerManagementFrame,
+  encodeRuntimeHostPeerManagementFrame,
+} from '../operator/index.js';
+
+test('peer management frames preserve a bounded machine-readable descriptor', () => {
+  const frame = {
+    kind: 'result' as const,
+    action: 'enable' as const,
+    status: {
+      state: 'enabled' as const,
+      serviceState: 'running',
+      peerId: '12D3KooWpeer',
+      rootId: 'a'.repeat(64),
+      routeHints: ['/ip4/192.0.2.1/udp/41000/quic-v1'],
+      coordinationRelays: [],
+    },
+  };
+  assert.deepEqual(
+    decodeRuntimeHostPeerManagementFrame(encodeRuntimeHostPeerManagementFrame(frame)),
+    frame,
+  );
+});
diff --git a/packages/runtime-host/src/operator/index.ts b/packages/runtime-host/src/operator/index.ts
index bf53d7a58..4052ac00c 100644
--- a/packages/runtime-host/src/operator/index.ts
+++ b/packages/runtime-host/src/operator/index.ts
@@ -28,6 +28,14 @@ export {
   type RuntimeHostAccessManagementFrame,
 } from './access-management-frame.js';
 export { runtimeHostAccessCredentialFingerprint } from '../access-credential-identity.js';
+export {
+  RUNTIME_HOST_PEER_MANAGEMENT_FRAME_PREFIX,
+  decodeRuntimeHostPeerManagementFrame,
+  encodeRuntimeHostPeerManagementFrame,
+  type RuntimeHostPeerManagementAction,
+  type RuntimeHostPeerManagementFrame,
+  type RuntimeHostPeerStatus,
+} from './peer-management-frame.js';
 export {
   RUNTIME_HOST_OPERATOR_ACCESS_MANAGEMENT_CAPABILITY,
   RUNTIME_HOST_OPERATOR_CAPABILITY_REQUEST_ENV,
diff --git a/packages/runtime-host/src/operator/peer-management-frame.ts b/packages/runtime-host/src/operator/peer-management-frame.ts
new file mode 100644
index 000000000..97da28b41
--- /dev/null
+++ b/packages/runtime-host/src/operator/peer-management-frame.ts
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { z } from 'zod';
+
+export const RUNTIME_HOST_PEER_MANAGEMENT_FRAME_PREFIX = 'MAKA_RUNTIME_HOST_PEER_MANAGEMENT_V1 ';
+const FRAME_MAX_BYTES = 128 * 1024;
+
+const ACTION_SCHEMA = z.enum(['enable', 'disable', 'status', 'rotate', 'descriptor']);
+const boundedString = (maxBytes: number) =>
+  z.string().refine((value) => Buffer.byteLength(value, 'utf8') <= maxBytes);
+const ADDRESS_SCHEMA = boundedString(2 * 1024);
+const STATUS_SCHEMA = z
+  .object({
+    state: z.enum(['not_configured', 'disabled', 'enabled']),
+    serviceState: boundedString(128),
+    peerId: boundedString(160).optional(),
+    rootId: z
+      .string()
+      .regex(/^[a-f0-9]{64}$/u)
+      .optional(),
+    routeHints: z.array(ADDRESS_SCHEMA).max(16),
+    coordinationRelays: z.array(ADDRESS_SCHEMA).max(16),
+  })
+  .strict();
+
+const FRAME_SCHEMA = z.discriminatedUnion('kind', [
+  z
+    .object({
+      kind: z.literal('result'),
+      action: ACTION_SCHEMA,
+      status: STATUS_SCHEMA,
+    })
+    .strict(),
+  z
+    .object({
+      kind: z.literal('rotated'),
+      action: z.literal('rotate'),
+      previousPeerId: boundedString(160),
+      peerId: boundedString(160),
+    })
+    .strict(),
+  z
+    .object({
+      kind: z.literal('error'),
+      action: ACTION_SCHEMA,
+      error: z
+        .object({
+          code: boundedString(128),
+          message: boundedString(2 * 1024),
+        })
+        .strict(),
+    })
+    .strict(),
+]);
+
+export type RuntimeHostPeerManagementAction = z.infer<typeof ACTION_SCHEMA>;
+export type RuntimeHostPeerStatus = z.infer<typeof STATUS_SCHEMA>;
+export type RuntimeHostPeerManagementFrame = z.infer<typeof FRAME_SCHEMA>;
+
+export function encodeRuntimeHostPeerManagementFrame(
+  frame: RuntimeHostPeerManagementFrame,
+): string {
+  const encoded = Buffer.from(JSON.stringify(FRAME_SCHEMA.parse(frame)), 'utf8').toString(
+    'base64url',
+  );
+  if (Buffer.byteLength(encoded, 'utf8') > FRAME_MAX_BYTES) {
+    throw new RangeError('Runtime Host peer management frame exceeds the encoded size limit');
+  }
+  return `${RUNTIME_HOST_PEER_MANAGEMENT_FRAME_PREFIX}${encoded}\n`;
+}
+
+export function decodeRuntimeHostPeerManagementFrame(
+  line: string,
+): RuntimeHostPeerManagementFrame | undefined {
+  const marker = line.indexOf(RUNTIME_HOST_PEER_MANAGEMENT_FRAME_PREFIX);
+  if (marker < 0) return undefined;
+  try {
+    const encoded = line.slice(marker + RUNTIME_HOST_PEER_MANAGEMENT_FRAME_PREFIX.length).trim();
+    if (encoded.length === 0 || Buffer.byteLength(encoded, 'utf8') > FRAME_MAX_BYTES) {
+      return undefined;
+    }
+    const value: unknown = JSON.parse(Buffer.from(encoded, 'base64url').toString('utf8'));
+    const decoded = FRAME_SCHEMA.safeParse(value);
+    return decoded.success ? decoded.data : undefined;
+  } catch {
+    return undefined;
+  }
+}
diff --git a/scripts/ci-test-plan.test.mjs b/scripts/ci-test-plan.test.mjs
index 2665ca3ab..5bc8dd511 100644
--- a/scripts/ci-test-plan.test.mjs
+++ b/scripts/ci-test-plan.test.mjs
@@ -341,6 +341,7 @@ test('pull request triggers stay on an explicit allowlist', () => {
 
   assert.deepEqual(onPullRequests, [
     'ci.yml',
+    'cli-package-validation.yml',
     'copilot-auto-review.yml',
     'dependency-audit.yml',
     'gitoxide-helper-admission.yml',
diff --git a/scripts/package-macos-arm64.mjs b/scripts/package-macos-arm64.mjs
index 34779367b..078ba0c0b 100644
--- a/scripts/package-macos-arm64.mjs
+++ b/scripts/package-macos-arm64.mjs
@@ -91,6 +91,8 @@ export async function packageMacosArm64({
 
   await run('npm', ['run', 'clean']);
   await run('npm', ['run', 'build']);
+  await run('npm', ['run', 'build:runtime-host-peer']);
+  await run('npm', ['run', 'check:runtime-host-peer-notices']);
   await run('npm', ['run', 'check:release']);
   await remove(releaseDirectory, { recursive: true, force: true });
   await run('npm', ['--workspace', '@maka/desktop', 'run', 'package:macos-arm64']);
diff --git a/scripts/package-windows-x64.mjs b/scripts/package-windows-x64.mjs
index 46cb20441..515d95b87 100644
--- a/scripts/package-windows-x64.mjs
+++ b/scripts/package-windows-x64.mjs
@@ -103,6 +103,8 @@ export async function packageWindowsX64({
 
   await run('npm', ['run', 'clean']);
   await run('npm', ['run', 'build']);
+  await run('npm', ['run', 'build:runtime-host-peer']);
+  await run('npm', ['run', 'check:runtime-host-peer-notices']);
   await run('cargo', ['build', '--manifest-path', sandboxManifestPath, '--release', '--locked']);
   await run('npm', ['run', 'check:windows-cargo-notices']);
   await mkdir(sandboxResourceDirectory, { recursive: true });
diff --git a/scripts/verify-packaged-app.mjs b/scripts/verify-packaged-app.mjs
index 43c51b85c..bdb84e538 100644
--- a/scripts/verify-packaged-app.mjs
+++ b/scripts/verify-packaged-app.mjs
@@ -1022,6 +1022,9 @@ export async function assertPackagedResources(
     // artifacts that were correct when they shipped. The canonical icon itself
     // is `requireCanonicalIcon` above, not this.
     requireAppIconCatalog = true,
+    // Current Desktop builds ship the direct-peer Client addon beside its Rust
+    // notices. Upgrade baselines may predate both resources.
+    requireDirectPeerArtifact = true,
   } = {},
 ) {
   if (bundledGitContract !== 'forbidden' && bundledGitContract !== 'legacy-required') {
@@ -1042,6 +1045,12 @@ export async function assertPackagedResources(
       : []),
     ...(requireCanonicalIcon ? [join('assets', 'icon.png')] : []),
     join('workers', 'filesystem-worker.js'),
+    ...(requireDirectPeerArtifact
+      ? [
+          join('runtime-host-peer', 'maka_runtime_host_peer.node'),
+          join('licenses', 'runtime-host-peer', 'THIRD_PARTY_NOTICES.txt'),
+        ]
+      : []),
     // The picker's catalog is read at runtime, and Electron reports a missing
     // file as an empty image rather than an error — a packaging change that
     // dropped one would ship a blank tile silently.
diff --git a/scripts/verify-packaged-app.test.mjs b/scripts/verify-packaged-app.test.mjs
index 1f7596d19..6db7792b7 100644
--- a/scripts/verify-packaged-app.test.mjs
+++ b/scripts/verify-packaged-app.test.mjs
@@ -58,6 +58,7 @@ test('legacy packaged resources require the historical bundled Git contract', as
     requireWindowsSandbox: false,
     bundledGitContract: 'legacy-required',
     requireCanonicalIcon: false,
+    requireDirectPeerArtifact: false,
   });
 
   for (const path of [
diff --git a/scripts/verify-windows-x64.mjs b/scripts/verify-windows-x64.mjs
index 2aea9189b..219a7c707 100644
--- a/scripts/verify-windows-x64.mjs
+++ b/scripts/verify-windows-x64.mjs
@@ -146,6 +146,7 @@ export async function verifyPackagedWindowsApp(
     bundledGitContract: requiresCurrentContract ? 'forbidden' : 'legacy-required',
     requireCanonicalIcon: requiresCurrentContract,
     requireAppIconCatalog: requiresCurrentContract,
+    requireDirectPeerArtifact: requiresCurrentContract,
   });
   if (requiresCurrentContract) await assertPackagedDependencyClosure(resources);
   else await requirePath(join(resources, 'git', 'cmd', 'git.exe'));


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org