Skip to content

Configuration Guide

susshi reads ~/.susshi.yml by default. This page documents the full schema and inheritance model.

Configuration Inheritance

Settings are resolved with this priority (highest last):

  1. defaults
  2. group
  3. environment
  4. server

Field semantics by inheritance level

Not all fields follow the same rule. Three distinct semantics apply:

Semantic Fields Behaviour
OVERRIDE user, ssh_key, ssh_cert, ssh_agent_sock, ssh_port, mode, ssh_options, wallix, jump, production Lower level replaces the parent value entirely
REPLACE tunnels Lower level replaces the parent list entirely; if absent the parent list is used
UNION tags, probe_filesystems Every level appends its values to the parent list (duplicates are removed)

Fields only available in defaults (not overridable per group/env/server): theme, keep_open, default_filter, use_system_ssh_config, control_master, agent_forwarding, control_path, control_persist, pre_connect_hook, post_disconnect_hook, hook_timeout_secs, confirm_production.

Field availability per level

Field defaults group environment server
user ✓ ✓ ✓ ✓
ssh_key ✓ ✓ ✓ ✓
ssh_cert ✓ — — ✓
ssh_agent_sock ✓ — — ✓
ssh_port ✓ ✓ ✓ ✓
ssh_options ✓ ✓ ✓ ✓
mode ✓ ✓ ✓ ✓
wallix block ✓ ✓ ✓ ✓
wallix_group — ✓ ✓ ✓
jump ✓ ✓ ✓ ✓
tunnels ✓ ✓ ✓ ✓
tags ✓ ✓ ✓ ✓
probe_filesystems ✓ ✓ ✓ ✓
pre_connect_hook ✓ — — ✓
post_disconnect_hook ✓ — — ✓
hook_timeout_secs ✓ — — —
control_master ✓ — — —
agent_forwarding ✓ — — —
control_path ✓ — — —
control_persist ✓ — — —
use_system_ssh_config ✓ — — —
keep_open ✓ — — —
default_filter ✓ — — —
theme ✓ — — —
production ✓ ✓ ✓ ✓
confirm_production ✓ — — —
name — ✓ ✓ ✓
host — — — ✓
notes — — — ✓

Default values when absent

Field Default
user "root"
ssh_key "~/.ssh/id_rsa"
ssh_port 22
mode direct
hook_timeout_secs 5
control_master false
agent_forwarding false
control_path "~/.ssh/ctl/%h_%p_%r"
control_persist "10m"
keep_open false
use_system_ssh_config false
production auto-detected from the environment name (see below)
confirm_production false
wallix.auto_select true
wallix.fail_if_menu_match_error true
wallix.selection_timeout_secs 8
wallix.direct false
wallix.account "default"
wallix.protocol "SSH"

includes (Multi-file Configuration)

Use includes to split configuration by team, perimeter, or environment:

includes:
  - label: "DEV"
    path: "~/.susshi_dev.yml"
  - label: "QUALIF"
    path: "~/.susshi_qualif.yml"
    merge_defaults: true

Fields:

  • label: displayed as a namespace header in the TUI.
  • path: absolute path, ~-expanded path, or a https:// / http:// URL.
  • merge_defaults (optional, default: false): merge main-file defaults as base values for the included file.

The wallix block of an included file's defaults is merged field by field with the main file's one. An include can therefore set only the Wallix group for its perimeter (and its own sub-includes) while inheriting the bastion host / user from the main file:

# ~/.susshi.yml
defaults:
  mode: "wallix"
  wallix:
    host: "bastion.example.com"
    user: "jdoe"
includes:
  - label: "TEAM A"
    path: "~/.susshi_team_a.yml"
    merge_defaults: true
# ~/.susshi_team_a.yml
defaults:
  wallix:
    group: "team-a-admins"   # host/user inherited from ~/.susshi.yml
groups:
  - ...

HTTPS includes

path can be a full HTTPS URL. susshi will fetch the file over TLS at startup:

includes:
  - label: "SHARED"
    path: "https://inventory.example.com/team-servers.yml"
    merge_defaults: true

Behavior:

  • The URL is fetched synchronously at startup (same point as file includes).
  • HTTP errors and network failures are non-fatal — emitted as LoadError warnings.
  • The downloaded content is validated with the same unknown-field checks as local files.
  • Recursive includes inside a URL-fetched file use normal local-path resolution.

Behavior (all includes):

  • Includes are resolved recursively.
  • Circular includes are reported as non-blocking warnings.
  • Missing/unreadable files are non-fatal warnings.
  • Unknown YAML fields emit non-blocking ValidationWarning entries.

defaults

Global values applied unless overridden. See the field availability table above for the full list.

Jump block

jump is always a list (even for one host). The entire list is replaced by a child level that defines jump:

jump:
  - host: "jump1.example.com"
    user: "jump-user"
  - host: "jump2.example.com"    # multi-hop: second hop
    user: "jump-user"

Wallix block

wallix:
  host: "bastion.example.com"
  user: "bastion-user"
  group: "devops-admins"
  account: "default"
  protocol: "SSH"
  auto_select: true
  fail_if_menu_match_error: true
  selection_timeout_secs: 8
  # direct: false          # menu flow only: skip menu probe for direct-checkout targets
  # authorization: ""      # force exact Wallix authorization name (skips menu matching)
  # authorizations: ["PR-APP_{group}"]  # candidate authorizations, {group} = suffix above
  # header_columns: ["ID", "Cible", "Autorisation"]  # override if bastion uses different column labels

bastion is accepted as a backward-compatible alias key.

Wallix-specific fields:

  • template — login-string template. Default: {target_user}@%n:SSH:{bastion_user}.
  • direct — skip the menu probe in the menu flow. No effect when an authorization is known (the direct login is used).
  • authorization — force the exact Wallix authorization name. Skips menu matching when set.
  • authorizations — candidate authorization names, in order of preference; {group} is replaced by group. A single candidate enables the direct login (no menu); several are tried in order. See Wallix Guide.
  • header_columns — list of tokens used to detect the menu header row. Override if your bastion uses localized or custom column names.

Tunnels

Tunnels use REPLACE semantics: a child level that defines tunnels replaces the parent list entirely. This allows per-environment or per-server tunnel sets without inheriting unwanted parent tunnels.

tunnels:
  - local_port: 5432
    remote_host: 127.0.0.1
    remote_port: 5432
    label: "PostgreSQL"     # optional — auto-generated if absent

In wallix mode, tunnels require a known Wallix authorization — see Tunnels.

Tags

Tags use UNION semantics: every level (defaults → group → env → server) appends its tags to the accumulated set. Duplicates are removed (first occurrence wins).

defaults:
  tags: [infra]
groups:
  - name: Prod
    tags: [prod]
    environments:
      - name: EU
        tags: [eu-west]
        servers:
          - name: web-01
            host: 10.0.0.1
            tags: [web]
# web-01 resolved tags: [infra, prod, eu-west, web]

Tags can be used to filter servers in the TUI (/) or in --export-filter.

Production servers

Servers flagged as production get a red PROD badge in the list and the status bar, and a red border with a ⚠ PRODUCTION line in the details panel.

  • Explicit flag: production: true|false at any level (defaults, group, environment, server). The most specific level wins, so a server can opt out of a production environment.
  • Auto-detection (fallback when no level sets the flag): the environment name is prod, production or prd (case-insensitive). Names such as preprod or product-api do not match.
  • Confirmation (opt-in): set confirm_production: true in defaults to be asked before connecting to a production server. Only y confirms; n or Esc cancels (Enter is ignored on purpose, so a reflex double-press cannot bypass it).
defaults:
  confirm_production: true

groups:
  - name: Shop
    environments:
      - name: prod          # auto-detected
        servers:
          - name: web-1
            host: 203.0.113.10
      - name: staging
        production: true    # explicit flag
        servers:
          - name: web-stg
            host: 203.0.113.20

_vars and Interpolation

Define per-file variables:

_vars:
  bastion: "bastion.prod.example.com"
  env: "prod"

Use placeholders in any string field:

name: "api-{{ env }}"
host: "{{ bastion }}"

Rules:

  • Scope is file-local (does not leak across includes).
  • Undefined variables emit a non-blocking warning and leave the {{ placeholder }} intact.
  • Built-in {{ index }} expands to the 1-based server position within each list.

groups, environments, and servers

Top-level inventory is defined in groups.

A group can contain:

  • servers directly (level 2: Group → Server), or
  • nested environments, each with servers (level 3: Group → Environment → Server).

Any level may override defaults.

Server-specific fields

  • name, host — required
  • mode — direct, jump, or wallix
  • tags — string labels, merged with parent tags (UNION)
  • notes — free-form description shown in the detail panel
  • ssh_key — path to the private key (tilde expanded)
  • ssh_cert — path to a signed SSH certificate passed alongside ssh_key
  • ssh_agent_sock — path to a Unix socket for a dedicated SSH agent (Unix only)
  • tunnels — predefined local-port-forwarding tunnels (REPLACE semantics)
  • pre_connect_hook, post_disconnect_hook — server-level hook overrides

Complete Example

See ../examples/full_config.yaml for a complete annotated configuration.