# Jenkins CLI Command Execution Architecture: How the Client Communicates with Jenkins Masters

> Explore the Jenkins CLI command execution architecture. Understand how the client connects to Jenkins masters via HTTP, WebSocket, or SSH using a shared binary protocol.

- Repository: [Jenkins/jenkins](https://github.com/jenkinsci/jenkins)
- Tags: architecture
- Published: 2026-06-19

---

**The Jenkins CLI is a thin client that communicates with the Jenkins server over HTTP, WebSocket, or SSH using a shared binary protocol defined in `PlainCLIProtocol`.** This architecture separates command-line parsing, transport selection, and protocol handling into distinct layers, allowing the same command implementations to run regardless of the underlying connection method.

The Jenkins CLI client (`jenkins-cli.jar`) acts as a bridge between your local terminal and the Jenkins controller. According to the jenkinsci/jenkins source code, the architecture cleanly decouples **transport selection** from **command execution**, enabling flexible authentication and connectivity options while maintaining a consistent interface for server-side commands.

## Three-Layer Architecture

The CLI implementation in `hudson.cli` follows a layered design that separates concerns between user interaction, connection management, and data transmission.

### Entry Point and Argument Parsing

The `hudson.cli.CLI` class serves as the primary entry point. The `main()` method parses command-line arguments, determines the transport mode (`Mode.HTTP`, `Mode.SSH`, or `Mode.WEB_SOCKET`), and constructs the target URL. It also gathers authentication credentials from environment variables, the `-auth` flag, or the `-bearer` token option.

In [`CLI.java`](https://github.com/jenkinsci/jenkins/blob/main/CLI.java), the parsing logic evaluates the `-ssh`, `-http`, or default flags to select the appropriate transport factory before initiating the connection.

### Connection Factory

The `hudson.cli.CLIConnectionFactory` creates a fluent API object that holds authentication headers and TLS configuration. This factory attaches the `Authorization` header (Basic or Bearer) to HTTP and WebSocket requests. It also manages the `-noCertificateCheck` flag for bypassing SSL verification during transport initialization.

### Protocol Abstraction Layer

All transports utilize the same binary framing protocol defined in `hudson.cli.PlainCLIProtocol`. This protocol abstracts stdin, stdout, stderr, and command arguments into discrete frames, ensuring consistent behavior across HTTP, WebSocket, and SSH connections.

## Transport Mode Implementations

The CLI client supports three distinct transport mechanisms, each implemented in [`CLI.java`](https://github.com/jenkinsci/jenkins/blob/main/CLI.java) with mode-specific connection factories.

### HTTP Mode

When using **HTTP mode**, the `plainHttpConnection()` method creates a `FullDuplexHttpStream` that wraps a standard `HttpURLConnection`. This implementation establishes a plain socket connection to the Jenkins server and tunnels the binary protocol over HTTP.

The HTTP transport is the fallback option when neither SSH nor WebSocket flags are specified.

### WebSocket Mode

**WebSocket mode** uses the Tyrus client (`ClientManager`) to establish a persistent connection at `<url>/cli/ws`. The `webSocketConnection()` method attaches the `Authorization` header via a custom `Authenticator` and pipes `PlainCLIProtocol` frames through the WebSocket session.

This mode provides full-duplex communication over a single TCP connection, making it efficient for interactive commands.

### SSH Mode

For **SSH mode**, the `hudson.cli.SSHCLI` class handles connection establishment. The `sshConnection()` method opens an SSH channel to the server, authenticates using a private key via `PrivateKeyProvider`, and runs the binary protocol over the SSH channel.

SSH mode requires the `-ssh` flag and a URL with the `ssh://` scheme, offering encrypted communication without requiring HTTP port access.

## The PlainCLIProtocol Binary Protocol

The `hudson.cli.PlainCLIProtocol` class defines the wire format used by all transport modes. This protocol uses framed messages to communicate between the `ClientSide` (local CLI) and `ServerSide` (Jenkins controller).

### Client-to-Server Frames

The client sends the following frame types to initiate and feed the remote command:

- **`ARG`** – Command arguments as UTF-8 strings
- **`LOCALE`** – Client locale settings
- **`ENCODING`** – Character encoding specifications
- **`START`** – Signals the server to begin execution
- **`STDIN`** – Standard input data chunks
- **`END_STDIN`** – Signals EOF for stdin

### Server-to-Client Frames

The server responds with output and status frames:

- **`STDOUT`** – Standard output data
- **`STDERR`** – Standard error data
- **`EXIT`** – Process exit code indicating command completion

This framing abstraction allows the server to resolve the requested command class (such as `hudson.cli.BuildCommand`) and invoke its `run()` method while streaming I/O through the selected transport.

## Server-Side Command Resolution

When the server receives the `START` frame, the Jenkins core (`hudson.remoting.*` and the CLI command registry) resolves the command name to a concrete implementation class. Commands such as `BuildCommand` or `GetJobCommand` extend the base CLI infrastructure and execute within the Jenkins security context, receiving streamed stdin and returning output via the protocol frames.

## Practical Usage Examples

Execute a build over HTTP with basic authentication:

```bash
java -jar jenkins-cli.jar -s http://localhost:8080/ -auth user:token build my-job

```

Run a command over SSH using key-based authentication:

```bash
java -jar jenkins-cli.jar -ssh -s ssh://jenkins.example.com/ -i ~/.ssh/id_rsa \
    -user jenkins_user build my-job

```

Execute via WebSocket with token file authentication:

```bash
java -jar jenkins-cli.jar -s http://localhost:8080/ \
    -auth @/path/to/token.txt get-job my-job

```

Each invocation enters through `CLI.main()`, selects the transport mode, constructs a `CLIConnectionFactory` with the appropriate authentication header, and delegates to either `plainHttpConnection()`, `webSocketConnection()`, or `SSHCLI.sshConnection()`.

## Summary

- **The Jenkins CLI architecture** separates command parsing, transport selection, and protocol handling into distinct layers within `hudson.cli`.
- **Three transport modes** (HTTP, WebSocket, SSH) share the same `PlainCLIProtocol` binary framing, defined in [`PlainCLIProtocol.java`](https://github.com/jenkinsci/jenkins/blob/main/PlainCLIProtocol.java).
- **Authentication** is handled uniformly through `CLIConnectionFactory`, which attaches `Authorization` headers to HTTP and WebSocket requests.
- **Server-side execution** occurs when the `START` frame arrives, triggering the resolved command class in the Jenkins core.
- **Key source files** include [`CLI.java`](https://github.com/jenkinsci/jenkins/blob/main/CLI.java) (entry point), [`CLIConnectionFactory.java`](https://github.com/jenkinsci/jenkins/blob/main/CLIConnectionFactory.java) (auth handling), [`PlainCLIProtocol.java`](https://github.com/jenkinsci/jenkins/blob/main/PlainCLIProtocol.java) (framing), and [`SSHCLI.java`](https://github.com/jenkinsci/jenkins/blob/main/SSHCLI.java) (SSH transport).

## Frequently Asked Questions

### How does the Jenkins CLI handle authentication across different transport modes?

The `CLIConnectionFactory` class centralizes authentication by building the `Authorization` header from `-auth` or `-bearer` arguments. This factory attaches the header to HTTP and WebSocket requests through the `Authenticator` mechanism, while SSH mode uses `PrivateKeyProvider` for key-based authentication directly within the SSH channel establishment.

### What is the difference between HTTP and WebSocket transport in the Jenkins CLI?

HTTP mode uses `FullDuplexHttpStream` to wrap traditional `HttpURLConnection` objects, while WebSocket mode uses the Tyrus `ClientManager` to establish a persistent WS connection at `/cli/ws`. Both transport the same `PlainCLIProtocol` frames, but WebSocket provides full-duplex communication over a single connection, whereas HTTP may use chunked transfer encoding for bidirectional streaming.

### Can the Jenkins CLI work without the SSH port open?

Yes, the CLI functions over HTTP (port 8080 by default) or WebSocket without requiring SSH access. HTTP mode uses `plainHttpConnection()` and WebSocket mode uses `webSocketConnection()`, both of which communicate over standard HTTP ports. SSH mode is optional and only required when explicitly specified with the `-ssh` flag.

### Which source file contains the main entry point for the Jenkins CLI?

The `hudson.cli.CLI` class in [`cli/src/main/java/hudson/cli/CLI.java`](https://github.com/jenkinsci/jenkins/blob/main/cli/src/main/java/hudson/cli/CLI.java) contains the `main()` method that serves as the entry point. This method handles argument parsing, transport mode selection, and delegates to the appropriate connection factory before initiating the `PlainCLIProtocol` handshake.