Tudo que você precisa para rodar OpenCode no Termux (Android) como um serviço web acessível de qualquer lugar via Cloudflare Tunnel, com notificação push.
Público-alvo: Android 14+ (arm64, MIUI/Xiaomi), Termux F-Droid + proot-distro Ubuntu. Testado com Poco X7 Pro, Android 14, MIUI HyperOS.
opencode_termux/
├── .config/opencode/ ← GLOBAL: skills, agentes, config (symlink de ~/.config/opencode)
│ ├── opencode.jsonc ← config global do opencode
│ ├── skills/ ← 50 skills (24 globais + 14 do obra/superpowers + 10 upstream + 2 unificadas)
│ │ ├── code-reviewer/
│ │ ├── executing-plans/
│ │ ├── design-system/
│ │ ├── frontend-complete/
│ │ ├── fastapi-expert/
│ │ └── ...
│ └── agents/ ← subagentes (git-commit, code-review, task-planner, dev, task-build)
│ ├── git-commit.md
│ └── code-review.md
├── opencode.json ← config DO PROJETO (aponta para skills e agentes locais)
├── bin/
│ ├── opencode-web.sh ← manager fire-and-forget (Cloudflare)
│ ├── opencode-web-stop.sh ← stopper (Cloudflare)
│ ├── opencode-tailscale.sh ← manager fire-and-forget (Tailscale)
│ ├── opencode-tailscale-stop.sh ← stopper (Tailscale)
│ ├── termux-ssh.sh ← inicia sshd + notifica IP
│ └── termux-ssh-stop.sh ← para sshd
├── run-cloudflare-tunnel.sh ← script executado dentro do proot (Cloudflare)
├── run-opencode-tailscale.sh ← script executado dentro do proot (Tailscale)
├── shell/aliases.sh ← aliases para bash
├── scripts/setup.sh ← configuração inicial em qualquer device
├── docs/ ← documentação de referência
│ ├── AGENTS_TEMPLATE.md ← template de AGENTS.md para projetos
│ ├── MULTI_AGENT_ORCHESTRATION.md ← orquestração multi-agente
│ ├── SESSION_CONTEXT_20260618.md ← contexto da sessão de criação
│ ├── decisions/ ← ADRs (decisões arquiteturais)
│ ├── proot-distro/
│ │ └── README.md ← docs completas do proot-distro
│ ├── termux/
│ │ ├── filesystem-layout.md ← paths, $PREFIX, $TMPDIR
│ │ ├── termux-notification.md ← API de notificações
│ │ └── ssh-sftp-access.md ← referência SSH/SFTP
│ ├── tailscale/
│ │ └── README.md ← docs completas do Tailscale
│ └── cloudflare/
│ ├── quick-tunnel.md ← Quick Tunnel / TryCloudflare
│ ├── downloads.md ← cloudflared arm64 .deb
│ ├── config-file.md ← YAML config structure
│ └── run-parameters.md ← tunnel run flags
├── AI_HANDOVER.md ← handover entre sessões
├── .env ← configurações reais
└── .env.example ← template de configuração
📌 Como funciona:
~/.config/opencode/→ symlink →opencode_termux/.config/opencode/Skills e agentes vivem no repositório e são referenciados globalmente pelo symlink. Clone em qualquer device, rodebash scripts/setup.sh, e tudo funciona.📖 Documentação completa: Para detalhes sobre orquestração de agentes, veja
docs/MULTI_AGENT_ORCHESTRATION.md.
- Use o Termux da F-Droid, não o da Play Store (a versão Play é abandonada e quebra).
- O ambiente Ubuntu via proot é obrigatório — o OpenCode CLI exige glibc, e o Termux nativo usa bionic.
pkgnão funciona como root dentro do proot. Você instalará pacotes manualmente viadpkg -icom.debbaixados.termux-notificationnão funciona em MIUI/Xiaomi (o app Termux:API não pode ser instalado). Este projeto usa ntfy.sh para notificações push, que funciona em qualquer Android.- O Cloudflare Tunnel é efêmero (Quick Tunnel). A URL muda a cada execução.
- O Ctrl+C do
opencode servetem um bug conhecido (#21505) que impede o processo de terminar. Este projeto contorna isso com uma arquitetura Fire-and-Forget — o manager inicia e sai, deixando o serviço em background. Useopencode_web_stoppara parar.
Instale o Termux pela F-Droid.
Ao abrir pela primeira vez, atualize os pacotes:
pkg upgrade -y
pkg install proot-distro curl -yproot-distro install ubuntu
proot-distro login ubuntuDentro do proot (usuário root), teste a rede:
curl -s https://ifconfig.meapt update && apt install nodejs npm -y
node -v
npm -vnpm install -g opencode-linux-arm64 --force
ln -sf /data/data/com.termux/files/usr/lib/node_modules/opencode-linux-arm64/bin/opencode /data/data/com.termux/files/usr/bin/opencode
hash -r
opencode --versionPor que
--force? O npm detecta o OS como "android" e bloqueia a instalação.--forcecontorna isso. Por que o symlink? O npm global no proot não adiciona o binário ao PATH. O symlink garante queopencodeseja encontrado.
Após instalar o OpenCode CLI (step 4), execute pela primeira vez:
opencodePor que é lento?
O OpenCode usa SQLite como banco de dados local. Na primeira execução:
O banco é criado em: ~/.local/share/opencode/opencode.db
Se o diretório não existir, o OpenCode cria automaticamente.
O OpenCode usa Drizzle ORM para gerenciar o schema do banco. Na primeira vez, ele executa migrations que criam tabelas como project, session, message, tool, participant, worktree, além de índices e journal de migrations.
O OpenCode baixa e inicializa oh-my-opencode (content checker) e verifica atualizações de plugins.
Lê ~/.config/opencode/opencode.json e opencode.json do diretório atual.
Quanto tempo leva?
| Ambiente | Tempo estimado |
|---|---|
| Desktop (Intel/AMD) | 5-15 segundos |
| Termux (ARM64) | 30-90 segundos |
| Termux (ARM64, 1ª vez) | 2-5 minutos |
O que você verá no terminal:
$ opencode
Loading configuration...
Performing one time database migration...
Database migration complete
Initializing plugins...
Loading models...
Ready.
Dicas importantes:
-
Wake lock — Execute antes para evitar que Android suspenda:
termux-wake-lock
-
Não interrompa — NÃO feche o terminal nem pressione Ctrl+C durante a migração. Isso pode corromper o banco.
-
Se travar — Se não houver progresso por mais de 2 minutos:
pkill -f opencode rm ~/.local/share/opencode/opencode.db opencode -
Primeira vez vs subsequentes:
- 1ª vez: 30-90s (migration + plugins)
- 2ª vez: 2-5s (banco já existe)
- Após update: 5-15s (nova migration se necessário)
Problemas comuns:
| Problema | Causa | Solução |
|---|---|---|
| "Database is locked" | Outro processo usando o banco | pkill -f opencode e tente novamente |
| "Migration failed" | Banco corrompido | Delete opencode.db e reexecute |
| Timeout na inicialização | Plugin não baixa | Verifique conexão com internet |
curl -LO https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64.deb
dpkg -i cloudflared-linux-arm64.deb
cloudflared versionexit # sai do prootDe volta ao Termux nativo:
git clone <url-do-repositorio> opencode_termux
cd opencode_termuxbash scripts/setup.shO que setup.sh faz:
- Faz backup de
~/.config/opencode/existente (se não for symlink) - Cria symlink:
~/.config/opencode/→opencode_termux/.config/opencode/ - Instala dependências npm do
.config/opencode/ - Instrui sobre aliases
Isso torna skills e agentes disponíveis globalmente para todos os projetos.
Adicione ao ~/.bashrc do Termux nativo (não dentro do proot):
echo 'source /root/Projetos/opencode_termux/shell/aliases.sh' >> ~/.bashrc
source ~/.bashrccp .env.example .env
# edite NTFY_TOPIC, PROJECT_DIR se necessárioopencode_webO que acontece:
- O script manager adquire wake lock (impede o Android de dormir)
- Inicia
proot-distro login ubuntu --shared-tmprodandorun-cloudflare-tunnel.sh - Dentro do proot:
opencode web→cloudflared tunnel→ ntfy.sh push - A URL pública aparece no terminal e chega como notificação no Android
- O manager sai — o serviço fica rodando em background (PID salvo)
Para parar:
opencode_web_stopPara ver o status (manual):
cat $PREFIX/tmp/opencode_web.pid # PID
cat $PREFIX/tmp/opencode_url.txt # URL ativaAcesse os arquivos do Termux via SSH/SFTP usando o Termius ou qualquer cliente SSH.
pkg install openssh -ypasswdtermux_sshO que acontece:
- Verifica se
opensshestá instalado - Inicia
sshdna porta 8022 - Detecta o IP do dispositivo
- Envia notificação push com o comando SSH formatado
- No Termius, cole o comando:
ssh root@<IP> -p 8022
termux_ssh_stop- Abra o Termius → New Host
- Preencha:
- Hostname:
<IP do dispositivo> - Port:
8022 - Username:
root - Password: (a senha que você definiu com
passwd)
- Hostname:
- Salve e conecte
No Termius, após conectar via SSH:
- Clique no ícone SFTP na barra lateral
- Navegue pelos diretórios do Termux
Ou use um cliente SFTP separado (FileZilla, WinSCP) com as mesmas credenciais.
| Caminho | Descrição |
|---|---|
$HOME (~) |
Diretório home do Termux |
$PREFIX/tmp |
Temp (limpo ao reiniciar) |
/sdcard |
Armazenamento interno do Android |
/storage/emulated/0 |
Armazenamento compartilhado |
⚠️ Limitação:$PREFIX/tmpé apagado ao reiniciar o Termux. Para arquivos persistentes, use~/storageapós rodartermux-setup-storage.
~/.config/opencode/ ──symlink──► opencode_termux/.config/opencode/
│
skills/ (50 skills)
agents/ (git-commit.md, code-review.md, task-planner.md, dev.md, task-build.md)
opencode.jsonc
Todos os projetos enxergam skills e agentes via ~/.config/opencode/
Termux (nativo) proot (Ubuntu)
────────────────────────────────────────────────────
opencode-web.sh ──proot──► run-cloudflare-tunnel.sh
(fire-and-forget) ├── opencode web (porta 4096)
├── cloudflared tunnel
└── curl ntfy.sh (notificação)
│
notify_file (/tmp/opencode_url.txt)
│
┌─────┘
▼
ntfy push (notificação remota)
termux-notification (local, best-effort)
| Passo | Quem | O que faz |
|---|---|---|
| 1 | opencode-web.sh |
Adquire wake lock, inicia proot com --shared-tmp |
| 2 | proot + run-cloudflare-tunnel.sh |
Sobe opencode web em 127.0.0.1:4096 |
| 3 | proot | Sobe cloudflared tunnel --url http://127.0.0.1:4096 |
| 4 | proot | Extrai URL do log do cloudflared, escreve em /tmp/opencode_url.txt |
| 5 | proot | Envia notificação ntfy.sh com a URL |
| 6 | opencode-web.sh |
Lê o notify file (via --shared-tmp), mostra a URL no terminal, tenta termux-notification (best-effort) |
| 7 | opencode-web.sh |
Sai — serviço continua em background |
O opencode serve (e o opencode web) têm um bug conhecido onde Ctrl+C não termina o processo (#21505), e o processo deixa órfãos (#20899). Com Fire-and-Forget:
- O manager não aguarda o proot — usa
nohup+disown+ PID file - O stop é feito por um script dedicado (
opencode-web-stop.sh) que mata o proot graceful → force e limpa processos órfãos/zumbis por padrão - Sem traps, sem raw mode, sem travamentos de terminal
50 skills em .config/opencode/skills/ (24 globais + 14 do obra/superpowers + 10 upstream + 2 unificadas), além de customize-opencode (built-in do opencode, sem diretório).
| Agente | Modo | Responsabilidade |
|---|---|---|
task-build |
primary | Orquestra pipelines completas |
task-planner |
subagent | Planeja tasks antes da implementação |
dev |
subagent | Implementa código |
code-review |
subagent | Revisa código |
git-commit |
subagent | Cria commits semânticos |
Prompts dos 5 agentes reforçados em 19–21/08/2026 (
58fc4ea,609d579,68e2b11,825294a,5a1bf2b) — detalhes emdocs/MULTI_AGENT_ORCHESTRATION.md.Nota:
customize-opencodeé built-in do opencode (sem diretório em skills/)Skills obrigatórias:
executing-plans,systematic-debugging,verification-before-completion,plan-reviewer— carregadas automaticamente pelo agenttask-build.Regra: Code review é obrigatório antes de cada commit (individual + consolidado).
Subagentes: git-commit, code-review, task-planner, dev, task-build (prompts em .config/opencode/agents/).
Lista completa: opencode.json permission.skill e docs/SESSION_CONTEXT_20260618.md.
Manager fire-and-forget. Inicia, notifica e sai.
Variáveis (via .env ou env var):
| Variável | Default | Descrição |
|---|---|---|
OPENCODE_PORT |
4096 |
Porta local do OpenCode Web |
OPENCODE_HOSTNAME |
127.0.0.1 |
Hostname do opencode web (usar 127.0.0.1 dentro do proot — 0.0.0.0 crasha com getifaddrs) |
NTFY_TOPIC |
opencode-tunnel |
Tópico ntfy.sh para notificação |
PROJECT_DIR |
diretório do script | Onde está run-cloudflare-tunnel.sh |
NOTIFY_FILE |
$PREFIX/tmp/opencode_url.txt |
Arquivo de handoff da URL |
PID_FILE |
$PREFIX/tmp/opencode_web.pid |
Arquivo do PID |
LOG_FILE |
$PREFIX/tmp/opencode_web.log |
Log da execução no proot |
Para o serviço e limpa processos órfãos/zumbis.
- Carrega
.envvia$SCRIPT_DIRcom defaults (OPENCODE_PORT=4096,OPENCODE_HOSTNAME=127.0.0.1) — usa as mesmas variáveis dobin/opencode-web.sh(vide tabela acima). - Mata o proot graceful → force: SIGTERM, espera 3×1s checando se virou zumbi, depois SIGKILL se ainda vivo.
- Limpeza de órfãos — roda sempre (mesmo sem PID file):
run-cloudflare-tunnel.sh+ processo na porta do OpenCode +cloudflared tunnel(match por padrão com a porta). - Nunca usa
pkill -f "opencode web"— risco de matar a sessão TUI. - Verificação final: zumbis → log INFO (serão reaped pelo init), vivos → log WARN.
- Cleanup: remove PID file, notify file, log file; executa
stty saneetermux-wake-unlock.
Executado dentro do proot. Sobe opencode web + cloudflared tunnel + ntfy.sh push.
Define os aliases opencode_web, opencode_web_stop, opencode_tailscale, opencode_tailscale_stop, termux_ssh, termux_ssh_stop e limpar_opencode.
Inicia o serviço SSH do Termux para acesso remoto.
Variáveis (via .env ou env var):
| Variável | Default | Descrição |
|---|---|---|
NTFY_TOPIC |
opencode-tunnel |
Tópico ntfy.sh para notificação |
SSH_PORT |
8022 |
Porta do sshd |
SSHD_PID_FILE |
$PREFIX/tmp/termux_sshd.pid |
Arquivo do PID |
Para o serviço sshd: kill graceful → kill -9 → cleanup.
O OpenCode suporta NVIDIA NIM como provedor de inferência com tier gratuito (sem billing por token, ~40 requests/minuto).
-
Obtenha uma API key em build.nvidia.com (conta gratuita)
-
No OpenCode, use o comando
/connect:/connect nvidia -
Ou configure manualmente em
opencode.jsondo seu projeto:{ "$schema": "https://opencode.ai/config.json", "provider": { "nvidia": { "options": { "baseURL": "https://integrate.api.nvidia.com/v1" } } } } -
Defina a variável de ambiente (dentro do proot):
export NVIDIA_API_KEY="nvapi-xxx..."
| Modelo | Descrição |
|---|---|
meta/llama-3.1-70b-instruct |
Geral, bom custo-benefício |
nvidia/nemotron-70b-instruct |
Instruções complexas |
deepseek/deepseek-v4-flash |
Rápido, respostas curtas |
Para auto-sincronizar modelos disponíveis:
opencode plugin nim-sync -gNota: O tier gratuito tem limite de ~40 requests/minuto. Para uso intenso, considere um plano pago em build.nvidia.com.
| Pergunta | Resposta |
|---|---|
| O opencode não abre o navegador sozinho? | Sim, o CLI tenta abrir o navegador. No Termux isso falha silenciosamente. Use a URL do tunnel. |
| Como saber a URL atual? | No momento da inicialização ela aparece no terminal e chega por ntfy.sh. Depois, cat $PREFIX/tmp/opencode_url.txt. |
O que é --shared-tmp? |
Faz o /tmp do proot compartilhar o mesmo diretório do Termux nativo ($PREFIX/tmp), permitindo que o manager leia o notify file. |
termux-wake-lock falha? |
Instale termux-api (F-Droid) ou ignore — o wake lock não é estritamente necessário. |
| O tunnel caiu e não sobe de novo? | opencode_web_stop primeiro, depois opencode_web novamente (o stop agora limpa órfãos/zumbis por padrão). |
opencode web vs opencode serve? |
Ambos funcionam. web é a interface web (recomendado). serve expõe via SSE. |
| Como mudar a porta? | Edite .env: OPENCODE_PORT=8080. |
| Posso rodar sem cloudflared? | Sim, mas o acesso será apenas local (http://127.0.0.1:4096). Edite run-cloudflare-tunnel.sh e remova o cloudflared. |
| Preciso de API key da Anthropic? | Não necessariamente — use NVIDIA NIM (gratuito), OpenAI, ou outros provedores via /connect. Veja seção NVIDIA NIM. |
| Como usar NVIDIA NIM (gratuito)? | Obtenha API key em build.nvidia.com, use /connect nvidia no OpenCode ou configure provider.nvidia em opencode.json. |
| Posso usar outros provedores além da Anthropic? | Sim — OpenCode suporta OpenAI, Google Gemini, NVIDIA NIM, e outros via /connect. Configure o provider em opencode.json. |
| Como mudar de modelo? | No OpenCode Web, use o seletor de modelo na UI. Ou edite opencode.json → campo model. |
| Como acessar os arquivos do Termux via SSH? | Instale openssh, configure senha com passwd, rode termux_ssh. Conecte com Termius na porta 8022. |
| O SSH funciona com SFTP? | Sim — use o Termius ou qualquer cliente SFTP com as mesmas credenciais (IP, porta 8022, root, senha). |
| Preciso de IP fixo? | Não — o script detecta o IP automaticamente e envia via notificação push. |