env/launchers.zsh.example

swarm-mcp profile launchers (zsh)

Source this file from your ~/.zshrc to gain per-profile launcher functions.

A "profile" is just a name you pick (e.g. "personal", "work", "client-x").

Each profile maps the four canonical agent binaries (claude/codex/opencode/

hermes) to launcher aliases of your choice, and points swarm-mcp at the

matching env file under $SWARM_ENV_DIR.

Launch shapes per profile (see env/README.md "Three ways to launch each

agent" for the long form):

worker — profile worker alias (e.g. clowd). Sources the profile env,

exports AGENT_IDENTITY/SWARM_IDENTITY/SWARM_DB_PATH, then execs

the canonical binary. Registers in the swarm as identity:.

gateway — profile lead alias (e.g. clowdg). Same as worker plus

SWARM_ROLE=gateway / SWARM_AGENT_ROLE=planner

so the session routes non-trivial work through dispatch.

vanilla — the unwrapped binary (e.g. plain claude). No alias to define.

SessionStart hooks see no AGENT_IDENTITY and intentionally skip

registration; the session leaves no DB footprint and stays

invisible to swarm peers. Use this for uncoordinated solo work.

Quick start:

1. mkdir -p ~/.config/swarm-mcp

2. Copy env/profile.env.example -> ~/.config/swarm-mcp/.env

and edit identities, MCP names, DB path, herdr socket, etc.

3. Source this file from your shell config and call swarm_define_profile

once per profile to materialize the launcher aliases.

Example invocations are at the bottom of this file — copy whichever rows

match the profiles you want.

export SWARM_ENV_DIR="${SWARM_ENV_DIR:-$HOME/.config/swarm-mcp}"

--- Internal helpers (do not call directly) ----------------------------------

Source $env_file into a subshell, then exec the rest as a command.

_swarm_run() ( local env_file="$1" shift set -a source "$env_file" set +a "$@" )

Source $env_file, force AGENT_IDENTITY/SWARM_DB_PATH to the profile, then exec.

_swarm_run_profile() ( local profile="$1" local env_file="$2" shift 2 set -a source "$env_file" set +a export AGENT_IDENTITY="$profile" export SWARM_IDENTITY="$profile" export SWARM_DB_PATH="${SWARM_DB_PATH:-$HOME/.swarm-mcp-$profile/swarm.db}" "$@" )

Same as _swarm_run_profile but flags the session as a gateway/lead.

_swarm_run_lead() ( local profile="$1" local env_file="$2" local runtime="$3" shift 3 set -a source "$env_file" set +a export AGENT_IDENTITY="$profile" export SWARM_IDENTITY="$profile" export SWARM_DB_PATH="${SWARM_DB_PATH:-$HOME/.swarm-mcp-$profile/swarm.db}" case "$runtime" in claude) export SWARM_CC_ROLE=gateway export SWARM_CC_AGENT_ROLE=planner ;; codex) export SWARM_CODEX_ROLE=gateway export SWARM_CODEX_AGENT_ROLE=planner ;; opencode) export SWARM_OPENCODE_ROLE=gateway export SWARM_OPENCODE_AGENT_ROLE=planner ;; hermes) export SWARM_HERMES_ROLE=gateway export SWARM_HERMES_AGENT_ROLE=planner ;; esac "$@" )

Launch a visible herdr server bound to a profile-scoped socket path.

_swarm_herdr() ( local socket_path="$1" local session="$2" shift 2 mkdir -p "${socket_path:h}" HERDR_SOCKET_PATH="$socket_path" command herdr --session "$session" "$@" )

--- Public generator ---------------------------------------------------------

swarm_define_profile [option=value ...]

Materializes launcher shell functions for one profile. Options (all

optional unless noted):

env_file= Defaults to $SWARM_ENV_DIR/.env

claude= Worker alias for the claude binary

codex= Worker alias for the codex binary

opencode= Worker alias for the opencode binary

hermes= Worker alias for the hermes binary

claude_lead= Lead/gateway alias for claude (adds gateway env)

codex_lead= Lead/gateway alias for codex (adds gateway env)

opencode_lead= Lead/gateway alias for opencode (adds gateway env)

hermes_lead= Lead/gateway alias for hermes (adds gateway env)

herdr= Alias that launches a visible herdr server

herdr_socket= Override herdr socket; defaults to

${HERMES_HOST_HOME:-$HOME}/.config/herdr/sessions//herdr.sock

claude_args= Extra args appended to every claude launch

(split on whitespace; defaults to "--enable-auto-mode")

claude_lead_args= Extra args for the claude_lead alias only; falls

back to claude_args when unset. Use this to enable

gateway-only flags like --remote-control.

Aliases you omit simply aren't defined — you can mix profile-specific

launchers freely. The function exports SWARM_HARNESS_= into

the profile env file the next time it is sourced; swarm-mcp reads those to

resolve dispatch normalization for this profile.

swarm_define_profile() { emulate -L zsh local profile="$1" shift if [[ -z "$profile" ]]; then print -u2 "swarm_define_profile: profile name required" return 64 fi local env_file="$SWARM_ENV_DIR/$profile.env" local claude_alias="" codex_alias="" opencode_alias="" hermes_alias="" local claude_lead_alias="" codex_lead_alias="" local opencode_lead_alias="" hermes_lead_alias="" local herdr_alias="" herdr_socket="" local claude_args="--enable-auto-mode" local claude_lead_args="" local kv key value for kv in "$@"; do key="${kv%%=}" value="${kv#=}" case "$key" in env_file) env_file="$value" ;; claude) claude_alias="$value" ;; codex) codex_alias="$value" ;; opencode) opencode_alias="$value" ;; hermes) hermes_alias="$value" ;; claude_lead) claude_lead_alias="$value" ;; codex_lead) codex_lead_alias="$value" ;; opencode_lead) opencode_lead_alias="$value" ;; hermes_lead) hermes_lead_alias="$value" ;; herdr) herdr_alias="$value" ;; herdr_socket) herdr_socket="$value" ;; claude_args) claude_args="$value" ;; claude_lead_args) claude_lead_args="$value" ;; *) print -u2 "swarm_define_profile($profile): unknown option '$key'" return 64 ;; esac done if [[ -z "$herdr_socket" ]]; then herdr_socket="${HERMES_HOST_HOME:-$HOME}/.config/herdr/sessions/$profile/herdr.sock" fi [[ -z "$claude_lead_args" ]] && claude_lead_args="$claude_args"

Define each requested alias. eval is used to template the function name;

bodies stay quoted so $profile/$env_file values are baked in at define time.

if [[ -n "$claude_alias" ]]; then eval "$claude_alias() { _swarm_run_profile $(printf %q "$profile") $(printf %q "$env_file") command claude ${claude_args} "$@"; }" fi if [[ -n "$codex_alias" ]]; then eval "$codex_alias() { _swarm_run_profile $(printf %q "$profile") $(printf %q "$env_file") command codex "$@"; }" fi if [[ -n "$opencode_alias" ]]; then eval "$opencode_alias() { _swarm_run_profile $(printf %q "$profile") $(printf %q "$env_file") command opencode "$@"; }" fi if [[ -n "$hermes_alias" ]]; then eval "$hermes_alias() { _swarm_run_profile $(printf %q "$profile") $(printf %q "$env_file") command hermes "$@"; }" fi if [[ -n "$claude_lead_alias" ]]; then eval "$claude_lead_alias() { _swarm_run_lead $(printf %q "$profile") $(printf %q "$env_file") claude command claude ${claude_lead_args} "$@"; }" fi if [[ -n "$codex_lead_alias" ]]; then eval "$codex_lead_alias() { _swarm_run_lead $(printf %q "$profile") $(printf %q "$env_file") codex command codex "$@"; }" fi if [[ -n "$opencode_lead_alias" ]]; then eval "$opencode_lead_alias() { _swarm_run_lead $(printf %q "$profile") $(printf %q "$env_file") opencode command opencode "$@"; }" fi if [[ -n "$hermes_lead_alias" ]]; then eval "$hermes_lead_alias() { _swarm_run_lead $(printf %q "$profile") $(printf %q "$env_file") hermes command hermes "$@"; }" fi if [[ -n "$herdr_alias" ]]; then eval "$herdr_alias() { _swarm_herdr $(printf %q "$herdr_socket") $(printf %q "$profile") "$@"; }" fi }

--- Auto-discovery -----------------------------------------------------------

Scan $SWARM_ENV_DIR for *.env files and call swarm_define_profile for each,

using the SWARM_HARNESS_* values declared in the file. This makes profile

setup a single step: drop ~/.config/swarm-mcp/.env and the matching

aliases appear on next shell. Manual swarm_define_profile calls (below or in

your own dotfiles) still work and override the auto-defined ones.

Opt out by setting SWARM_MCP_DISABLE_AUTODEFINE=1 before sourcing this file.

swarm_autodefine_profiles() { emulate -L zsh setopt local_options null_glob extended_glob

[[ -n "${SWARM_MCP_DISABLE_AUTODEFINE:-}" ]] && return 0 [[ -d "$SWARM_ENV_DIR" ]] || return 0

local env_file profile local claude_alias codex_alias opencode_alias hermes_alias local claude_lead_alias codex_lead_alias opencode_lead_alias hermes_lead_alias local herdr_alias local claude_args_val claude_lead_args_val local -a args

for env_file in "$SWARM_ENV_DIR"/*.env(.N); do [[ -r "$env_file" ]] || continue profile="${env_file:t:r}"

# Read SWARM_HARNESS_* from the file in a subshell so per-profile
# AGENT_IDENTITY / SWARM_DB_PATH don't leak into the parent shell.
eval "$(
  source "$env_file" 2>/dev/null
  printf 'claude_alias=%q

' "${SWARM_HARNESS_CLAUDE:-}" printf 'codex_alias=%q ' "${SWARM_HARNESS_CODEX:-}" printf 'opencode_alias=%q ' "${SWARM_HARNESS_OPENCODE:-}" printf 'hermes_alias=%q ' "${SWARM_HARNESS_HERMES:-}" printf 'claude_lead_alias=%q ' "${SWARM_HARNESS_CLAUDE_LEAD:-}" printf 'codex_lead_alias=%q ' "${SWARM_HARNESS_CODEX_LEAD:-}" printf 'opencode_lead_alias=%q ' "${SWARM_HARNESS_OPENCODE_LEAD:-}" printf 'hermes_lead_alias=%q ' "${SWARM_HARNESS_HERMES_LEAD:-}" printf 'herdr_alias=%q ' "${SWARM_HARNESS_HERDR:-}" printf 'claude_args_val=%q ' "${SWARM_HARNESS_CLAUDE_ARGS:-}" printf 'claude_lead_args_val=%q ' "${SWARM_HARNESS_CLAUDE_LEAD_ARGS:-}" )"

args=()
[[ -n "$claude_alias" ]]         && args+=("claude=$claude_alias")
[[ -n "$codex_alias" ]]          && args+=("codex=$codex_alias")
[[ -n "$opencode_alias" ]]       && args+=("opencode=$opencode_alias")
[[ -n "$hermes_alias" ]]         && args+=("hermes=$hermes_alias")
[[ -n "$claude_lead_alias" ]]    && args+=("claude_lead=$claude_lead_alias")
[[ -n "$codex_lead_alias" ]]     && args+=("codex_lead=$codex_lead_alias")
[[ -n "$opencode_lead_alias" ]]  && args+=("opencode_lead=$opencode_lead_alias")
[[ -n "$hermes_lead_alias" ]]    && args+=("hermes_lead=$hermes_lead_alias")
[[ -n "$herdr_alias" ]]          && args+=("herdr=$herdr_alias")
[[ -n "$claude_args_val" ]]      && args+=("claude_args=$claude_args_val")
[[ -n "$claude_lead_args_val" ]] && args+=("claude_lead_args=$claude_lead_args_val")

(( ${#args[@]} > 0 )) && swarm_define_profile "$profile" "${args[@]}"

done }

swarm_autodefine_profiles

--- Manual override examples (optional) --------------------------------------

Profile names and alias names are arbitrary — auto-discovery above will pick

them up from your env files. These manual calls are only needed if you want

to override the aliases declared in a profile env file, or if you'd rather

not rely on auto-discovery at all (set SWARM_MCP_DISABLE_AUTODEFINE=1).

swarm_define_profile personal \

claude=clowd \

codex=cdx \

opencode=opc \

hermes=hermesp-worker \

claude_lead=clowdg \

codex_lead=cdxg \

opencode_lead=opcg \

hermes_lead=hermesp \

herdr=herdrp

swarm_define_profile work \

claude=clawd \

codex=codex \

opencode=opencode \

hermes=hermesw-worker \

claude_lead=clawdg \

codex_lead=codexg \

opencode_lead=opencodeg \

hermes_lead=hermesw \

herdr=herdrw