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

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, 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 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:

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

Run a command over SSH using key-based authentication:

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:

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.
  • 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 (entry point), CLIConnectionFactory.java (auth handling), PlainCLIProtocol.java (framing), and 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 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →