Skip to content

Troubleshooting

Quick fixes for common Batty issues.

batty start fails: no team config found

Cause: No .batty/team_config/team.yaml in the project.

batty init                             # scaffold team config

batty start fails: session already exists

Cause: A previous session wasn't stopped.

batty stop                             # stop existing session
batty start                            # start fresh

tmux version error on startup

Cause: tmux is too old or missing.

tmux -V                                # check version

Recommended: >= 3.2. Minimum: 3.1. Below 3.1 is not supported. Upgrade tmux and retry.

kanban-md not found

Cause: kanban-md is not installed or not on PATH.

cargo install kanban-md --locked

Ensure ~/.cargo/bin is in your PATH.

DevSpace AIM catalog entries duplicate across launches

Cause: AIM currently soft-deletes packages on uninstall. Old ~/.aim/packages/*/eventId-* directories can survive across DevSpace launches, so later Batty-launched engineer sessions can see duplicate package/catalog entries.

Batty does not currently ship the affected DevSpace startup hook in this repo. If your environment uses an external bootstrap script such as blueprint_startup.sh, keep the AIM cleanup workaround there until AIM fixes uninstall behavior.

Safe workaround: keep only the newest eventId-* directory inside each AIM package directory before launching Batty sessions.

for package_dir in "${HOME}"/.aim/packages/*; do
  [ -d "${package_dir}" ] || continue
  newest=""
  newest_mtime=0

  for event_dir in "${package_dir}"/eventId-*; do
    [ -d "${event_dir}" ] || continue
    mtime="$(stat -c '%Y' "${event_dir}" 2>/dev/null || stat -f '%m' "${event_dir}")"
    if [ "${mtime}" -gt "${newest_mtime}" ]; then
      newest="${event_dir}"
      newest_mtime="${mtime}"
    fi
  done

  for event_dir in "${package_dir}"/eventId-*; do
    [ -d "${event_dir}" ] || continue
    [ "${event_dir}" = "${newest}" ] || rm -rf -- "${event_dir}"
  done
done

Run that in the DevSpace startup hook before AIM package discovery. If a public upstream AIM issue or PR becomes available, add its link to planning/issues.md and keep this workaround until the soft-delete behavior is fixed.

MCP servers collide between concurrent engineers

Cause: Some MCP servers use fixed ports, socket paths, cache files, or remote lock/table keys. If two Batty engineers launch the same server with those singleton resources, one can fail silently or corrupt shared state.

Batty exports a per-member MCP namespace into every launched agent process:

printf '%s\n' "$BATTY_MCP_NAMESPACE"
printf '%s\n' "$BATTY_MCP_RESOURCE_DIR"
printf '%s\n' "$BATTY_MCP_PORT_BASE"

Configure MCP servers to derive resources from those variables:

--state-dir "$BATTY_MCP_RESOURCE_DIR/server-name"
--socket "$BATTY_MCP_RESOURCE_DIR/server-name.sock"
--port "$BATTY_MCP_PORT_BASE"
--ddb-prefix "$BATTY_MCP_NAMESPACE"

If a server cannot be namespaced, serialize it with the shared Batty lock:

flock "$BATTY_MCP_SHARED_LOCK" mcp-server-command

Two concurrent engineers should report different namespace/resource/port values and the same shared lock path. If not, restart the Batty daemon with a current binary and confirm the agent was launched by Batty rather than by hand.

No session to attach to

Cause: The team session isn't running.

tmux list-sessions                     # see what's running
batty start                            # start a new session
batty attach                           # then attach

Messages not being delivered

Cause: The daemon may not be running, or the target member name is wrong.

  1. Check daemon is alive:
cat .batty/daemon.pid                  # get PID
ps aux | grep batty                    # verify process is running
  1. Check the inbox directly:
batty inbox <member>                   # list all messages
  1. Check daemon logs:
tail -50 .batty/daemon.log

Agent not responding in its pane

Cause: The agent may have exited or be waiting for input.

  1. Attach and check: batty attach, then navigate to the agent's pane
  2. Check daemon logs for spawn errors: tail .batty/daemon.log
  3. Verify the agent binary is available: which claude or which codex

For unattended teams, keep auto_respawn_on_crash: true in team.yaml so crashed shim agents are restarted automatically. Set it to false only while debugging or when you want to restart panes manually.

batty send rejected: not allowed to message

Cause: The talks_to rules in team.yaml don't allow this communication path.

Check team.yaml and adjust talks_to for the sender's role. The default hierarchy is:

  • Architect \<-> Manager
  • Manager \<-> Engineer

The human (CLI user) can always message any role.

Validate fails: layout zones exceed 100%

Cause: Zone width_pct values in layout.zones sum to more than 100.

batty validate                         # shows the specific error

Adjust width_pct values to sum to 100 or less.

Worktree merge conflicts

Cause: An engineer's worktree branch conflicts with main.

batty merge eng-1-1                    # attempt merge

If conflicts occur, resolve them manually in the worktree directory, then complete the merge.

Auto-merge outcomes differ between tasks

Cause: This is expected. Batty's auto-merge path has multiple supported outcomes per task, so a batch of green completions can split across done, review, retry, revert, or escalation.

Start with:

batty board summary
batty inbox manager
batty metrics

Then interpret the result per task:

  1. If the task moved to review, Batty decided the diff was not safe for unattended merge. Common reasons are large diffs, config changes, migration changes, or an explicit per-task override.
  2. If the engineer was told to retry after a rebase conflict, resolve the conflict in the engineer worktree and let them complete the task again.
  3. If the manager received a "failed post-merge verification on main and was reverted" message, treat that as a real rollback. Inspect the failing output, create follow-up work, and do not assume the change is still on main.
  4. If the manager received "passed tests but could not be merged to main", the queue could not finish the merge safely. Clean the main worktree if needed, retry manually, or redirect the engineer.

Telegram messages are not arriving

Cause: The bot token, allowed user ID, or Telegram chat bootstrap step is incomplete.

Check these in order:

  1. Confirm the user role in .batty/team_config/team.yaml has channel: telegram and a channel_config block.
  2. If you rely on BATTY_TELEGRAM_BOT_TOKEN, verify it is exported in the shell that launches batty start.
  3. DM the bot first and send /start; Telegram will not let bots initiate a new chat.
  4. Re-run batty telegram if you need to refresh the token or allowed user ID.
  5. Restart Batty after changes:
batty stop
batty start

Discord commands arrive but are ignored

Cause: The Discord bot can read channel metadata but cannot read message text because Message Content Intent is disabled.

Check batty status and .batty/daemon.log for a Discord MESSAGE_CONTENT intent fault. If present, open the Discord Developer Portal, select the bot application, go to Bot -> Privileged Gateway Intents, enable Message Content Intent, then restart Batty.

batty stop
batty start

Batty advances the Discord cursor even for empty-content messages so the same bad batch is not reprocessed forever; after enabling the intent, new content-bearing commands should be delivered normally.

Daemon dies unexpectedly

Cause: Check the daemon log for errors.

cat .batty/daemon.log

Common causes: tmux session was killed externally, agent binary not found, permission errors on inbox directories.

Restart with:

batty stop                             # clean up
batty start                            # fresh start

If Batty finds a stale saved session during startup, it falls back to a cold respawn with context rebuild instead of requiring a manual pane restart. Healthy live panes do not need a proactive restart; startup recovery only touches panes that are already dead.

Multiple orphaned batty sessions

Cause: Previous sessions from test runs or crashes.

batty stop                             # kills primary + all orphaned batty-* sessions