Skip to content

Repository files navigation

MAP CLI

CI

A tool for spawning and managing multiple AI coding agents (Claude Code and OpenAI Codex) with a Docker-like architecture: thin CLI (map) + local daemon (mapd).

Run Claude Code and Codex agents in parallel

Map.demo.mp4

Sync gh projects / issues

map-gh-projects.mp4

Installation

Quick install (macOS and Linux):

curl -fsSL https://raw.githubusercontent.com/pmarsceill/mapcli/main/install.sh | bash

This installs both map and mapd to ~/.local/bin. Make sure this directory is in your PATH.

System Requirements

MAP requires the following tools to be installed and available in your PATH:

DependencyRequired ForVersion
gitWorktree isolation2.15+ (worktree support)
tmuxAgent session managementAny recent version
claudeClaude Code agentsLatest (optional if only using Codex)
codexOpenAI Codex agentsLatest (optional if only using Claude)

At least one of claude or codex must be installed depending on which agent type you want to use.

Installing Dependencies:

macOS (Homebrew)
brew install git tmux
# Claude CLI: https://docs.anthropic.com/en/docs/claude-code# Codex CLI: https://github.com/openai/codex
Ubuntu/Debian
sudo apt update && sudo apt install git tmux
# Claude CLI: https://docs.anthropic.com/en/docs/claude-code# Codex CLI: https://github.com/openai/codex
Fedora/RHEL
sudo dnf install git tmux
# Claude CLI: https://docs.anthropic.com/en/docs/claude-code# Codex CLI: https://github.com/openai/codex
Arch Linux
sudo pacman -S git tmux
# Claude CLI: https://docs.anthropic.com/en/docs/claude-code# Codex CLI: https://github.com/openai/codex

Manual installation:

Download the latest release from the releases page and extract the binaries to a directory in your PATH.

Build from source:

git clone https://github.com/pmarsceill/mapcli.git
cd mapcli
make build
# Binaries are in bin/

Overview

MAP (Multi-Agent Platform) provides infrastructure for spawning and coordinating multiple AI coding agents. It supports both Claude Code and OpenAI Codex agents. The architecture separates concerns:

  • map - Lightweight CLI for spawning agents and monitoring their status
  • mapd - Daemon process that manages agent lifecycles and worktrees

Quick Start

Build

make build

This creates two binaries in bin/:

  • map - CLI tool
  • mapd - Daemon

Run

  1. Start the daemon:

    map up
    # Or run in foreground for debugging:
    map up -f
  2. Spawn agents:

    # Spawn a Claude agent (default)
    map agent create
    # Spawn a Codex agent
    map agent create -a codex
    # Spawn with a prompt
    map agent create -p "Fix the bug in auth.go"# Spawn multiple Codex agents
    map agent create -n 3 -a codex
  3. Monitor agents:

    # List spawned agents
    map agent list
    # Watch agent output in real-time
    map agent watch
    # List worktrees
    map worktree ls
  4. Stop the daemon:

    map down

CLI Commands

Daemon Control

CommandDescription
map up [-f]Start the daemon (foreground with -f)
map down [-f]Stop the daemon (force immediate shutdown with -f)
map cleanClean up orphaned processes, tmux sessions, and socket files
map watchStream real-time events from the daemon
map config listList all configuration values
map config get <key>Get a configuration value
map config set <key> <value>Set a configuration value

Agent Management

CommandDescription
map agentsList spawned agents (alias: map ag)
map agent create [-a type]Spawn agents (claude or codex)
map agent listList spawned agents (alias: ls, same as map agents)
map agent kill <id>Terminate a spawned agent
map agent kill --allTerminate all spawned agents
map agent watch [id]Attach to agent's tmux session
map agent watch -aWatch all agents in tiled tmux view
map agent respawn <id>Restart agent in dead tmux pane
map agent merge <id>Merge agent's worktree changes into current branch
map agent merge <id> -kMerge agent's changes and kill the agent

Worktree Management

CommandDescription
map worktree lsList agent worktrees (alias: list)
map worktree cleanupRemove orphaned worktrees
map worktree cleanup --agent <id>Remove worktree for a specific agent
map worktree cleanup --allRemove all agent worktrees

Task Management

CommandDescription
map task submit <description>Submit a new task for agent processing (alias: map tasks, map t)
map task ls [-n limit]List all tasks with status (default limit: 20)
map task show <id>Show detailed task information
map task cancel <id>Cancel a pending or in-progress task
map task sync gh-project <name>Sync tasks from a GitHub Project
map task my-taskShow the current task for this agent (by working directory)
map task input-needed <id> <question>Request user input via GitHub issue

Spawning Agents

MAP can spawn Claude Code or OpenAI Codex agents as subprocesses, with each agent optionally isolated in its own git worktree for safe concurrent work.

Agent Types

MAP supports two agent types via the -a flag:

TypeCLIDescription
claudeClaude CodeAnthropic's Claude Code CLI (default)
codexOpenAI CodexOpenAI's Codex CLI

Agent Naming

Each agent receives a unique, human-friendly name based on its type:

  • Claude agents: French-style names (e.g., jacques-bernard, marie-claire, philippe-martin)
  • Codex agents: California-style names (e.g., chad-stevenson, bryce-anderson, tyler-johnson)

Names are automatically generated and guaranteed unique within a session.

Basic Usage

# Spawn a Claude agent (default)
map agent create
# Spawn a Codex agent
map agent create -a codex
# Spawn 3 Claude agents in parallel
map agent create -n 3
# Spawn 3 Codex agents in parallel
map agent create -n 3 -a codex
# Spawn with a specific prompt
map agent create -p "Fix the bug in auth.go"
map agent create -a codex -p "Implement the login feature"# Spawn without worktree isolation (agents share working directory)
map agent create --no-worktree

Agent Management

# List all spawned agents
map agent list
# Kill a specific agent
map agent kill claude-abc123
# Force kill (SIGKILL instead of SIGTERM)
map agent kill claude-abc123 --force
# Kill all agents
map agent kill --all
# Force kill all agents
map agent kill --all --force

Worktree Management

When agents are spawned with worktree isolation (the default), each agent gets its own git worktree in ~/.mapd/worktrees/. This allows multiple agents to work on the same repository concurrently without conflicts.

Permission Bypass: By default, agents are started with permission-bypassing flags to enable autonomous operation:

  • Claude: --dangerously-skip-permissions
  • Codex: --dangerously-bypass-approvals-and-sandbox

This is safe when using worktrees because each worktree is an isolated copy created by MAP. Use --require-permissions to restore standard permission prompts if needed.

# List all worktrees
map worktree ls
# Clean up orphaned worktrees (agents that have exited)
map worktree cleanup
# Clean up a specific agent's worktree
./bin/map worktree cleanup --agent <agent-id># Clean up all worktrees
map worktree cleanup --all

Merging Agent Changes

When an agent completes work in its worktree, use map agent merge to bring those changes back to your main branch:

# Merge an agent's changes into your current branch
map agent merge <agent-id># Merge with a custom commit message for uncommitted changes
map agent merge <agent-id> -m "Agent completed feature X"# Squash all agent commits into one
map agent merge <agent-id> --squash
# Stage changes without committing (for manual review)
map agent merge <agent-id> --no-commit
# Merge and kill the agent afterward
map agent merge <agent-id> -k
map agent merge <agent-id> --kill

The merge command will:

  1. Commit any uncommitted changes in the agent's worktree (if any)
  2. Merge those changes into your current branch
  3. Optionally kill the agent after a successful merge (with -k flag)

Task Management

MAP includes a task routing system for distributing work to agents.

Task Lifecycle

Tasks follow this lifecycle: PENDING → OFFERED → ACCEPTED → IN_PROGRESS → COMPLETED/FAILED/CANCELLED

Tasks can also enter WAITING_INPUT status when an agent needs user input. Once the user responds, the task returns to IN_PROGRESS.

Task Commands

# Submit a new task
map task submit "Fix the authentication bug in login.go"# Submit with scope paths (limits where agent can work)
map task submit "Update API handlers" -p ./internal/api -p ./internal/handlers
# List all tasks
map task ls
# Show task details
map task show <task-id># Cancel a task
map task cancel <task-id>

Syncing from GitHub Projects

MAP can import tasks directly from GitHub Projects using the gh CLI:

# Sync tasks from a GitHub Project (uses @me as default owner)
map task sync gh-project "My Project"# Sync from an organization's project
map task sync gh-project "Sprint Board" --owner myorg
# Preview what would be synced without making changes
map task sync gh-project "My Project" --dry-run
# Sync from a different source column
map task sync gh-project "My Project" --status-column "Ready"# Move items to a different target column after sync
map task sync gh-project "My Project" --target-column "Assigned"# Limit the number of items to sync
map task sync gh-project "My Project" --limit 5

How it works:

  1. Finds the GitHub Project by name
  2. Fetches issues from the source status column (default: "Todo")
  3. Creates a MAP task for each issue
  4. Moves the issue to the target status column (default: "In Progress")

Requirements:

  • The gh CLI must be installed and authenticated (gh auth login)
  • The project must have a "Status" field with single-select options
FlagDefaultDescription
--status-columnTodoSource status column to sync from
--target-columnIn ProgressTarget status column after task creation
--owner@meGitHub project owner (user, org, or @me)
--limit10Maximum number of items to sync
--dry-runfalsePreview without creating tasks or updating GitHub

Bidirectional GitHub Issue Sync

When tasks are synced from GitHub Projects, MAP tracks the originating issue and enables bidirectional communication:

Automatic Input Detection:

  • The daemon monitors agent tmux sessions for signs that the agent is waiting for user input
  • When detected (agent idle + question pattern in output), the question is automatically posted to the GitHub issue
  • Users can respond directly on the GitHub issue
  • Responses are automatically delivered back to the agent's session

How it works:

  1. Sync issues with map task sync gh-project "Project" - GitHub metadata is stored with each task
  2. Agent works on the task and asks a question (detected automatically)
  3. Question is posted to the GitHub issue with prefix **My agent needs more input:**
  4. User responds on GitHub
  5. Response is delivered to the agent's tmux session
  6. Agent continues working

Manual input requests:

Agents can also explicitly request input:

# From within an agent session, request user input
map task input-needed <task-id>"What error format should I use?"

Agent introspection:

# Find the current task for this working directory
map task my-task

Event Streaming

Watch real-time events from the daemon:

# Stream all daemon events
map watch

Events include task lifecycle changes (created, offered, accepted, started, completed, failed, cancelled, waiting_input, input_received) and agent status updates.

Agent Create Options

FlagDefaultDescription
-a, --agent-typeclaudeAgent type: claude or codex
-n, --count1Number of agents to spawn
--branchcurrent branchGit branch for worktrees
--worktreetrueUse worktree isolation
--no-worktreefalseSkip worktree isolation
--nameagent typeAgent name prefix
-p, --promptnoneInitial prompt to send to the agent
--require-permissionsfalseRequire permission prompts (by default, permissions are skipped for autonomous operation)

Architecture

┌─────────┐ ┌─────────────────────────────────────┐
│ CLI │◄───────►│ Daemon (mapd) │
│ (map) │ gRPC │ ┌───────────┐ ┌────────────────┐ │
└─────────┘ │ │ Worktree │ │ Process │ │
│ │ Manager │ │ Manager │ │
│ └─────┬─────┘ └───────┬────────┘ │
└────────┼────────────────┼───────────┘
│ │
┌──────────────┘ └──────────────┐
▼ ▼
┌───────────────────┐ ┌─────────────────────┐
│ ~/.mapd/worktrees │ │ claude/codex CLI │
│ claude-abc123/ │◄─────── cwd ─────────│ (tmux session) │
│ codex-def456/ │ └─────────────────────┘
└───────────────────┘

Project Structure

mapcli/
├── cmd/
│ ├── map/ # CLI binary
│ └── mapd/ # Daemon binary
├── internal/
│ ├── daemon/ # Daemon core (server, store, process management)
│ ├── cli/ # CLI commands
│ └── client/ # Shared gRPC client
├── proto/map/v1/ # Protocol definitions & generated code
├── go.mod
├── Makefile
└── README.md

Configuration

MAP supports persistent configuration via a YAML file at ~/.mapd/config.yaml. Configuration values can be set via:

  1. CLI flags (highest priority)
  2. Environment variables (with MAP_ prefix)
  3. Config file (~/.mapd/config.yaml)
  4. Defaults (lowest priority)

Config Commands

CommandDescription
map config listList all configuration values (alias: ls)
map config get <key>Get a specific configuration value
map config set <key> <value>Set and persist a configuration value

Configuration File

# ~/.mapd/config.yamlsocket: /tmp/mapd.sockdata-dir: ~/.mapdagent:
default-type: claude # claude or codexdefault-count: 1# number of agents to spawndefault-branch: ""# git branch for worktreesuse-worktree: true # worktree isolationskip-permissions: true # skip permission prompts

Configuration Options

KeyDefaultDescription
socket/tmp/mapd.sockUnix socket path for daemon communication
data-dir~/.mapdData directory for SQLite and worktrees
agent.default-typeclaudeDefault agent type (claude or codex)
agent.default-count1Default number of agents to spawn
agent.default-branch""Default git branch for worktrees (empty = current branch)
agent.use-worktreetrueUse worktree isolation by default
agent.skip-permissionstrueSkip permission prompts by default

Environment Variables

All configuration options can be set via environment variables with the MAP_ prefix. Nested keys use underscores:

export MAP_SOCKET=/custom/path.sock
export MAP_AGENT_DEFAULT_TYPE=codex
export MAP_AGENT_DEFAULT_COUNT=3

Global CLI Flags

FlagDefaultDescription
-s, --socket/tmp/mapd.sockUnix socket path for daemon communication
--config~/.mapd/config.yamlPath to config file

Daemon (map up)

FlagDefaultDescription
-f, --foregroundfalseRun daemon in foreground
-d, --data-dir~/.mapdData directory for SQLite

Development

Prerequisites

  • Go 1.24+
  • All system requirements above
  • (Optional) protoc with go plugins for regenerating proto files

Regenerate Proto Files

If you have protoc installed:

make install-tools # Install protoc-gen-go plugins
make generate # Regenerate proto files

Makefile Targets

TargetDescription
make buildBuild all binaries
make allGenerate protos and build
make generateRegenerate protobuf files
make testRun all tests
make cleanRemove build artifacts
make rebuildClean, generate, and build
make depsDownload and tidy dependencies
make install-toolsInstall protoc plugins
make devHot reload development mode (requires Air)

Linting

Run the linter before submitting changes:

golangci-lint run --timeout=5m

Common issues to watch for:

  • errcheck: Always handle error return values (use _ = fn() for intentionally ignored errors)
  • staticcheck: Avoid deprecated functions
  • For deferred close operations: defer func() { _ = x.Close() }()

Development Helpers

Run components directly without building:

make run-daemon # Run daemon in current shell
make run-cli ARGS="agent list"# Run CLI with arguments

Dependencies

Core runtime dependencies:

PackagePurpose
github.com/spf13/cobraCLI framework
github.com/spf13/viperConfiguration management
google.golang.org/grpcgRPC communication
google.golang.org/protobufProtocol buffer support
modernc.org/sqliteSQLite database (pure Go)
github.com/google/uuidUUID generation

About

A CLI to run many coding agents locally in parallel

Topics

Resources

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages