Skip to content

Commit 1f00924

Browse files
committed
vmctl remote: accessibility tree, pointer and keyboard control, and overlays
Implement vmctl remote command for programmatic guest control. Add accessibility tree inspection, pointer control (click, drag, scroll), keyboard input, and visual element overlays. Add host-side screenshot via ScreenCaptureKit, Unix socket API for external tool integration, and batch action orchestration.
1 parent af9e350 commit 1f00924

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+5912
-1219
lines changed

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,8 @@ dmg: tools ghosttools-icon
176176
@cp "$(GHOSTTOOLS_ICON_ICNS)" "$(GHOSTTOOLS_BUILD_DIR)/dmg-stage/GhostTools.app/Contents/Resources/"
177177
@# Copy README to DMG root
178178
@cp "$(GHOSTTOOLS_DIR)/README.txt" "$(GHOSTTOOLS_BUILD_DIR)/dmg-stage/"
179-
@# Ad-hoc sign the app
180-
codesign --force --deep -s "-" "$(GHOSTTOOLS_BUILD_DIR)/dmg-stage/GhostTools.app"
179+
@# Sign with developer identity (preserves TCC permissions across rebuilds)
180+
codesign --force --deep -s "Apple Development" "$(GHOSTTOOLS_BUILD_DIR)/dmg-stage/GhostTools.app"
181181
@# Create the DMG
182182
@rm -f "$(GHOSTTOOLS_DMG)"
183183
hdiutil makehybrid -o "$(GHOSTTOOLS_DMG)" \

Website/image-loader.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export default function ghostVMLoader({
2+
src,
3+
}: {
4+
src: string;
5+
width: number;
6+
quality?: number;
7+
}) {
8+
// In static export with basePath, unoptimized images don't get the prefix.
9+
// This loader ensures all images are served from the correct subdirectory.
10+
const basePath = "/GhostVM";
11+
if (src.startsWith("/") && !src.startsWith(basePath)) {
12+
return `${basePath}${src}`;
13+
}
14+
return src;
15+
}

Website/next.config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ const nextConfig: NextConfig = {
44
output: "export",
55
basePath: "/GhostVM",
66
images: {
7-
unoptimized: true,
7+
loader: "custom",
8+
loaderFile: "./image-loader.ts",
89
},
910
};
1011

Website/src/app/docs/architecture/page.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,25 @@ export default function Architecture() {
6464
discovery, and health monitoring.
6565
</p>
6666

67+
<h3>Host API Service</h3>
68+
<p>
69+
Each running VM&apos;s Helper process exposes a Unix domain socket at{" "}
70+
<code>~/Library/Application Support/GhostVM/api/</code>. The socket
71+
accepts newline-delimited JSON requests and provides access to both
72+
host-only operations (status, stop, suspend) and guest proxy operations
73+
(clipboard, files, logs). See the{" "}
74+
<a href="/docs/host-api">Host API</a> docs for details.
75+
</p>
76+
77+
<h3>MCP Server</h3>
78+
<p>
79+
The <code>vmctl mcp</code> command starts a{" "}
80+
<a href="https://modelcontextprotocol.io">Model Context Protocol</a>{" "}
81+
server that bridges JSON-RPC on stdin/stdout to the Host API socket.
82+
This allows AI assistants like Claude Desktop to control VMs
83+
programmatically. See the <a href="/docs/mcp">MCP Server</a> docs.
84+
</p>
85+
6786
<h2>Services Architecture</h2>
6887
<p>
6988
All host-guest services are located in <code>GhostVM/Services/</code>{" "}

Website/src/app/docs/cli/page.tsx

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,20 @@ Options:
3737

3838
<h2>Common Commands</h2>
3939

40+
<h3>clone</h3>
41+
<p>
42+
Duplicate a VM using APFS copy-on-write. The clone gets a fresh machine
43+
identity and MAC address. Near-zero disk overhead.
44+
</p>
45+
<CodeBlock language="bash">{`vmctl clone <source-bundle> <new-name>`}</CodeBlock>
46+
4047
<h3>start</h3>
4148
<p>Launch a VM.</p>
4249
<CodeBlock language="bash">
4350
{`vmctl start <bundle-path> [options]
4451
4552
Options:
46-
--headless Run without GUI window
47-
--shared-folder PATH Host folder to share
48-
--writable Writable shared folder
49-
--read-only Read-only shared folder (default)`}
53+
--recovery Boot to Recovery mode`}
5054
</CodeBlock>
5155

5256
<h3>stop</h3>
@@ -59,15 +63,7 @@ Options:
5963

6064
<h3>resume</h3>
6165
<p>Resume from suspended state.</p>
62-
<CodeBlock language="bash">
63-
{`vmctl resume <bundle-path> [options]
64-
65-
Options:
66-
--headless Run without GUI window
67-
--shared-folder PATH Host folder to share
68-
--writable Writable shared folder
69-
--read-only Read-only shared folder (default)`}
70-
</CodeBlock>
66+
<CodeBlock language="bash">{`vmctl resume <bundle-path>`}</CodeBlock>
7167

7268
<h3>discard-suspend</h3>
7369
<p>Discard the suspended state so the VM boots fresh.</p>
@@ -82,6 +78,14 @@ vmctl snapshot <bundle-path> revert <name>
8278
vmctl snapshot <bundle-path> delete <name>`}
8379
</CodeBlock>
8480

81+
<h3>mcp</h3>
82+
<p>
83+
Start an MCP server for the given VM. Reads JSON-RPC from stdin,
84+
writes responses to stdout. See the{" "}
85+
<a href="/docs/mcp">MCP Server</a> docs for full details.
86+
</p>
87+
<CodeBlock language="bash">{`vmctl mcp <bundle-path>`}</CodeBlock>
88+
8589
<h2>Examples</h2>
8690
<CodeBlock language="bash" title="Full macOS workflow">
8791
{`# Create and install a macOS VM
@@ -95,6 +99,15 @@ vmctl snapshot ~/VMs/dev.GhostVM create clean-state
9599
# Later: revert to clean state
96100
vmctl snapshot ~/VMs/dev.GhostVM revert clean-state`}
97101
</CodeBlock>
102+
103+
<CodeBlock language="bash" title="Clone and automate">
104+
{`# Clone an existing workspace
105+
vmctl clone ~/VMs/dev.GhostVM staging
106+
vmctl start ~/VMs/staging.GhostVM
107+
108+
# Start an MCP server for AI agent control
109+
vmctl mcp ~/VMs/staging.GhostVM`}
110+
</CodeBlock>
98111
<PrevNextNav currentHref="/docs/cli" />
99112
</>
100113
);

Website/src/app/docs/getting-started/page.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ vmctl start ~/VMs/sandbox.GhostVM`}
9191
Set up <Link href="/docs/services">host-guest services</Link> like clipboard
9292
sync and file transfer
9393
</li>
94+
<li>
95+
Let AI agents control VMs with the{" "}
96+
<Link href="/docs/mcp">MCP Server</Link>
97+
</li>
9498
</ul>
9599

96100
<PrevNextNav currentHref="/docs/getting-started" />

Website/src/app/docs/gui-app/page.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ export default function GUIApp() {
5353
</li>
5454
<li>
5555
<strong>Icon Chooser</strong> &mdash; switch the workspace Dock icon
56-
between Generic, App, Stack, and Custom modes, saved instantly
56+
between Generic, Glass, App, and Stack modes. Glass mode renders any
57+
app icon with a frosted overlay. Drag and drop icons into the icon
58+
slots for quick customization
5759
</li>
5860
<li>
5961
<strong>Capture Inputs</strong> &mdash; toggle to send all keyboard
@@ -75,6 +77,8 @@ export default function GUIApp() {
7577
<ul>
7678
<li>Start / Boot to Recovery</li>
7779
<li>Stop / Terminate</li>
80+
<li>Clone &mdash; duplicate the workspace with APFS copy-on-write</li>
81+
<li>Rename &mdash; change the workspace name and bundle filename</li>
7882
<li>Edit Settings (CPU, memory, disk, shared folders, port forwards)</li>
7983
<li>Snapshot management (create, revert, delete)</li>
8084
<li>Show in Finder / Remove from List / Delete</li>

Website/src/app/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import "./globals.css";
77
export const metadata: Metadata = {
88
title: "GhostVM - Agentic Workspaces on macOS",
99
description:
10-
"GhostVM is a native macOS app for running multiple isolated agentic workspaces on macOS. Deep host integration, scriptable CLI, and self-contained VM bundles.",
10+
"GhostVM is a native macOS app for running isolated agentic workspaces on macOS. AI agents control VMs via the built-in MCP server. Deep host integration, scriptable CLI, instant clones, and self-contained bundles.",
1111
};
1212

1313
export default function RootLayout({

Website/src/app/page.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import Hero from "@/components/landing/Hero";
2+
import MCPSection from "@/components/landing/MCPSection";
23
import ScreenshotShowcase from "@/components/landing/ScreenshotShowcase";
34
import AutomationSection from "@/components/landing/AutomationSection";
45
import IntegrationSection from "@/components/landing/IntegrationSection";
@@ -13,10 +14,11 @@ export default function Home() {
1314
<Hero />
1415
<IntegrationSection />
1516
<ScreenshotShowcase />
16-
<AutomationSection />
1717
<FeatureGrid />
1818
<SecuritySection />
1919
<VMIconShowcase />
20+
<AutomationSection />
21+
<MCPSection />
2022
<DownloadCTA />
2123
</>
2224
);

Website/src/components/landing/AutomationSection.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ const terminalLines = [
1313
{ prompt: false, text: "" },
1414
{ prompt: true, text: "vmctl snapshot ~/VMs/dev.GhostVM create clean-state" },
1515
{ prompt: false, text: 'Snapshot "clean-state" created.' },
16+
{ prompt: false, text: "" },
17+
{ prompt: true, text: "vmctl clone ~/VMs/dev.GhostVM staging" },
18+
{ prompt: false, text: "Cloned to ~/VMs/staging.GhostVM (APFS copy-on-write)" },
19+
{ prompt: false, text: "" },
20+
{ prompt: true, text: "vmctl mcp ~/VMs/staging.GhostVM" },
21+
{ prompt: false, text: "MCP server ready (stdin/stdout)" },
1622
];
1723

1824
const bullets = [
@@ -36,6 +42,14 @@ const bullets = [
3642
title: "CI/CD ready",
3743
description: "Provision isolated workspaces in build pipelines and testing workflows.",
3844
},
45+
{
46+
title: "Instant Clone",
47+
description: "Duplicate a workspace instantly with APFS copy-on-write. Fresh identity, minimal disk usage.",
48+
},
49+
{
50+
title: "MCP Server",
51+
description: "Expose tools to AI agents via JSON-RPC. Clipboard, files, and lifecycle — all programmatic.",
52+
},
3953
];
4054

4155
function TerminalBlock() {

0 commit comments

Comments
 (0)