diff --git a/scripts/debug/BUILD.gn b/scripts/debug/BUILD.gn
new file mode 100644
index 0000000..4664194
--- /dev/null
+++ b/scripts/debug/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright 2025 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/python/host.gni")
+import("//build/python/python_binary.gni")
+
+if (is_host) {
+ python_binary("debug") {
+ main_source = "main.py"
+
+ deps = [ "//scripts/lib/package_server" ]
+ }
+
+ install_python_tool("install") {
+ name = "debug"
+ binary = ":debug"
+ }
+}
diff --git a/scripts/debug/OWNERS b/scripts/debug/OWNERS
new file mode 100644
index 0000000..8bac3da
--- /dev/null
+++ b/scripts/debug/OWNERS
@@ -0,0 +1,2 @@
+include /src/developer/debug/OWNERS
+chand...@google.com
diff --git a/scripts/debug/main.py b/scripts/debug/main.py
new file mode 100644
index 0000000..1e548ef
--- /dev/null
+++ b/scripts/debug/main.py
@@ -0,0 +1,41 @@
+# Copyright 2025 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import asyncio
+import sys
+
+import package_server
+
+
+async def main(args: list[str] = sys.argv[1:]) -> int:
+ async with package_server.ensure_running():
+ # TODO(https://fxbug.dev/464692993): Refactor `//scripts/fxtest/python/debugger.py` into a
+ # shared library and use it here.
+ ffx_cmd = await asyncio.subprocess.create_subprocess_exec(
+ "ffx", "debug", "connect", *args, stdin=sys.stdin
+ )
+
+ try:
+ return await ffx_cmd.wait()
+ except asyncio.CancelledError:
+ # This block triggers if the python script receives SIGINT (Ctrl+C)
+ # or SIGTERM, and zxdb hasn't already exited.
+
+ # Gracefully shutdown zxdb.
+ ffx_cmd.terminate()
+
+ # Give zxdb a few seconds to clean up internal state
+ await asyncio.wait_for(ffx_cmd.wait(), timeout=3.0)
+
+ # Forcefully kill zxdb if it hasn't stopped yet.
+ if ffx_cmd.returncode is None:
+ ffx_cmd.kill()
+ await ffx_cmd.wait()
+ return -9
+
+ return ffx_cmd.returncode
+
+
+if __name__ == "__main__":
+ sys.exit(asyncio.run(main()))
diff --git a/scripts/lib/package_server/OWNERS b/scripts/lib/package_server/OWNERS
index dca95eb..eba1f98 100644
--- a/scripts/lib/package_server/OWNERS
+++ b/scripts/lib/package_server/OWNERS
@@ -1,2 +1,3 @@
+include /scripts/debug/OWNERS
include /src/sys/pkg/OWNERS
chand...@google.com
diff --git a/tools/devshell/BUILD.gn b/tools/devshell/BUILD.gn
index 29fc90f..c604192 100644
--- a/tools/devshell/BUILD.gn
+++ b/tools/devshell/BUILD.gn
@@ -55,6 +55,9 @@
# For `fx disable_ctf_tests`
"//scripts/disable_ctf_tests:install",
+
+ # For `fx debug`.
+ "//scripts/debug:install",
]
}
}
diff --git a/tools/devshell/debug b/tools/devshell/debug
new file mode 100644
index 0000000..60c4404
--- /dev/null
+++ b/tools/devshell/debug
@@ -0,0 +1,12 @@
+#!/bin/bash
+# Copyright 2025 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+#### CATEGORY=Run, inspect and debug
+### Starts target-side zxdb debug sessions
+
+source "$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"/lib/vars.sh || exit $?
+fx-config-read
+
+fx-command-run host-tool debug "$@"