✳ AI Skills
← arthurbonora

PUBLICAÇÃO DA COMUNIDADE

Limpeza de ambiente (sobras de agentes e testes)

Limpa o servidor das sobras deixadas por agentes de IA e testes: cópias de projeto, worktrees, node_modules, venvs e builds, caches, temporários, dumps soltos, containers, imagens e volumes órfãos e processos esquecidos. Descobre a stack, exige evidência de abandono (7 dias sem uso), usa quarentena de 2 dias e só remove com aprovação. Use quando pedirem para limpar o servidor ou a VPS, liberar disco, remover lixo ou sobras de testes dos agentes, ou quando o disco estiver cheio.

arthurbonora/limpeza-ambiente · MIT · v1.0.0

Instruções da skill

---
name: limpeza-ambiente
description: "Limpa o servidor das sobras deixadas por agentes de IA e testes: cópias de projeto, worktrees, node_modules, venvs e builds, caches, temporários, dumps soltos, containers, imagens e volumes órfãos e processos esquecidos. Descobre a stack, exige evidência de abandono (7 dias sem uso), usa quarentena de 2 dias e só remove com aprovação. Use quando pedirem para limpar o servidor ou a VPS, liberar disco, remover lixo ou sobras de testes dos agentes, ou quando o disco estiver cheio."
---

# Limpeza de ambiente (sobras de agentes e testes)

Você roda **dentro** do servidor (Claude Code, Codex ou outro agente no terminal), numa máquina que você não conhece. Agentes de IA criam cópias de projeto, worktrees, dependências, builds, dumps, containers e processos de teste e raramente limpam depois. Esta skill encontra essas sobras e as remove **com segurança**.

O difícil não é apagar: é **provar que algo é lixo**. Um diretório `projeto-copia` pode ser descartável ou pode ser o único lugar com trabalho não commitado. Por isso a regra de ouro é:

> **Na dúvida, fica.** Todo item precisa de evidência de abandono. Sem evidência, ele é 🔴 e só aparece no relatório.

Escopo: **arquivos, diretórios, containers, imagens, volumes, redes, build cache, processos e agendamentos**. Dados dentro de bancos de dados estão **fora do escopo**: nunca conecte em banco para apagar nada.

Escreva em português do Brasil, direto.

---

## Configuração

Procure `./.limpeza-ambiente/limpeza.config.json`. Se não existir, use os padrões abaixo e diga ao usuário que estão em uso (ele pode criar o arquivo a partir de `assets/limpeza.config.example.json`).

```json
{
  "dias_sem_uso": 7,
  "dias_quarentena": 2,
  "tamanho_minimo_mb": 10,
  "disco_critico_pct": 90,
  "raizes_varredura": ["/home", "/root", "/srv", "/opt", "/var/www", "/tmp", "/var/tmp"],
  "caminhos_extras": [],
  "caminhos_protegidos": []
}
```

- `dias_sem_uso`: idade mínima (sem modificação) para virar candidato.
- `dias_quarentena`: tempo mínimo em quarentena antes de poder ser purgado.
- `tamanho_minimo_mb`: itens menores não entram no relatório individualmente (somam numa linha "pequenos").
- `disco_critico_pct`: acima disso, ofereça compactar a quarentena.
- `raizes_varredura` + `caminhos_extras`: onde procurar. `caminhos_extras` serve para apontar onde os agentes daquele ambiente trabalham.
- `caminhos_protegidos`: nunca tocados, somados à lista embutida abaixo.

---

## Regras invioláveis

1. **Fases 0 a 4 são somente leitura.** Nada é movido, apagado, parado ou podado antes da Fase 5.
2. **Nada sai sem aprovação explícita**, por grupo ou por item. Uma aprovação não vale para outro grupo nem para a próxima execução.
3. **Nada é apagado direto, exceto 🟢.** Tudo 🟡 vai primeiro para a quarentena, com manifesto e comando de restauração.
4. **Lista de proteção absoluta** (nunca é candidato, mesmo parecendo abandonado):
   - sistema: `/`, `/bin`, `/boot`, `/dev`, `/etc`, `/lib*`, `/proc`, `/run`, `/sbin`, `/sys`, `/usr`, `/var/lib`, `/var/log`, `/var/spool`, `/var/mail`, `/snap`
   - diretórios internos do Docker/Podman (`/var/lib/docker`, `/var/lib/containers`): mexa só pelos comandos do próprio runtime, nunca com `rm`
   - qualquer caminho usado por algo vivo (Fase 0.3)
   - diretórios de backup (nome contendo `backup`, `bkp`, `snapshot` **fora** de uma cópia de projeto de agente) e qualquer coisa que o usuário chame de backup
   - os `caminhos_protegidos` da configuração
   - a própria pasta `./.limpeza-ambiente/` e a quarentena
5. **Nada com sinal de vida**: processo com `cwd` ou arquivo aberto dentro, porta escutando, serviço, container ou cron apontando para ele.
6. **Git com trabalho único nunca é candidato automático**: mudança não commitada, stash, commit não enviado a nenhum remote ou branch sem upstream. Vira 🔴 com aviso.
7. **Remoção segura**: nunca `rm -rf` com variável sem aspas, caminho vazio, `/` ou curinga solto. Use sempre a função de guarda da Fase 5.
8. **Sem `sudo` interativo**: use `sudo -n`; na falha, registre "não verificado (requer root)".
9. **Não siga links simbólicos** e **não atravesse sistemas de arquivos** (`find -P ... -xdev`). Não varra montagens de rede (NFS, SMB, sshfs, rclone).
10. **Não instale nada** para diagnosticar. Ferramenta ausente é "não verificado", nunca "está limpo".
11. **Redija segredos** ao citar arquivos ou variáveis (`.env`, tokens, senhas → `***`). Nunca imprima o conteúdo de um `.env`.

---

## Fase 0 — Descoberta (obrigatória, somente leitura)

### 0.1 Base e disco
```bash
cat /etc/os-release 2>/dev/null | head -3; uname -srm; id -un; uptime
df -hT -x tmpfs -x devtmpfs -x squashfs -x overlay 2>/dev/null
df -hi -x tmpfs -x devtmpfs 2>/dev/null           # inodes: muitos arquivos pequenos
findmnt -rno TARGET,FSTYPE,OPTIONS | grep -E 'nfs|cifs|smb|fuse|sshfs' || true   # excluir da varredura
findmnt -rno TARGET,OPTIONS / | grep -oE 'noatime|relatime|strictatime'        # atime é confiável?
for r in docker podman nerdctl; do command -v $r >/dev/null && echo "runtime=$r"; done
command -v git >/dev/null && echo "git=sim"
```

### 0.2 Estamos dentro de container?
```bash
grep -qaE 'docker|lxc|kubepods|containerd' /proc/1/cgroup 2>/dev/null && echo "em container"; ls /.dockerenv 2>/dev/null
```
Dentro de container, a limpeza fica restrita a ele. Diga isso ao usuário e recomende rodar também no host.

### 0.3 Mapa do que está vivo (a base de toda proteção)
Monte uma lista `vivos` de **caminhos** que não podem ser tocados:
```bash
# diretório de trabalho e executável de todos os processos
for p in /proc/[0-9]*; do readlink "$p/cwd" 2>/dev/null; readlink "$p/exe" 2>/dev/null; done | sort -u
# arquivos abertos (diretórios pais entram no mapa)
sudo -n lsof -nP +c0 -Fn 2>/dev/null | sed -n 's/^n//p' | grep '^/' | sort -u | head -5000
# portas escutando e processo dono
(ss -ltnup || netstat -ltnup) 2>/dev/null
# serviços supervisionados
systemctl list-units --type=service --state=running --no-legend --no-pager 2>/dev/null | awk '{print $1}' \
  | xargs -r -I{} systemctl show {} -p WorkingDirectory -p ExecStart --no-pager 2>/dev/null
pm2 jlist 2>/dev/null | python3 -c 'import json,sys;[print(a["pm2_env"].get("pm_cwd","")) for a in json.load(sys.stdin)]' 2>/dev/null
supervisorctl status 2>/dev/null
# docker compose e montagens de containers EM EXECUÇÃO
docker ps -q 2>/dev/null | xargs -r docker inspect --format \
  '{{index .Config.Labels "com.docker.compose.project.working_dir"}} {{range .Mounts}}{{.Source}} {{end}}' 2>/dev/null
# agendamentos
crontab -l 2>/dev/null; sudo -n ls /var/spool/cron/crontabs 2>/dev/null; ls /etc/cron.d 2>/dev/null
systemctl list-timers --all --no-legend --no-pager 2>/dev/null
```
Use `podman` no lugar de `docker` se for o runtime detectado. Um item é **vivo** se o seu caminho está no mapa ou é pai/filho de algo do mapa.

### 0.4 Onde os agentes trabalham
Procure, nas raízes configuradas, os sinais típicos de área de trabalho de agente:
- git worktrees (`.git` como **arquivo**, não diretório) e diretórios `worktrees/`
- muitos clones do mesmo remote (`git -C <dir> remote get-url origin` repetido)
- pastas de ferramentas de agente, quando existirem (`.claude`, `.codex`, `.cursor`, `.aider*`, `workspaces`, `sandbox`, `scratch`, `tmp-*`)
- os `caminhos_extras` da configuração

### 0.5 Perfil do ambiente
Antes de seguir, declare ao usuário em 5 a 8 linhas: SO, disco e inodes por montagem (e quais estão acima de `disco_critico_pct`), se `atime` é confiável, runtime de containers, quantos serviços/containers vivos foram mapeados, onde os agentes trabalham e o que **não** foi possível inspecionar (sem root, sem lsof, montagens excluídas).

---

## Fase 1 — Quarentena anterior

Leia o histórico em `./.limpeza-ambiente/` e procure lotes de quarentena (Fase 5.3) ainda existentes:
```bash
find / -xdev -maxdepth 1 -name '.quarentena-limpeza' 2>/dev/null
for m in $(findmnt -rno TARGET -t ext4,xfs,btrfs,zfs 2>/dev/null); do ls -d "$m/.quarentena-limpeza"/*/ 2>/dev/null; done
```
Para cada lote, leia `manifesto.json`. Lotes com idade **≥ `dias_quarentena`** são candidatos à **purga definitiva**; os mais novos apenas aparecem no relatório com a data em que poderão ser purgados. Se o usuário relatou falta de algo desde a última execução, ofereça restaurar antes de qualquer purga.

---

## Fase 2 — Caça às sobras (somente leitura)

### Medir idade corretamente
- **Não confie no `atime`** se o disco está em `noatime` ou `relatime`.
- Para diretório, a idade é a do **arquivo modificado mais recentemente dentro dele**, não a do próprio diretório. Para não varrer árvores enormes à toa, ignore as próprias dependências ao medir um projeto:
```bash
idade_dias() {  # $1 = diretório
  local t; t=$(find -P "$1" -xdev \( -name node_modules -o -name .venv -o -name venv -o -name __pycache__ \
       -o -name .next -o -name dist -o -name build -o -name target \) -prune -o -type f -printf '%T@\n' 2>/dev/null \
       | sort -n | tail -1)
  [ -z "$t" ] && t=$(stat -c %Y "$1")
  echo $(( ( $(date +%s) - ${t%.*} ) / 86400 ))
}
```
- Para repositório git, use também a data do último commit e do reflog (`git -C <dir> log -1 --format=%ct`, `git -C <dir> reflog -1 --format=%ct`); vale a **mais recente** entre arquivos, commit e reflog.
- Para container, use `State.FinishedAt`; para volume, `CreatedAt`.

### Base da varredura
Sempre com `-P -xdev`, podando a lista protegida e as montagens de rede:
```bash
PODA='\( -path /proc -o -path /sys -o -path /dev -o -path /run -o -path /var/lib -o -path /var/log -o -path /snap -o -path "*/.quarentena-limpeza" \) -prune'
```

### Categorias

| # | Categoria | Como encontrar | Classe padrão |
|---|---|---|---|
| A | **Cópias de projeto** | diretórios com nome de cópia/teste (`*-copy*`, `*-copia*`, `*-test*`, `*-teste*`, `*-tmp*`, `*-old*`, `*-bkp*`, `*_v[0-9]*`, sufixos de data ou hash) **que contenham um projeto** (`package.json`, `pyproject.toml`, `requirements.txt`, `go.mod`, `Cargo.toml`, `composer.json`, `pom.xml`, `.git`); clones repetidos do mesmo remote, mantendo o mais recente/ativo | 🟡 |
| B | **Worktrees órfãos** | `git -C <repo> worktree list --porcelain` e `git -C <repo> worktree prune --dry-run -v`; worktree cujo diretório sumiu ou cujo repo principal não existe | 🟡 (diretório) · 🟢 (`worktree prune` de registro sem diretório) |
| C | **Dependências e builds** de projetos inativos | `node_modules`, `.venv`, `venv`, `__pycache__`, `.pytest_cache`, `.mypy_cache`, `.ruff_cache`, `.next`, `.nuxt`, `.turbo`, `.parcel-cache`, `dist`, `build`, `target`, `coverage`, `.gradle` dentro de projeto com idade ≥ `dias_sem_uso` | 🟢 se o projeto tem manifesto de dependências/lockfile (regenerável); 🟡 se não tem |
| D | **Caches de ferramentas** | `~/.npm/_cacache`, `~/.cache/pip`, `~/.cache/yarn`, `pnpm store path`, `~/.cache/go-build`, `~/.cache/ms-playwright`, `~/.cache/puppeteer`, `~/.cargo/registry/cache` | 🟢 (avise que o próximo install fica mais lento); use o comando da ferramenta quando existir (`npm cache clean --force`, `pip cache purge`, `pnpm store prune`, `go clean -cache`) |
| E | **Temporários** | arquivos e diretórios em `/tmp` e `/var/tmp` com idade ≥ `dias_sem_uso`, que não sejam sockets, pipes, locks nem estejam abertos; respeite `systemd-tmpfiles` (não duplique o que ele já limpa) | 🟢 arquivos regulares · 🟡 diretórios de projeto |
| F | **Dumps e artefatos soltos** | fora de `/var/log` e da lista protegida: `*.sql`, `*.sql.gz`, `*.dump`, `*.bak`, `*.csv` grandes, `*.tar*`, `*.zip`, `*.log`, `*.har`, `screenshots/`, `playwright-report/`, `test-results/`, `*.heapsnapshot`, `core.*` | 🟡 (dumps podem conter dados pessoais: aponte isso) |
| G | **Containers e afins** | ver bloco abaixo | ver bloco |
| H | **Processos esquecidos** | ver bloco abaixo | 🟡 no máximo |
| I | **Agendamentos órfãos** | linhas de cron/timers apontando para caminhos que não existem mais | 🔴 só relatório (proponha comentar a linha, com backup) |
| J | **Branches git de experimento** | `git branch --merged` e branches locais antigas em repos de agente | 🔴 só relatório |

### G · Containers (Docker; adapte para Podman)
```bash
docker system df -v 2>/dev/null | head -60
# containers parados há mais de N dias
docker ps -a --filter status=exited --filter status=created --filter status=dead -q | xargs -r docker inspect \
  --format '{{.Name}} {{.State.FinishedAt}} {{.Config.Image}} compose={{index .Config.Labels "com.docker.compose.project"}}'
# imagens sem tag e imagens sem nenhum container (nem parado)
docker images -f dangling=true --format '{{.ID}} {{.Repository}}:{{.Tag}} {{.Size}} {{.CreatedSince}}'
docker images --format '{{.ID}} {{.Repository}}:{{.Tag}} {{.Size}} {{.CreatedSince}}'   # cruzar com docker ps -a
# volumes sem nenhum container
docker volume ls -f dangling=true -q | xargs -r docker volume inspect --format '{{.Name}} {{.CreatedAt}} {{.Labels}}'
docker network ls --filter type=custom --format '{{.Name}}'   # cruzar com containers conectados
docker builder du 2>/dev/null | tail -3
```
Classificação:
- 🟢 imagens **dangling**, build cache com mais de `dias_sem_uso` (`docker builder prune --filter until=<N*24>h`), redes custom sem container.
- 🟡 containers parados há ≥ `dias_sem_uso` que **não** pertencem a um compose cujo diretório existe e está vivo; imagens com tag sem nenhum container e criadas há ≥ `dias_sem_uso` com nome de teste/dev.
- 🟡 volumes **anônimos** (nome de 64 hex) sem container e com idade ≥ `dias_sem_uso`: vão para a quarentena como `tar` (Fase 5.3), porque volume é dado.
- 🔴 volumes **nomeados** sem container, imagens com tag de produção, qualquer coisa ligada a compose de serviço vivo. Volume nomeado pode ser o banco de uma stack desligada temporariamente.

### H · Processos esquecidos
```bash
ps -eo pid,ppid,user,etimes,rss,comm,args --sort=-rss | head -60
cat /proc/<pid>/cgroup     # dentro de "*.service" = supervisionado; "session-*.scope" ou "user@" = iniciado à mão
```
Candidatos: servidores de desenvolvimento e ferramentas de teste (`vite`, `next dev`, `nodemon`, `webpack serve`, `ts-node-dev`, `uvicorn --reload`, `flask run`, `rails s`, `jupyter`, `http.server`, `chromium --headless`, `playwright`, túneis temporários), rodando há mais de 24 h, **fora** de serviço supervisionado e com `cwd` em diretório candidato ou temporário. Mostre RAM e porta de cada um. Processo **nunca** vai para quarentena; a ação é `SIGTERM`, item por item.

### Pertencimento
Para cada candidato registre também o **dono** (`stat -c %U`) e, quando der para saber, qual agente/usuário o criou (dono do arquivo, nome da pasta, label do container). Isso alimenta o histórico de "quem mais suja".

---

## Fase 3 — Classificação com evidência

Cada candidato só entra no relatório com: **caminho/ID, categoria, tamanho, idade, dono, evidência de abandono e comando de ação**. Some tamanhos com `du -sxb` (diretórios) ou o tamanho informado pelo runtime (containers).

Sinais de abandono (quanto mais, maior a confiança):
- idade ≥ `dias_sem_uso`, medida como na Fase 2
- nome com padrão de cópia, teste ou temporário
- **ausente** do mapa de vivos (Fase 0.3)
- duplicata de um projeto ativo (mesmo remote ou mesmo manifesto, com um irmão mais recente)
- conteúdo regenerável (dependências, builds, caches)
- criado em área de trabalho de agente (Fase 0.4)

Classes:
- 🟢 **Seguro**: regenerável e sem sinal de vida. Remoção direta após aprovação; libera espaço **na hora**.
- 🟡 **Provável**: abandonado com evidência, mas não regenerável. Vai para a **quarentena**; libera espaço só na purga.
- 🔴 **Duvidoso**: qualquer item que caia em uma regra de proteção ou tenha só um sinal fraco. Fica no relatório e **não** entra em nenhuma ação.

Rebaixe para 🔴, sempre:
- git com mudança não commitada, stash, commit sem remote ou branch sem upstream (`git status --porcelain`, `git stash list`, `git log --branches --not --remotes --oneline`)
- item que é pai/filho de algo vivo
- volume Docker nomeado
- item com idade abaixo de `dias_sem_uso` em qualquer uma das medidas
- falha ao medir idade ou tamanho (sem permissão): é "não verificado", não lixo

Sinalize (sem mudar a classe) itens que contêm `.env`, chaves (`*.pem`, `id_*`) ou dumps de dados: o usuário precisa saber que há segredo ou dado pessoal ali antes de purgar.

---

## Fase 4 — Relatório + baseline

Escreva em `./.limpeza-ambiente/` (ou em um diretório gravável que o usuário indicar).

`relatorio-YYYY-MM-DD-HHMM.md`:
```markdown
# Limpeza de ambiente — <host> — <data>

## Resumo
<disco e inodes por montagem; espaço recuperável AGORA (🟢) e EM <dias_quarentena> DIAS (🟡); RAM recuperável (processos); risco principal>

## Ambiente
<perfil da Fase 0.5>

## Quarentena anterior
| Lote | Criado em | Tamanho | Itens | Pode purgar? |

## 🟢 Seguro — <total>
| Categoria | Item | Tamanho | Idade | Evidência | Ação |

## 🟡 Provável (quarentena) — <total>
| Categoria | Item | Tamanho | Idade | Dono | Evidência | Avisos |

## 🔴 Duvidoso (sem ação) — <total>
| Categoria | Item | Tamanho | Motivo de ficar |

## Processos esquecidos
| PID | Comando | RAM | Porta | Rodando há | cwd |

## Comparação com a execução anterior
<crescimento de disco entre execuções; quem/qual área mais gerou sobras>

## Não verificado
<sem root, sem lsof, montagens excluídas, ferramentas ausentes>
```

`baseline.json`: **acumule um array de execuções; nunca sobrescreva o histórico.**
```json
{"data":"","host":"","config":{},
 "disco":{"<montagem>":{"uso_pct":0,"livre_gb":0,"inodes_pct":0}},
 "recuperavel":{"verde_mb":0,"amarelo_mb":0,"vermelho_mb":0,"ram_mb":0},
 "por_categoria_mb":{"A":0,"B":0,"C":0,"D":0,"E":0,"F":0,"G":0},
 "por_dono_mb":{},
 "quarentena":{"lotes":[],"purgados":[]},
 "aplicado":{"removido_mb":0,"quarentenado_mb":0,"processos_encerrados":0},
 "recusados":[],"nao_verificado":[]}
```
Leia o baseline **antes** da Fase 2. Não reproponha item que o usuário recusou antes (a menos que o tamanho tenha crescido muito), e mostre a tendência: disco crescendo X GB por semana diz mais que um valor isolado.

No chat, entregue só: o resumo, os totais por classe e categoria e as perguntas de aprovação. O detalhe fica no arquivo.

---

## Fase 5 — Aplicação (só com aprovação)

Pergunte, nesta ordem e separadamente: (1) purga dos lotes antigos da quarentena, (2) 🟢 por categoria, (3) 🟡 por categoria ou item, (4) processos item por item. Itens 🔴 nunca entram.

### 5.1 Guarda de remoção (use sempre)
```bash
seguro_para_remover() {  # $1 = caminho absoluto
  local p; p=$(realpath -e -- "$1" 2>/dev/null) || { echo "não existe: $1"; return 1; }
  case "$p" in ""|/|/bin*|/boot*|/dev*|/etc*|/lib*|/proc*|/run*|/sbin*|/sys*|/usr*|/var/lib*|/var/log*|/var/spool*|/snap*|"$HOME")
    echo "PROTEGIDO: $p"; return 1;; esac
  [ "$(echo "$p" | tr -cd '/' | wc -c)" -lt 2 ] && { echo "raso demais: $p"; return 1; }
  # rechecar vida no momento da ação (a Fase 0 pode ter ficado velha)
  for pr in /proc/[0-9]*; do c=$(readlink "$pr/cwd" 2>/dev/null); case "$c" in "$p"|"$p"/*) echo "EM USO (cwd): $p"; return 1;; esac; done
  sudo -n lsof +D "$p" >/dev/null 2>&1 && { echo "EM USO (arquivo aberto): $p"; return 1; }
  return 0
}
```
Também confira contra `caminhos_protegidos` da configuração. Se a guarda recusar, o item vira 🔴 e é reportado; nunca contorne.

### 5.2 🟢 Seguro
Para cada item aprovado: `seguro_para_remover` → ação → registro. Prefira o comando da ferramenta quando existir:
```bash
git -C <repo> worktree prune -v
docker image prune -f                                   # só dangling
docker builder prune -f --filter until=$((DIAS*24))h
docker network rm <rede>                                # redes custom sem container, uma a uma
npm cache clean --force; pip cache purge; pnpm store prune; go clean -cache
rm -rf -- "<projeto>/node_modules"                      # só depois da guarda
```

### 5.3 🟡 Quarentena
A quarentena fica **no mesmo sistema de arquivos** do item (o `mv` é instantâneo e não gasta espaço copiando):
```bash
MNT=$(df --output=target -- "<item>" | tail -1)
LOTE="$MNT/.quarentena-limpeza/$(date +%F-%H%M)"
mkdir -p "$LOTE" && chmod 700 "$MNT/.quarentena-limpeza"
[ "$(stat -c %d "<item>")" = "$(stat -c %d "$LOTE")" ] || echo "outro sistema de arquivos: pule ou peça decisão"
seguro_para_remover "<item>" && mv -n -- "<item>" "$LOTE/<id-unico>"
```
Para cada lote, grave `manifesto.json` com: `id`, caminho original, dono, permissões, tamanho, categoria, evidência, data, e o **comando de restauração** (`mv -n -- "$LOTE/<id>" "<caminho original>"`). Copie o manifesto também para `./.limpeza-ambiente/`.

Casos especiais:
- **Container parado**: `docker export <id> | gzip > "$LOTE/<nome>.tar.gz"` (se couber) e registre `docker inspect` no manifesto; depois `docker rm <id>`. Se não couber, peça decisão.
- **Volume anônimo**: `docker run --rm -v <vol>:/v:ro -v "$LOTE":/q <imagem-já-presente-com-tar> tar czf /q/<vol>.tgz -C /v .` e depois `docker volume rm <vol>`. Sem imagem local com `tar`, não baixe nada: deixe 🔴.
- **Imagem com tag**: `docker save <img> | gzip > "$LOTE/<img>.tar.gz"` e então `docker rmi <img>`.

Lembre o usuário: **o 🟡 só libera espaço na purga**, daqui a `dias_quarentena` dias, na próxima execução.

**Disco crítico** (uso ≥ `disco_critico_pct`): ofereça compactar o lote (`tar -I 'zstd -T0' -cf lote.tar.zst` ou `gzip`), conferir o arquivo (`tar -tf`) e só então remover o diretório não compactado. Recupera boa parte do espaço já agora e mantém a restauração possível.

### 5.4 Purga da quarentena
Só lotes com idade ≥ `dias_quarentena` **e** aprovação explícita nesta execução:
```bash
seguro_para_remover "$LOTE" && rm -rf -- "$LOTE"
```
Registre em `quarentena.purgados` do baseline.

### 5.5 Processos
Um por vez: mostre PID, comando, cwd, RAM e porta → `kill -TERM <pid>` → espere 10 s → confirme que saiu. Se não sair, pergunte antes de `kill -KILL`. Nunca encerre processo de serviço supervisionado, de outro usuário sem confirmação, nem o da sua própria sessão.

### 5.6 Medir e registrar
Repita `df -h`, `df -hi`, `docker system df` e `free -m`; registre antes/depois em `aplicado` no baseline. Se algo quebrou (serviço reclamando, usuário sentindo falta), **restaure imediatamente** pelo manifesto e reporte.

Encerre com: espaço liberado agora, espaço que será liberado na próxima purga (e a partir de quando), RAM liberada, o que ficou como 🔴 e por quê, e como restaurar.

---

## Atalho: "quanto dá para liberar?"

Faça as Fases 0, 2 e 3 e responda no chat com os totais 🟢/🟡/🔴 por categoria e os 5 maiores itens. Relatório em arquivo e aplicação só se o usuário pedir.

Requisitos

  • shell bash com GNU coreutils e findutils (find, du, stat, df)
  • git (opcional)
  • docker ou podman (opcional)
  • lsof (opcional, melhora a detecção de uso)
  • tar com gzip ou zstd (opcional, para compactar a quarentena)

Permissões declaradas

  • acesso ao terminal do servidor
  • leitura do sistema de arquivos
  • mover e remover arquivos e diretórios somente após aprovação
  • gerenciar containers, imagens, volumes e redes do Docker/Podman somente após aprovação
  • encerrar processos somente após aprovação
  • sudo não interativo opcional (sudo -n)

Avaliações

Carregando…

Carregando recomendações…

Versões

  • v1.0.0

    Primeira publicação: descoberta do ambiente, caça a sobras de agentes e testes em arquivos e containers, classificação com evidência (7 dias sem uso), quarentena de 2 dias com manifesto e restauração, remoção só com aprovação e baseline histórico.