blob: af4d239e0d3a6ce9cb2137326fa7b72f5f68297f [file] [view]
# zxdb_cli
## Problem Understanding
Traditional debugging tools like `zxdb` are designed for interactive, human
workflows. Developers can manage continuous streams of logs and maintain
debugger state across a long session.
However, automated agents and AI assistants operate differently. They work in
discrete turns, struggle with commands that run indefinitely, and can be
overwhelmed by the verbose output of the Debug Adapter Protocol (DAP).
To enable these tools to effectively use `zxdb`, we need a bridge between the
chatty, connection-oriented DAP and a simpler request-response model that fits
their turn-based workflow.
`fx debug cli` solves this by using a background daemon to manage the persistent
debugger connection. The CLI then exposes a clean, summarized interface to run
commands and get immediate feedback without getting stuck in interactive loops
or protocol noise.
## Usage and Behavior
### Fallback to Interactive Session
If the entry-point script is run without the `cli` subcommand (or with arguments
that don't match it), it behaves as a thin wrapper around `ffx debug connect`.
It will pass all arguments directly to the standard interactive `zxdb` session,
maintaining the experience for human developers.
### Automated Package Server
Both the interactive fallback and the background daemon automatically ensure
that the Fuchsia package server is running. This removes the need for developers
(or agents) to manually check and start the package server before beginning a
debugging session.
### Basic Workflow Examples
The CLI allows running a full debugging session using a request-response model.
Below is a standard workflow: starting the daemon, attaching to a process, and
stopping the daemon.
#### Standard CLI Usage
1. **Start the daemon**:
```bash
fx debug cli start
```
Output:
```
Spawning daemon...
Daemon is ready.
```
2. **Attach to a process** (e.g., attaching to `cobalt.cm`):
```bash
fx debug cli attach cobalt.cm
```
Output:
```
{"success": true, "message": "", "body": {"success": true}}
```
3. **Query threads**:
```bash
fx debug cli threads
```
Output:
```
{"success": true, "body": {"threads": [{"id": 1, "name": "main"}, {"id": 2, "name": "worker"}]}}
```
4. **Pause a thread**:
```bash
fx debug cli pause 1
```
Output:
```
{"success": true, "body": {"success": true}}
```
5. **Resume a thread**:
```bash
fx debug cli continue 1
```
Output:
```
{"success": true, "body": {"success": true}}
```
6. **Get stack trace**:
```bash
fx debug cli stackTrace 1
```
Output:
```
{"success": true, "body": {"stackFrames": [{"id": 0, "name": "main", "line": 42}]}}
```
7. **Stop the daemon**:
```bash
fx debug cli stop
```
Output:
```
{"success": true, "message": "Daemon stopping", "body": null}
```
#### JSON CLI Usage (With JSON)
For programmatic environments or agents, the same operations can be invoked via JSON payloads using the `--json` flag.
1. **Start the daemon**:
```bash
fx debug cli --json '{"command": "start"}'
```
Output:
```
Spawning daemon...
Daemon is ready.
```
2. **Attach to a process**:
```bash
fx debug cli --json '{"command": "attach", "filter": "cobalt.cm"}'
```
Output:
```
{"success": true, "message": "", "body": {"success": true}}
```
3. **Query threads**:
```bash
fx debug cli --json '{"command": "threads"}'
```
Output:
```
{"success": true, "body": {"threads": [{"id": 1, "name": "main"}, {"id": 2, "name": "worker"}]}}
```
4. **Pause a thread**:
```bash
fx debug cli --json '{"command": "pause", "thread_id": 1}'
```
Output:
```
{"success": true, "body": {"success": true}}
```
5. **Resume a thread**:
```bash
fx debug cli --json '{"command": "continue", "thread_id": 1}'
```
Output:
```
{"success": true, "body": {"success": true}}
```
6. **Get stack trace**:
```bash
fx debug cli --json '{"command": "stackTrace", "thread_id": 1}'
```
Output:
```
{"success": true, "body": {"stackFrames": [{"id": 0, "name": "main", "line": 42}]}}
```
7. **Stop the daemon**:
```bash
fx debug cli --json '{"command": "stop"}'
```
Output:
```
{"success": true, "message": "Daemon stopping", "body": null}
```
## Technical Architecture
The system is built around two primary components: a long-lived background
**Daemon** and a short-lived **CLI** wrapper (`fx debug cli`).
* **The Daemon**: This process maintains the continuous connection to the
debugger. It starts the package server and `zxdb`, connects to the DAP
server, and listens on a Unix Domain Socket (UDS) for requests. It queues
critical events and maintains the aggregate state of the session.
* **The CLI (`fx debug cli`)**: This is a stateless tool designed for
automated agents. It connects to the daemon via UDS, sends a command,
receives the response, and exits.
### How They Fit Together
```mermaid
graph TD
subgraph Host Machine
AI["Automated Agent"] -->|Invokes| CLI["fx debug cli"]
CLI -->|"UDS (JSON Protocol)"| Daemon["Daemon Binary"]
Daemon -->|"DAP (TCP Port 15678)"| Zxdb["zxdb"]
Daemon -->|Manages| PkgServer["Package Server"]
end
subgraph Fuchsia Target
Zxdb -->|"Debug IPC"| DebugAgent["Debug Agent"]
DebugAgent -->|"syscalls"| TargetApp["Target Application"]
end
```
### Communication Protocol
The protocol between the CLI and the Daemon uses a simplified, non-strict
version of the Debug Adapter Protocol (DAP), transmitted as newline-delimited
JSON over the Unix Domain Socket.
#### Smart Proxy and Schemas
To maximize efficiency for automated agents, the daemon acts as a smart proxy.
It strips away verbose protocol metadata and boils messages down to their
essential fields. This ensures that response payloads are compact and
token-efficient.
Example `get-state` Response:
```json
{
"processes": [
{
"id": "p1",
"name": "target_app",
"threads": [
{
"id": 1,
"name": "main"
}
]
}
]
}
```
## Ecosystem Fit
This tool layers on top of Fuchsia's existing debug infrastructure. It does not
replace `zxdb`; instead, it leverages `zxdb`'s DAP support (found in
`src/lib/debug/dap/python`) to provide a machine-friendly interface. By bridging
the gap between interactive streams and request-response patterns, it enables
automated tools to use our standard debugging stack effectively.