Conversation
Package agent-relay functionality as a Claude Code plugin for easy installation and sharing. The plugin provides: - MCP server integration (@agent-relay/mcp) for relay tools - Slash commands: /agent-relay:setup, :status, :spawn, :team, :send - Auto-invoked skill for relay messaging protocol - Curated agent definitions (lead, reviewer, architect, backend, frontend, tester, shadow-reviewer) - PostToolUse and SessionStart hooks for inbox notifications Users can install via `claude --plugin-dir ./plugin` for testing or through a marketplace for distribution. https://claude.ai/code/session_01U4dhgrfTUdXQ2e7Vpexr9e
Add ensure-daemon.sh script that runs on SessionStart to: - Detect if agent-relay is installed (global, ~/.agent-relay, or npx) - Check if daemon is already running via socket/PID check - Start daemon in background with nohup if not running - Output status and available tools to Claude's context - Show install instructions if agent-relay is not found Move inbox check to PostToolUse only; daemon startup runs on SessionStart. https://claude.ai/code/session_01U4dhgrfTUdXQ2e7Vpexr9e
| cat > $AGENT_RELAY_OUTBOX/msg << 'EOF' | ||
| TO: $AGENT_RELAY_SPAWNER | ||
|
|
||
| ACK: Starting on the task. | ||
| EOF |
There was a problem hiding this comment.
🔴 Single-quoted heredoc prevents $AGENT_RELAY_SPAWNER expansion, sending message to literal string instead of spawner agent
In the SKILL.md instructions for replying to a spawner, the heredoc uses << 'EOF' (single-quoted), which suppresses all variable expansion inside the heredoc body. This means TO: $AGENT_RELAY_SPAWNER on line 201 will be written literally as the string $AGENT_RELAY_SPAWNER rather than expanding to the actual spawner agent's name.
Root Cause
At plugin/skills/using-agent-relay/SKILL.md:200-204:
cat > $AGENT_RELAY_OUTBOX/msg << 'EOF'
TO: $AGENT_RELAY_SPAWNER
ACK: Starting on the task.
EOFThe 'EOF' (single-quoted) delimiter tells bash to treat the heredoc body as a literal string with no variable expansion. While $AGENT_RELAY_OUTBOX in the redirect target (outside the heredoc) IS expanded correctly, the $AGENT_RELAY_SPAWNER inside the heredoc body is NOT expanded.
The SKILL.md explicitly instructs agents: "you MUST run it via your Bash/shell tool, not just display it" and "You must EXECUTE the bash command above". An AI agent following these instructions literally would create a file containing the literal text TO: $AGENT_RELAY_SPAWNER, and the relay system would attempt to route the message to an agent literally named $AGENT_RELAY_SPAWNER instead of the actual spawner (e.g., Lead).
Impact: Messages intended for the spawner agent would be misrouted or lost, breaking the ACK protocol and potentially causing retry escalation.
| cat > $AGENT_RELAY_OUTBOX/msg << 'EOF' | |
| TO: $AGENT_RELAY_SPAWNER | |
| ACK: Starting on the task. | |
| EOF | |
| cat > $AGENT_RELAY_OUTBOX/msg << EOF | |
| TO: $AGENT_RELAY_SPAWNER | |
| ACK: Starting on the task. | |
| EOF | |
Was this helpful? React with 👍 or 👎 to provide feedback.
check-inbox.sh was checking /tmp/agent-relay.sock but the daemon creates its socket at <project>/.agent-relay/relay.sock. This caused MCP availability detection to always fail. Also fix SKILL.md troubleshooting to reference the project-local socket path instead of the legacy /tmp path. https://claude.ai/code/session_01U4dhgrfTUdXQ2e7Vpexr9e
Agents interact via $AGENT_RELAY_OUTBOX, MCP tools, and the CLI. Socket paths are internal implementation details. https://claude.ai/code/session_01U4dhgrfTUdXQ2e7Vpexr9e
The installer places the CLI wrapper at ~/.local/bin/agent-relay, not ~/.agent-relay/bin/agent-relay. The previous fallback path would never find the binary. https://claude.ai/code/session_01U4dhgrfTUdXQ2e7Vpexr9e
After an unclean exit (crash, kill -9, reboot), stale socket files block the daemon from restarting. Now we remove stale sockets and PID files when daemon_running() has already determined they're dead. https://claude.ai/code/session_01U4dhgrfTUdXQ2e7Vpexr9e
|
|
||
| # Get agent name from environment | ||
| AGENT_NAME="${AGENT_RELAY_NAME:-}" | ||
| DATA_DIR="${AGENT_RELAY_DIR:-$HOME/.agent-relay}" |
There was a problem hiding this comment.
🔴 check-inbox.sh defaults to wrong inbox directory, missing all messages
The check-inbox.sh script falls back to $HOME/.agent-relay when AGENT_RELAY_DIR is not set, but the entire project uses project-local namespacing where data is stored at $PROJECT_ROOT/.agent-relay/.
Root Cause
At plugin/scripts/check-inbox.sh:7, the fallback is:
DATA_DIR="${AGENT_RELAY_DIR:-$HOME/.agent-relay}"But the daemon and all other tooling in this repo use project-local paths. As seen in packages/config/src/project-namespace.ts:104-111, getProjectPaths() resolves data to <projectRoot>/.agent-relay/. The ensure-daemon.sh in this same PR consistently uses PROJECT_ROOT="$(pwd)" with SOCKET_PATH="$PROJECT_ROOT/.agent-relay/relay.sock" at line 41.
When AGENT_RELAY_DIR is not explicitly set in the environment (which is the common case for a plugin hook — it's invoked by Claude Code, not by the relay spawner), the inbox path resolves to $HOME/.agent-relay/$AGENT_NAME/inbox.md instead of $(pwd)/.agent-relay/$AGENT_NAME/inbox.md. Since the daemon writes inbox files under the project-local .agent-relay/ directory, the hook will never find them and will silently exit at the [ ! -f "$INBOX_PATH" ] check on line 15.
Impact: The PostToolUse inbox notification hook — the primary mechanism for alerting agents to pending messages — is effectively broken whenever AGENT_RELAY_DIR is not explicitly set, which defeats the purpose of the hook.
| DATA_DIR="${AGENT_RELAY_DIR:-$HOME/.agent-relay}" | |
| DATA_DIR="${AGENT_RELAY_DIR:-$(pwd)/.agent-relay}" | |
Was this helpful? React with 👍 or 👎 to provide feedback.
Package agent-relay functionality as a Claude Code plugin for easy
installation and sharing. The plugin provides:
Users can install via
claude --plugin-dir ./pluginfor testing orthrough a marketplace for distribution.
https://claude.ai/code/session_01U4dhgrfTUdXQ2e7Vpexr9e