Pi Agent no Docker

Saudações.

Hoje vou ensinar como enlatei o Agente Pi (Pi Coding Agent) em um container Docker.

Pré-requisitos:

  • Servidor, VPS ou VM com Linux;
  • Docker;

1 – Sobre o Pi Agent

O Pi é um agente de IA para programação executado no terminal, especializado e refinado para planejar (plan) e construir (build) softwares.

Ele é uma “versão gratuita e aberta do Claude Code” e faz parte do monorepo earendil-works/pi, que inclui:

  • CLI @earendil-works/pi-coding-agent;
  • runtime @earendil-works/pi-agent-core;
  • API unificada de modelos @earendil-works/pi-ai.

Você conversa com o modelo no terminal, e por padrão ele recebe ferramentas para ler arquivos, criar arquivos, editar arquivos e executar comandos bash.

A documentação alerta que o Pi roda no diretório atual e pode modificar arquivos ali, o ideal é usar Git, snapshots ou algum fluxo de rollback caso você não goste do que aconteceu e queira voltar a como era antes.

Para funcionar ele precisa:

  • Acesso a Internet durante a execução;
  • Chave de API para algum modelo de IA.

Links:

2 – Pi Agent no Docker

Usar o PI no Docker é muito simples, vou mostrar como montei a imagem para fins didáticos e no capítulo posterior você poderá usar minha imagem pronta montada com os mesmos scripts apresentados aqui.

2.1 – Caminhos e volumes

Esses caminhos precisam ser mapeados e direcionado para volumes, assim o container separa:

  • Programas: Os binários e bibliotecas de códigos;
  • Dados: Configurações e informações acumuladas pelo OC;
  • Cache: Arquivos gerados para acelerar a execução;
  • Workspace: Projeto de código onde serão produzidos os artefatos do agente, como códigos, documentações, etc;

2.2 – Arquivos para construir a imagem

Dockerfile da imagem:

Dockerfile – ./docker/Dockerfile
# syntax=docker/dockerfile:1.7

# Base Alpine com node 26, minimalista
FROM node:26-alpine3.22

ARG APP_UID=1001
ARG APP_GID=1001

# Versao do Pi, usar latest ou versao especifica
# docker buikd ...  --build-arg AGENTPI_VERSION=1.x.y
ARG PI_VERSION=latest

ENV \
    LANG=C.UTF-8 \
    LC_ALL=C.UTF-8

# Pacotes base:
RUN set -eux; \
    apk update; \
    apk upgrade; \
    apk add \
      bash \
      ca-certificates \
      curl \
      wget \
      git \
      openssh-client \
      tar \
      xz\
      zstd \
      unzip \
      tzdata \
      openssl \
      less \
      procps \
      jq \
      sqlite; \
    true

# Instala Pi via npm
RUN set -eux; \
    npm install -g "@earendil-works/pi-coding-agent@${PI_VERSION}"; \
    pi --version

# Usuario não-root para rodar o agente.
# A HOME real sera em /data, para persistir tudo que for config/
RUN \
    set -eux; \
    mkdir -p /data/home/pi; \
    addgroup -g "${APP_GID}" pi; \
    adduser -u "${APP_UID}" -G pi -D \
        -h /data/home/pi -s /bin/bash pi; \
    \
    chown pi:pi /data -R; \
    mkdir -p /data /cache /workspace /cache/tmp /root/.local; \
    chmod 0755 /data /cache /workspace; \
    chmod 1777 /cache/tmp

# (PAREI AQUI)

# Redireciona /tmp para /cache/tmp, inclusive para arquivos .so temporarios.
RUN \
    rm -rf /tmp; \
    ln -s /cache/tmp /tmp

# Criar links de /root para os volumes caso rode processos como root dentro do container
RUN \
    rm -rf /root/.config /root/.cache /root/.npm /root/.local/share; \
    ln -s /data/config /root/.config; \
    ln -s /data/share /root/.local/share; \
    ln -s /cache/xdg /root/.cache; \
    ln -s /cache/npm /root/.npm

# Variaveis centrais:
# - XDG_CONFIG_HOME e XDG_DATA_HOME em /data
# - XDG_CACHE_HOME, npm cache e TMPDIR em /cache
# - NO_PROXY para evitar que o servidor local do TUI passe por proxy
ENV HOME=/data/home/pi \
    XDG_CONFIG_HOME=/data/config \
    XDG_DATA_HOME=/data/share \
    XDG_CACHE_HOME=/cache/xdg \
    PI_CONFIG_DIR=/data/config/pi \
    NPM_CONFIG_CACHE=/cache/npm \
    NPM_CONFIG_PREFIX=/data/npm-global \
    TMPDIR=/cache/tmp \
    NO_PROXY=localhost,127.0.0.1 \
    PATH=/data/npm-global/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# Diretorio padrao inicial
WORKDIR /workspace

# Volumes anonimos (default, requer mapeamento no run)
VOLUME ["/data", "/cache", "/workspace"]

2.3 – Construção da imagem

Para construir a imagem, crie uma pasta para esse projeto “pi-builder” crie os dois arquivos (conteúdo acima) nos seguintes caminhos:

  • Dockerfile: ./docker/Dockerfile
  • Entrypoint: ./rootfs/opt/entrypoint.sh

Execute o build para construir a imagem:

Bash
# Constuir imagem pi:latest
    docker build . -f docker/Dockerfile --no-cache -t pi:latest;

Caso queira construir uma imagem versionada usando uma versão específica do Pi:

Bash
# Construir imagem de versao especifica do pi:
    PI_VERSION="1.x.y";
    docker build . \
        -f docker/Dockerfile\
        -t pi:$PI_VERSION \
        --build-arg PI_VERSION=$PI_VERSION;

3 – Rodando Pi no Docker

Vamos rodar o OC no Docker, criando o container pi-dev.

2.1 – Rede Docker

Criando a rede para containers (network_public):

Bash
# Rede de containers
docker network create network_public \
    -d bridge \
    -o com.docker.network.bridge.name=br-net-public \
    -o com.docker.network.driver.mtu=1500 \
    -o com.docker.network.bridge.gateway_mode_ipv4=nat-unprotected \
    --subnet 10.249.0.0/16 \
    --gateway 10.249.255.254;

2.2 – Volume

A pasta /workspace dentro do container deve ser mapeada na pasta onde estará seu projeto de software no HOST.

Ela é a pasta onde os programas são executados por padrão (workdir do container).

Nesse exemplo vou armazenar tudo em /storage/pi-dev para você testar e aprender, e depois você personaliza.

Bash
# Nome do container
    NAME="pi-dev";

# Diretorio do volume no HOST
    DATADIR=/storage/$NAME;

# Pastas de volumes montados na pasta principal do volume no host
    mkdir -p $DATADIR;
    # - Configs e DB de contexto
    mkdir -p $DATADIR/data;
    
    # - Cache do bibliotecas
    mkdir -p $DATADIR/cache;
    
    # - Pasta com projeto de software (caminho padrao inicial /workspace)
    mkdir -p $DATADIR/workspace;

2.3 – Container do OC

Comando para rodar no “docker run”:

Bash
# Variaveis
    NAME="pi-dev";

    # Para usar sua imagem local construida no cap. 2
    #IMAGE="pi:latest";
    # Para usar minha imagem pronta:
    IMAGE="tmsoftbrasil/pi:latest";

# Diretorio de dados persistentes:
    DATADIR=/storage/$NAME;

    # Pastas de volumes montados
    # na pasta principal do volume no host
    mkdir -p $DATADIR;
    mkdir -p $DATADIR/data;
    mkdir -p $DATADIR/cache;
    mkdir -p $DATADIR/workspace;

# Rodar container
    # Renovar/rodar
    docker rm -f $NAME 2>/dev/null

    #    --read-only
    docker run \
        -d --restart=always \
        --name $NAME --hostname $LOCAL.intranet.br \
        \
        --tmpfs /run:rw,noexec,nosuid,size=16m \
        --tmpfs /tmp:rw,noexec,nosuid,size=16m \
        \
        --cpus=2 \
        --memory 2g --memory-swap 2g --memory-reservation 256m \
        \
        --network network_public \
        \
        -v $DATADIR/data:/data \
        -v $DATADIR/cache:/cache \
        -v $DATADIR/workspace:/workspace \
        \
        \
        $IMAGE \
            tail -f /dev/null;

2.4 – Stack para Compose

Caso prefira no modelo de Stack para docker compose:

YAML
name: pi-dev

services:
  pi-dev:
    image: tmsoftbrasil/pi:latest
    container_name: pi-dev
    hostname: pi-dev
    restart: always
    read_only: true
    command: tail -f /dev/null

    tmpfs:
      - /run:rw,noexec,nosuid,size=16m
      - /tmp:rw,noexec,nosuid,size=16m

    deploy:
      resources:
        limits:
          cpus: "2"
          memory: 2g
        reservations:
          memory: 256m

    mem_swappiness: 0
    memswap_limit: 2g

    networks:
      - network_public

    volumes:
      - /storage/pi-dev/data:/data
      - /storage/pi-dev/cache:/cache
      - /storage/pi-dev/workspace:/workspace

networks:
  network_public:
    external: true

3 – Primeiro acesso

Obtenha shell no container “pi-dev“:

Bash
# Obter shell no container:
docker exec -it pi-dev bash;

# Rodar Pi:
pi;

# Ou, rodar direto o pi dentro do container:
docker exec -it pi-dev pi;

3.1 – Tela inicial

Execute:

ComandoDescrição
/loginFazer login em plataforma oAuth ou informar chave de API
/modelEscolher o modelo LLM

Eu prefiro usar via API, usar o OpenRouter com o modelo DeepSeek-V4-PRO.

.

Agora é contigo. Use sua criatividade.

Terminamos por hoje!

Patrick Brandão, patrickbrandao@gmail.com

O segredo de avançar é começar.
O segredo de começar é dividir seus projetos
complexos e esmagadores em tarefas
pequenas e gerenciáveis,
e depois começar pela primeira.
Mark Twain