Creating an Adapter
An adapter is a standalone program that connects enwiro to your window manager or any other application that has a workspace-like abstraction. It translates between enwiro’s environment model and whatever workspace or session concept your platform provides.
You can write an adapter in any language. Enwiro communicates with adapters by running them as subprocesses and exchanging data over stdin/stdout.
How Enwiro Finds Your Adapter
Section titled “How Enwiro Finds Your Adapter”Enwiro scans every directory in $PATH for executables whose name starts with
enwiro-adapter-. The part after that prefix becomes the adapter name.
Examples:
enwiro-adapter-sway- adapter nameswayenwiro-adapter-hyprland- adapter namehyprlandenwiro-adapter-my-wm- adapter namemy-wm
The binary must have executable permissions. Non-executable files are silently ignored. Enwiro also checks the directory containing its own executable, so co-locating your adapter binary there works too.
If only one adapter is installed, enwiro auto-selects it. If you have multiple
adapters installed, set adapter in your configuration file
(~/.config/enwiro/enwiro.toml) to choose which one to use:
adapter = "sway"Subcommands
Section titled “Subcommands”Your adapter binary must handle four subcommands passed as the first argument.
get-active-workspace-id
Section titled “get-active-workspace-id”enwiro-adapter-yourname get-active-workspace-idPrint the name of the currently active environment to stdout. No stdin is provided. Enwiro trims surrounding whitespace from the output.
This is used by enw wrap to determine which environment the user is currently
in. If the user is not in any recognized environment, print an empty string.
Exit with code 0 on success. On failure, exit non-zero and write an error message to stderr.
activate <name>
Section titled “activate <name>”echo '<payload>' | enwiro-adapter-yourname activate my-envSwitch to (or create) a workspace for the named environment. The environment
name is passed as a positional argument after activate.
Enwiro pipes a JSON payload to the adapter’s stdin with the following shape:
{ "version": 1, "managed_envs": [ {"name": "project-a", "slot_score": 0.8}, {"name": "project-b", "slot_score": 0.3} ], "gear": {}}Fields:
version- Protocol version (currently1). Your adapter can match on this to handle future protocol changes gracefully.managed_envs- List of all environments enwiro currently manages, each with aslot_score(a float used for workspace ordering/placement). For example, the i3wm adapter uses this for workspace rebalancing. Adapters that don’t need it can ignore it.gear- Opaque JSON object containing per-environment gear data. Adapters that support auto-opening URLs or GUI applications can walk this structure (see Gear below). Adapters that don’t need this feature can ignore the field entirely.
All fields are optional and have sensible defaults.
Exit with code 0 on success. On failure, exit non-zero and write an error message to stderr.
echo '<payload>' | enwiro-adapter-yourname runSpawn a command in a new window, pane, or terminal within the adapter’s platform. Enwiro pipes a JSON payload to stdin:
{ "version": 1, "env_name": "my-env", "env_path": "/home/user/.enwiro_envs/my-env", "command": "nvim", "args": ["src/main.rs"]}Fields:
version- Protocol version (currently1).env_name- The environment name.env_path- Absolute filesystem path to the environment directory.command- The command to run.args- Arguments to pass to the command (may be empty).
Requirements:
Your adapter must ensure the spawned process has:
- Its working directory set to
env_path. - The environment variable
ENWIRO_ENVset toenv_name.
How the command is spawned is up to the adapter: a new terminal window (i3wm), a new tmux window (tmux), or any other mechanism appropriate for the platform.
Exit with code 0 on success. On failure, exit non-zero and write an error message to stderr.
listen
Section titled “listen”enwiro-adapter-yourname listenStart a long-running process that emits workspace-switch events to stdout as JSON lines (one JSON object per line). The daemon reads these events to track which environment is currently active.
Each event must have this shape:
{"type": "workspace_switch", "env_name": "my-env", "timestamp": 1700000000}Fields:
type- Always the string"workspace_switch".env_name- The environment name that was switched to.timestamp- Unix timestamp (seconds since epoch) of the switch.
The adapter should emit an event whenever the user switches workspaces or sessions. How you detect switches depends on your platform: i3/sway provide IPC event subscriptions, tmux requires polling.
The listen subcommand may accept a --debounce-secs flag to control how
often events are emitted. This is optional but recommended for adapters that
poll.
The daemon terminates the listen process when it shuts down.
The gear field in the activate payload contains structured data about
applications and URLs associated with each environment. Adapters that want to
auto-open applications on activation can walk this structure.
The gear JSON has this shape:
{ "<gear-name>": { "description": "Human-readable description", "web": { "<entry-name>": { "description": "Open the PR", "url": "https://example.com/pr/1" } }, "linux-gui": { "<entry-name>": { "command": ["obsidian", "--vault", "/path/to/vault"] } } }}webentries have aurlfield. The adapter can open these in a browser.linux-guientries have acommandfield (an argv array). The adapter can spawn these as GUI processes.
Gear handling is entirely optional. If your adapter ignores the gear field,
activation still works normally. The gear structure is designed to be
forward-compatible: unknown fields and categories are silently ignored.
Output Encoding
Section titled “Output Encoding”All stdout output must be valid UTF-8. If your binary produces invalid UTF-8, enwiro treats it as an error.
Error Handling
Section titled “Error Handling”- Exit code 0 means success - stdout is parsed as results.
- Non-zero exit code means failure - stdout is discarded and stderr is shown to the user as the error message.
- Adapter failures are reported to the user. Unlike cookbooks (where one failing cookbook doesn’t break the recipe list), a failing adapter prevents the operation from completing.
Example: A Minimal Adapter in Bash
Section titled “Example: A Minimal Adapter in Bash”Here is a minimal adapter skeleton. It does not implement real window management but demonstrates the protocol:
#!/usr/bin/env bashset -euo pipefail
case "${1:-}" in get-active-workspace-id) # Return the environment name from a hypothetical WM # In practice, query your window manager's API here echo "my-env" ;; activate) name="$2" # Read the JSON payload from stdin (optional: parse for gear/managed_envs) payload=$(cat) # Switch to or create a workspace named "$name" echo "Activating $name" >&2 ;; run) # Read the JSON payload from stdin payload=$(cat) env_name=$(echo "$payload" | jq -r '.env_name') env_path=$(echo "$payload" | jq -r '.env_path') command=$(echo "$payload" | jq -r '.command') args=$(echo "$payload" | jq -r '.args[]' 2>/dev/null || true)
# Spawn the command with ENWIRO_ENV set and cwd set to env_path cd "$env_path" ENWIRO_ENV="$env_name" exec "$command" $args ;; listen) # Emit workspace switch events as JSON lines # In practice, subscribe to your WM's event stream while true; do printf '{"type":"workspace_switch","env_name":"my-env","timestamp":%d}\n' \ "$(date +%s)" sleep 5 done ;; *) echo "Unknown subcommand: ${1:-}" >&2 exit 1 ;;esacSave this as enwiro-adapter-example, make it executable (chmod +x), and
place it anywhere on your $PATH. Set adapter = "example" in your enwiro
config to use it.
How It All Fits Together
Section titled “How It All Fits Together”When a user runs enw wrap <command>:
- Enwiro calls
get-active-workspace-idon the configured adapter. - The returned name is matched to an environment in
~/.enwiro_envs/. - The command is run with
ENWIRO_ENVset and the working directory changed to the environment path.
When a user runs enw activate <name>:
- Enwiro constructs an
ActivatePayloadwith managed environments and gear. - The payload is piped to the adapter’s
activatesubcommand via stdin. - The adapter creates or switches to the appropriate workspace.
When a user runs enw run <command>:
- Enwiro constructs a
RunPayloadwith the environment name, path, and command. - The payload is piped to the adapter’s
runsubcommand via stdin. - The adapter spawns the command in a new window/pane with
ENWIRO_ENVand the correct working directory.
When the enwiro daemon starts:
- It spawns the adapter’s
listensubcommand as a long-running child process. - It reads workspace-switch events from the adapter’s stdout.
- These events are used for activity tracking.
get-active-workspace-idmust be fast. It runs synchronously every time the user invokesenw wrap.activatecan be slow. Window manager IPC calls and workspace setup are expected here.- Best-effort gear handling. If a gear URL or GUI command fails to open, log the error and continue. Don’t let a missing browser or application prevent workspace activation.
- Forward compatibility. Use serde defaults or equivalent. If your adapter encounters unknown JSON fields in a payload, ignore them rather than failing. This keeps older adapters compatible with newer enwiro versions.