Skip to content

Support concurrent per-project wrapper sessions for shared installs #67

Description

@maxlamagna

Agentchattr already supports per-project data and port overrides for shared installs, but interactive CLI wrappers still collide on tmux session names and cannot override per-agent runtime fields such as cwd without editing shared config. This proposal adds opt-in wrapper session prefixes and narrowly scoped per-agent env overrides, preserving default behavior.

Motivation

Currently wrapper.py:871 always names the tmux session agentchattr-{assigned_name}. Each repo's server issues its own slot counter starting at 1, so the first codex wrapper in any repo always asks for agentchattr-codex. wrapper_unix.py:134-138 then kills the existing session of that name before creating its own — evicting the first repo's agent. Reproduced 2026-05-27 across two onboarded repos.

Proposed change (one file, ~10 LOC)

Two surgical edits in wrapper.py:

  1. Whitelisted per-agent env-var overrides. After agent_cfg = config.get("agents", {}).get(agent, {}) (line 589), inject a small loop that lets AGENTCHATTR_AGENT_<KEY_UPPER> env vars override agent_cfg[<key_lower>] — restricted to a whitelist {"cwd", "mcp_settings_path"} to prevent committed env files from overriding security-sensitive keys like command or mcp_inject.

  2. Opt-in slug-prefixed Unix session name. When AGENTCHATTR_REPO_SLUG is set and non-empty, the tmux session is agentchattr-{slug}-{assigned_name} instead of agentchattr-{assigned_name}. When unset/empty, behaviour is identical.

Both env vars are opt-in. With them unset, behaviour is byte-for-byte unchanged.

Inline diff (commit 61801d0, against v0.4.0 / commit 0440f5d)

diff --git a/wrapper.py b/wrapper.py
@@ -587,6 +587,17 @@ def main():
     agent = args.agent
     agent_cfg = config.get("agents", {}).get(agent, {})
+    # Per-invocation per-agent overrides via env vars.
+    # Format: AGENTCHATTR_AGENT_<KEY_UPPER> overrides agent_cfg[<key_lower>].
+    # Whitelisted to prevent committed project.env files from overriding
+    # security-sensitive keys like `command` or `mcp_inject`.
+    _AGENT_OVERRIDE_ALLOWED = {"cwd", "mcp_settings_path"}
+    for _env_key, _env_val in os.environ.items():
+        if not _env_key.startswith("AGENTCHATTR_AGENT_") or not _env_val:
+            continue
+        _cfg_key = _env_key[len("AGENTCHATTR_AGENT_"):].lower()
+        if _cfg_key in _AGENT_OVERRIDE_ALLOWED:
+            agent_cfg[_cfg_key] = _env_val
     cwd = agent_cfg.get("cwd", ".")
@@ -868,7 +879,11 @@ def main():
-        unix_session_name = f"agentchattr-{assigned_name}"
+        _slug = os.environ.get("AGENTCHATTR_REPO_SLUG", "").strip()
+        unix_session_name = (
+            f"agentchattr-{_slug}-{assigned_name}" if _slug
+            else f"agentchattr-{assigned_name}"
+        )

Tests included (Python unittest, 11 tests covering whitelist behaviour + slug fallback + structural presence) — available in our local checkout.

Happy to push to a fork and open a PR if this direction is acceptable; I held off pending your feedback on the API shape (env vars vs. CLI flags, whitelist scope, etc.).

Why env vars (vs. CLI flags)

The downstream caller is a per-project launcher script that already exports AGENTCHATTR_DATA_DIR / AGENTCHATTR_PORT / etc. (per v0.4.0's env-var-driven config_loader.py:30-36). Per-agent overrides as env vars stay consistent with that pattern; the whitelist gives the same safety as a CLI parser would.

Happy to discuss alternatives.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions