feat: make sessions terminal neutral
Some checks failed
tamq-ci / test (push) Failing after 6s

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a03397-4d51-7fd1-8ff2-946eb22ea2bc
This commit is contained in:
tegwick 2026-08-24 20:10:08 +02:00
parent 408d32df88
commit 74b2f27997
20 changed files with 608 additions and 182 deletions

View file

@ -1,7 +1,7 @@
# tmux-amq
Tmux Agentic Message Queueing (`tamq`) is a local, durable message queue for
agent workers running in gita-registered repositories.
Tmux Agentic Message Queueing (`tamq`) provides repository-aware tmux sessions
and a local, durable message queue. It does not assume who or what uses a pane.
The local alpha provides tmux endpoint lifecycle, local SQLite history and
leases, direct `@repo:` routing, JSONL export/replay, and a Unix-socket protocol
@ -10,8 +10,7 @@ for a later coordination-engine adapter.
## Install and start a local session
Prerequisites must be available on `PATH`: Python 3.11+, [uv](https://docs.astral.sh/uv/),
tmux, gita, and the agent command you want to run (`codex` by default). Each
repository must already have an exact gita slug and path.
tmux, and gita. Each repository must already have an exact gita slug and path.
Install or upgrade `tamq` as an isolated user tool:
@ -21,47 +20,74 @@ command -v tamq
tamq --version
```
Start an attached two-repository Codex session:
Start an attached two-repository shell session:
```bash
tamq start --command codex railiance-platform activity-core
tamq flex-auth audit-core
```
This creates or reuses the managed `tamq` session, opens same-named windows in
the exact gita paths for `railiance-platform` and `activity-core`, launches Codex
behind `tamq tap` in each new window, and attaches to the first window. Codex is
the default, so this is equivalent:
the exact gita paths, leaves tmux's ordinary interactive shells untouched, and
attaches to the first window. The explicit form is equivalent:
```bash
tamq start railiance-platform activity-core
tamq start flex-auth audit-core
```
Set up the session without attaching, then attach later:
```bash
tamq start --detach --command codex railiance-platform activity-core
tamq start --detach flex-auth audit-core
tamq status
tamq attach
```
Repeated starts reuse existing windows and do not launch a second agent in
them. `--cmd` remains an alias for `--command`. A quoted command may include
arguments, for example `--command 'codex --profile local'`.
No initial command runs unless requested. To run one explicitly in each newly
created window, use `--command`; tamq runs exactly that command and makes no
assumption about its purpose:
An already-running pane keeps the `tamq tap` code that launched it. After
upgrading from an earlier alpha, recreate the managed session once so terminal
mode and resize fixes take effect:
```bash
tamq --command codex flex-auth audit-core
tamq start --command 'htop --tree' flex-auth audit-core
```
`--cmd` remains an alias for `--command`. Repeated starts reuse existing
windows and never run another initial command in them.
## Exchange messages manually
Each managed shell exports its own repository slug as `TAMQ_REPO`. From the
`flex-auth` window, queue a message:
```bash
tamq send '@audit-core: please review the auth boundary'
```
In the `audit-core` window, inspect and acknowledge it:
```bash
tamq inbox
tamq ack <message-id>
```
Outside a managed window, use `tamq inbox --repo audit-core` and optionally
`--json`. Manual messages remain durable and pending until acknowledged. They
are never injected as terminal keystrokes, so they cannot corrupt a command
being typed in the target pane.
After upgrading from the earlier Codex-default alpha, recreate the managed
session once so existing panes are replaced by neutral shells and the broker is
re-registered in manual delivery mode:
```bash
tamq stop
tmux kill-session -t tamq
tamq start --command codex railiance-platform activity-core
tamq flex-auth audit-core
```
For degraded tmux-only use, `tamq start --no-service ...` launches the selected
agent directly, without `tamq tap`, socket endpoint registration, or message
delivery. Stop the broker and remove the managed tmux session explicitly when
finished:
For degraded tmux-only use, `tamq start --no-service ...` skips socket endpoint
registration and durable messaging. Stop the broker and remove the managed tmux
session explicitly when finished:
```bash
tamq stop
@ -77,16 +103,14 @@ anywhere with `uv tool uninstall tmux-amq`.
uv run pytest
uv run tamq --help
uv run tamq --version
uv run tamq start --cmd codex net-kingdom railiance-platform
uv run tamq start net-kingdom railiance-platform
uv run tamq attach
```
The alpha includes the local SQLite queue and a tmux endpoint
manager, strict gita target validation, and a control-mode client for tmux
operations/injection, and the PTY tap for full-duplex input observation. The
control-mode client alone does not expose arbitrary pane input; `tamq tap` is
the supported input-broker hook. `tamq send` remains available as an explicit
fallback. coordination-engine integration remains a later phase.
The alpha includes the local SQLite queue, neutral tmux endpoint manager, strict
gita target validation, manual inbox, control-mode client, and an explicit PTY
tap for integration experiments. Coordination-engine integration remains a
later phase.
## Terminal architecture
@ -94,16 +118,17 @@ fallback. coordination-engine integration remains a later phase.
1. tmux control mode is the topology and output/control stream;
2. the local broker assigns endpoint/source identity and durably queues intent;
3. `tamq tap` is a full-duplex PTY proxy around the agent process. It forwards
3. Explicit `tamq tap` mode is a full-duplex PTY proxy around a command. It forwards
bytes unchanged in raw terminal mode, propagates terminal resize and lifecycle
signals, and observes complete input lines for `@repo:` routing.
This keeps tmux-specific topology concerns separate from reusable terminal I/O
observation and message identity.
Pending messages are delivered through the control-mode client as
`#sender-repo: body`, then marked `injected` in SQLite. Delivery is
endpoint-scoped and uses the same message ID for retry/deduplication.
Neutral endpoints use manual delivery: messages stay in the durable inbox and
never become pane input. The legacy pane-delivery path is available only with
the explicit `tamq start --tap --command ...` opt-in; it remains subject to the
retry and acknowledgement limitations tracked by `TAMQ-WP-0003`.
The visible endpoint label is `tmux-amq-<PID>`; each boot also receives an
instance nonce so PID reuse cannot collide with prior leases or receipts.