# How External Tools Communicate with the Omarchy Shell via IPC

> Learn how external tools communicate with the Omarchy Shell via IPC using Unix domain sockets and JSON-RPC. Integrate seamlessly with the omarchy-shell CLI or direct connections.

- Repository: [Omacom/omarchy](https://github.com/omacom/omarchy)
- Tags: internals
- Published: 2026-09-05

---

**External tools communicate with the Omarchy Shell via a Unix domain socket at `$XDG_RUNTIME_DIR/omarchy-shell` using JSON-RPC messages, either through the `omarchy-shell` CLI wrapper or direct socket connections.**

The Omarchy Shell is a QML-based desktop environment built on Quickshell that exposes a lightweight inter-process communication (IPC) interface. This mechanism allows any external program—from Bash scripts to Python applications—to invoke methods on running shell services without direct library linking.

## IPC Architecture and Socket Location

The shell creates a **Unix domain socket** at runtime to listen for incoming commands. By default, the socket resides at:

- `$XDG_RUNTIME_DIR/omarchy-shell` (preferred)
- `/run/user/$UID/omarchy-shell` (fallback when `XDG_RUNTIME_DIR` is unset)

The shell constantly monitors this socket for **JSON-RPC-style messages** formatted as JSON arrays. When a message arrives, the shell dispatches it to the appropriate internal service and returns a JSON response containing either a `result` or an `error` field.

## Communication Methods

External tools can interface with the shell using two primary approaches depending on their complexity requirements.

### Using the `omarchy-shell` CLI Wrapper

The `bin/omarchy-shell` script provides the simplest entry point for external communication. This helper handles socket connection management, JSON marshalling, and timeout enforcement automatically.

The wrapper reads command-line arguments, formats them into the required JSON structure, and writes to the socket. It respects the **`OMARCHY_SHELL_IPC_TIMEOUT`** environment variable to limit wait times for unresponsive shells.

```bash

# Toggle the main menu

omarchy-shell omarchy.menu toggle '{"menu":"root"}'

# Check lock status with a 200ms timeout

OMARCHY_SHELL_IPC_TIMEOUT=0.2s omarchy-shell lock status

```

### Direct Socket Access

For applications requiring high-frequency communication or multiplexed requests, direct socket programming eliminates process-spawning overhead. Any language supporting Unix domain sockets can implement the protocol by connecting to the socket path and exchanging raw JSON messages.

This approach requires manual handling of:

- Socket connection and disconnection
- JSON serialization/deserialization
- Timeout logic implementation

## Message Protocol and Format

All IPC communication follows a strict JSON array structure:

```json
["<target>", "<method>", "<arg-1>", "<arg-2>", ...]

```

- **`<target>`**: The registered service name (e.g., `omarchy.menu`, `omarchy.indicators`, `omarchy.clock`)
- **`<method>`**: The specific operation exposed by that service (e.g., `toggle`, `refresh`, `set`)
- **`<arg-*>`**: Optional arguments as strings or JSON-encoded objects

The shell responds with a JSON object:

```json
{"result": "success"}

```

Or in case of errors:

```json
{"error": "Service not found"}

```

## Core Implementation Files

Understanding the source structure helps when debugging IPC issues or extending functionality.

- **`bin/omarchy-shell`**: The primary CLI entry point that performs socket I/O, applies timeout logic via `OMARCHY_SHELL_IPC_TIMEOUT`, and marshals arguments to/from JSON according to the protocol specification.

- **[`src/OmarchShellIpc.cpp`](https://github.com/omacom/omarchy/blob/main/src/OmarchShellIpc.cpp)**: The low-level C++ implementation handling socket creation, incoming message parsing, and response dispatching to registered QML services.

- **`shell/Ui/Panel.qml`**: UI components expose an **`ipcTarget`** property that forwards QML-side interactions to the IPC layer, often using `Quickshell.execDetached` to invoke `omarchy-shell` with appropriate target and method parameters.

- **`shell/services/PluginRegistry.qml`**: Registers dynamic plugin services with the IPC dispatcher, allowing plugins to declare custom `ipcTarget` identifiers (e.g., `omarchy.weather`) and implement corresponding methods discoverable by external callers.

## Practical Integration Examples

### Bash One-Liners

Use the helper command for quick scripting and cron jobs:

```bash

# Refresh the clock widget

omarchy-shell omarchy.clock refresh

# Set idle stay-awake state

omarchy-shell idle setStayAwake false

```

### Python Socket Client

For direct integration without subprocess overhead:

```python
import socket
import json
import os

runtime_dir = os.getenv('XDG_RUNTIME_DIR', f"/run/user/{os.getuid()}")
sock_path = os.path.join(runtime_dir, "omarchy-shell")

request = json.dumps(["lock", "status"]).encode('utf-8')

with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s:
    s.connect(sock_path)
    s.sendall(request + b'\n')
    response = s.recv(4096).decode('utf-8')

print(json.loads(response))

```

### Systemd Service Integration

Systemd units can invoke shell methods during system state changes:

```ini
[Unit]
Description=Dim screen when idle
After=omarchy-shell.service

[Service]
Type=oneshot
ExecStart=/usr/bin/omarchy-shell idle setStayAwake false

```

### Configuring IPC Timeouts

Prevent scripts from hanging when the shell is not running:

```bash

# Fail after 500 milliseconds

OMARCHY_SHELL_IPC_TIMEOUT=0.5s omarchy-shell omarchy.indicators listPlugins

```

## Summary

- The Omarchy Shell creates a **Unix domain socket** at `$XDG_RUNTIME_DIR/omarchy-shell` for JSON-RPC communication.
- The **`omarchy-shell`** CLI wrapper in `bin/omarchy-shell` provides convenient socket access with timeout support via `OMARCHY_SHELL_IPC_TIMEOUT`.
- Messages follow the format `["target", "method", ...args]` and receive JSON responses with `result` or `error` fields.
- QML components expose **`ipcTarget`** properties defined in files like `shell/Ui/Panel.qml` and registered via `shell/services/PluginRegistry.qml`.
- External tools can choose between simple CLI invocation or direct socket programming for optimal performance.

## Frequently Asked Questions

### Where is the IPC socket located?

The socket path defaults to `$XDG_RUNTIME_DIR/omarchy-shell` when the `XDG_RUNTIME_DIR` environment variable is defined. If unset, the shell falls back to `/run/user/$UID/omarchy-shell` where `$UID` represents the current user ID.

### What programming languages can interface with the shell?

Any language capable of opening Unix domain sockets and parsing JSON can communicate directly with the shell. The repository shows working examples in Bash and Python, but Go, Rust, Node.js, or C applications can implement the same JSON-RPC protocol over the socket without restrictions.

### How does the shell handle malformed IPC requests?

According to the protocol implementation in [`src/OmarchShellIpc.cpp`](https://github.com/omacom/omarchy/blob/main/src/OmarchShellIpc.cpp), the shell validates incoming JSON arrays for correct structure. Malformed messages or requests targeting unregistered services receive JSON error responses containing an `error` field describing the failure, allowing callers to handle exceptions gracefully.

### Can custom plugins expose their own IPC endpoints?

Yes. The `shell/services/PluginRegistry.qml` system allows plugins to declare unique `ipcTarget` identifiers and implement corresponding methods. Once registered, these targets become discoverable and callable via the same socket interface using the standard `["target", "method"]` message format.