Files
Emanuel Almeida 6b3a6f2698 feat: refactor 30+ skills to Anthropic progressive disclosure pattern
- All SKILL.md files now <500 lines (avg reduction 69%)
- Detailed content extracted to references/ subdirectories
- Frontmatter standardised: only name + description (Anthropic standard)
- New skills: brand-guidelines, spec-coauthor, report-templates, skill-creator
- Design skills: anti-slop guidelines, premium-proposals reference
- Removed non-standard frontmatter fields (triggers, version, author, category)

Plugins affected: infraestrutura, marketing, dev-tools, crm-ops, gestao,
core-tools, negocio, perfex-dev, wordpress, design-media

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 15:05:03 +00:00

18 KiB

name, description
name description
docx Criacao, edicao e analise de documentos Word (.docx). Usar quando o utilizador mencionar "Word", ".docx", ou pedir documentos profissionais com formatacao (indices, cabecalhos, numeracao de paginas, letterheads). Inclui extracao de conteudo, insercao/substituicao de imagens, find-and-replace, tracked changes, comentarios, e conversao de conteudo para Word. Aplica-se a relatorios, memorandos, cartas, templates e propostas em formato .docx. NAO usar para PDFs, folhas de calculo, Google Docs, ou tarefas de codigo nao relacionadas.

Criacao, edicao e analise de documentos DOCX

Visao geral

Um ficheiro .docx e um arquivo ZIP contendo ficheiros XML.

Referencia rapida

Tarefa Abordagem
Ler/analisar conteudo pandoc ou descompactar para XML bruto
Criar novo documento Usar docx-js - ver seccao Criar Novos Documentos
Editar documento existente Descompactar -> editar XML -> recompactar - ver seccao Editar Documentos Existentes

Converter .doc para .docx

Ficheiros legacy .doc devem ser convertidos antes de editar:

python scripts/office/soffice.py --headless --convert-to docx document.doc

Ler conteudo

# Extracao de texto com tracked changes
pandoc --track-changes=all document.docx -o output.md

# Acesso ao XML bruto
python scripts/office/unpack.py document.docx unpacked/

Converter para imagens

python scripts/office/soffice.py --headless --convert-to pdf document.docx
pdftoppm -jpeg -r 150 document.pdf page

Aceitar tracked changes

Para produzir um documento limpo com todas as alteracoes aceites (requer LibreOffice):

python scripts/accept_changes.py input.docx output.docx

Criar novos documentos

Gerar ficheiros .docx com JavaScript, depois validar. Instalacao: npm install -g docx

Setup

const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell, ImageRun,
        Header, Footer, AlignmentType, PageOrientation, LevelFormat, ExternalHyperlink,
        TableOfContents, HeadingLevel, BorderStyle, WidthType, ShadingType,
        VerticalAlign, PageNumber, PageBreak } = require('docx');

const doc = new Document({ sections: [{ children: [/* conteudo */] }] });
Packer.toBuffer(doc).then(buffer => fs.writeFileSync("doc.docx", buffer));

Validacao

Apos criar o ficheiro, validar. Se a validacao falhar, descompactar, corrigir o XML e recompactar.

python scripts/office/validate.py doc.docx

Tamanho da pagina

// CRITICO: docx-js assume A4 por defeito
// Definir sempre o tamanho da pagina explicitamente para resultados consistentes
// Para documentos PT/EU, A4 e o padrao correcto
sections: [{
  properties: {
    page: {
      size: {
        width: 11906,   // A4: 210mm em DXA
        height: 16838    // A4: 297mm em DXA
      },
      margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 } // 1 polegada de margens
    }
  },
  children: [/* conteudo */]
}]

Tamanhos de pagina comuns (unidades DXA, 1440 DXA = 1 polegada):

Papel Largura Altura Largura conteudo (margens 1")
A4 (padrao PT/EU) 11.906 16.838 9.026
US Letter 12.240 15.840 9.360

Orientacao paisagem: docx-js troca largura/altura internamente, por isso passar dimensoes retrato e deixar a biblioteca tratar:

size: {
  width: 11906,   // Passar lado CURTO como width
  height: 16838,  // Passar lado LONGO como height
  orientation: PageOrientation.LANDSCAPE  // docx-js troca no XML
},
// Largura de conteudo = 16838 - margem esquerda - margem direita (usa o lado longo)

Estilos (Override Built-in Headings)

Usar Arial como fonte por defeito (suporte universal). Manter titulos a preto para legibilidade.

const doc = new Document({
  styles: {
    default: { document: { run: { font: "Arial", size: 24 } } }, // 12pt por defeito
    paragraphStyles: [
      // IMPORTANTE: Usar IDs exactos para override dos estilos built-in
      { id: "Heading1", name: "Heading 1", basedOn: "Normal", next: "Normal", quickFormat: true,
        run: { size: 32, bold: true, font: "Arial" },
        paragraph: { spacing: { before: 240, after: 240 }, outlineLevel: 0 } }, // outlineLevel necessario para TOC
      { id: "Heading2", name: "Heading 2", basedOn: "Normal", next: "Normal", quickFormat: true,
        run: { size: 28, bold: true, font: "Arial" },
        paragraph: { spacing: { before: 180, after: 180 }, outlineLevel: 1 } },
    ]
  },
  sections: [{
    children: [
      new Paragraph({ heading: HeadingLevel.HEADING_1, children: [new TextRun("Titulo")] }),
    ]
  }]
});

Listas (NUNCA usar bullets unicode)

// ERRADO - nunca inserir caracteres de bullet manualmente
new Paragraph({ children: [new TextRun("* Item")] })      // MAU
new Paragraph({ children: [new TextRun("\u2022 Item")] })  // MAU

// CORRECTO - usar config numbering com LevelFormat.BULLET
const doc = new Document({
  numbering: {
    config: [
      { reference: "bullets",
        levels: [{ level: 0, format: LevelFormat.BULLET, text: "\u2022", alignment: AlignmentType.LEFT,
          style: { paragraph: { indent: { left: 720, hanging: 360 } } } }] },
      { reference: "numbers",
        levels: [{ level: 0, format: LevelFormat.DECIMAL, text: "%1.", alignment: AlignmentType.LEFT,
          style: { paragraph: { indent: { left: 720, hanging: 360 } } } }] },
    ]
  },
  sections: [{
    children: [
      new Paragraph({ numbering: { reference: "bullets", level: 0 },
        children: [new TextRun("Item com bullet")] }),
      new Paragraph({ numbering: { reference: "numbers", level: 0 },
        children: [new TextRun("Item numerado")] }),
    ]
  }]
});

// ATENCAO: Cada reference cria numeracao INDEPENDENTE
// Mesma reference = continua (1,2,3 depois 4,5,6)
// Reference diferente = reinicia (1,2,3 depois 1,2,3)

Tabelas

CRITICO: Tabelas precisam de larguras duplas - definir tanto columnWidths na tabela COMO width em cada celula. Sem ambos, tabelas renderizam incorrectamente em algumas plataformas.

// CRITICO: Definir sempre largura da tabela para renderizacao consistente
// CRITICO: Usar ShadingType.CLEAR (nao SOLID) para evitar fundos pretos
const border = { style: BorderStyle.SINGLE, size: 1, color: "CCCCCC" };
const borders = { top: border, bottom: border, left: border, right: border };

new Table({
  width: { size: 9026, type: WidthType.DXA }, // Sempre usar DXA (percentagens quebram no Google Docs)
  columnWidths: [4513, 4513], // Deve somar a largura da tabela (DXA: 1440 = 1 polegada)
  rows: [
    new TableRow({
      children: [
        new TableCell({
          borders,
          width: { size: 4513, type: WidthType.DXA }, // Tambem definir em cada celula
          shading: { fill: "D5E8F0", type: ShadingType.CLEAR }, // CLEAR e nao SOLID
          margins: { top: 80, bottom: 80, left: 120, right: 120 }, // Padding da celula (interno, nao adicionado a largura)
          children: [new Paragraph({ children: [new TextRun("Celula")] })]
        })
      ]
    })
  ]
})

Calculo de largura da tabela:

Usar sempre WidthType.DXAWidthType.PERCENTAGE quebra no Google Docs.

// Largura da tabela = soma de columnWidths = largura do conteudo
// A4 com margens de 1": 11906 - 2880 = 9026 DXA
width: { size: 9026, type: WidthType.DXA },
columnWidths: [7000, 2026]  // Deve somar a largura da tabela

Regras de largura:

  • Usar sempre WidthType.DXA — nunca WidthType.PERCENTAGE (incompativel com Google Docs)
  • Largura da tabela deve igualar a soma de columnWidths
  • width da celula deve corresponder ao respectivo columnWidth
  • margins da celula sao padding interno - reduzem a area de conteudo, nao adicionam a largura
  • Para tabelas full-width: usar largura de conteudo (largura pagina menos margens esquerda e direita)

Imagens

// CRITICO: parametro type e OBRIGATORIO
new Paragraph({
  children: [new ImageRun({
    type: "png", // Obrigatorio: png, jpg, jpeg, gif, bmp, svg
    data: fs.readFileSync("image.png"),
    transformation: { width: 200, height: 150 },
    altText: { title: "Titulo", description: "Desc", name: "Nome" } // Os tres sao obrigatorios
  })]
})

Quebras de pagina

// CRITICO: PageBreak deve estar dentro de um Paragraph
new Paragraph({ children: [new PageBreak()] })

// Ou usar pageBreakBefore
new Paragraph({ pageBreakBefore: true, children: [new TextRun("Nova pagina")] })

Indice (Table of Contents)

// CRITICO: Headings devem usar HeadingLevel APENAS - sem estilos custom
new TableOfContents("Indice", { hyperlink: true, headingStyleRange: "1-3" })

Cabecalhos/Rodapes

sections: [{
  properties: {
    page: { margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 } } // 1440 = 1 polegada
  },
  headers: {
    default: new Header({ children: [new Paragraph({ children: [new TextRun("Cabecalho")] })] })
  },
  footers: {
    default: new Footer({ children: [new Paragraph({
      children: [new TextRun("Pagina "), new TextRun({ children: [PageNumber.CURRENT] })]
    })] })
  },
  children: [/* conteudo */]
}]

Regras criticas para docx-js

  • Definir tamanho de pagina explicitamente - docx-js assume A4; para documentos PT/EU, A4 (11906 x 16838 DXA) e o padrao correcto
  • Paisagem: passar dimensoes retrato - docx-js troca largura/altura internamente; passar lado curto como width, lado longo como height, e definir orientation: PageOrientation.LANDSCAPE
  • Nunca usar \n - usar elementos Paragraph separados
  • Nunca usar bullets unicode - usar LevelFormat.BULLET com config numbering
  • PageBreak deve estar em Paragraph - standalone cria XML invalido
  • ImageRun requer type - especificar sempre png/jpg/etc
  • Definir sempre width da tabela com DXA - nunca usar WidthType.PERCENTAGE (quebra no Google Docs)
  • Tabelas precisam de larguras duplas - array columnWidths E width da celula, ambos devem corresponder
  • Largura tabela = soma de columnWidths - para DXA, garantir que somam exactamente
  • Adicionar sempre margins nas celulas - usar margins: { top: 80, bottom: 80, left: 120, right: 120 } para padding legivel
  • Usar ShadingType.CLEAR - nunca SOLID para shading de tabelas
  • TOC requer HeadingLevel apenas - sem estilos custom nos paragrafos de heading
  • Override built-in styles - usar IDs exactos: "Heading1", "Heading2", etc.
  • Incluir outlineLevel - necessario para TOC (0 para H1, 1 para H2, etc.)

Editar documentos existentes

Seguir os 3 passos por ordem.

Passo 1: Descompactar

python scripts/office/unpack.py document.docx unpacked/

Extrai XML, pretty-prints, funde runs adjacentes e converte smart quotes para entidades XML (&#x201C; etc.) para sobreviverem a edicao. Usar --merge-runs false para saltar a fusao de runs.

Passo 2: Editar XML

Editar ficheiros em unpacked/word/. Ver Referencia XML abaixo para padroes.

Usar "Claude" como autor para tracked changes e comentarios, salvo se o utilizador pedir outro nome.

Usar a ferramenta Edit directamente para substituicao de strings. Nao escrever scripts Python. Scripts introduzem complexidade desnecessaria. A ferramenta Edit mostra exactamente o que esta a ser substituido.

CRITICO: Usar smart quotes para novo conteudo. Ao adicionar texto com apostrofos ou aspas, usar entidades XML para produzir smart quotes:

<!-- Usar estas entidades para tipografia profissional -->
<w:t>Here&#x2019;s a quote: &#x201C;Hello&#x201D;</w:t>
Entidade Caractere
&#x2018; ' (aspas simples esquerda)
&#x2019; ' (aspas simples direita / apostrofo)
&#x201C; " (aspas duplas esquerda)
&#x201D; " (aspas duplas direita)

Adicionar comentarios: Usar comment.py para tratar boilerplate em multiplos ficheiros XML (texto deve ser XML pre-escaped):

python scripts/comment.py unpacked/ 0 "Texto do comentario com &amp; e &#x2019;"
python scripts/comment.py unpacked/ 1 "Texto de resposta" --parent 0  # resposta ao comentario 0
python scripts/comment.py unpacked/ 0 "Texto" --author "Autor Custom"  # nome de autor custom

Depois adicionar marcadores ao document.xml (ver Comentarios na Referencia XML).

Passo 3: Recompactar

python scripts/office/pack.py unpacked/ output.docx --original document.docx

Valida com auto-reparacao, condensa XML e cria DOCX. Usar --validate false para saltar.

Auto-reparacao corrige:

  • durableId >= 0x7FFFFFFF (regenera ID valido)
  • xml:space="preserve" em falta em <w:t> com whitespace

Auto-reparacao nao corrige:

  • XML malformado, nesting de elementos invalido, relacoes em falta, violacoes de schema

Erros comuns

  • Substituir elementos <w:r> inteiros: Ao adicionar tracked changes, substituir o bloco <w:r>...</w:r> completo com <w:del>...<w:ins>... como siblings. Nao injectar tags de tracked change dentro de um run.
  • Preservar formatacao <w:rPr>: Copiar o bloco <w:rPr> do run original para os runs de tracked change para manter bold, tamanho de fonte, etc.

Referencia XML

Conformidade com schema

  • Ordem de elementos em <w:pPr>: <w:pStyle>, <w:numPr>, <w:spacing>, <w:ind>, <w:jc>, <w:rPr> por ultimo
  • Whitespace: Adicionar xml:space="preserve" a <w:t> com espacos no inicio/fim
  • RSIDs: Devem ser hex de 8 digitos (ex: 00AB1234)

Tracked Changes

Insercao:

<w:ins w:id="1" w:author="Claude" w:date="2025-01-01T00:00:00Z">
  <w:r><w:t>texto inserido</w:t></w:r>
</w:ins>

Eliminacao:

<w:del w:id="2" w:author="Claude" w:date="2025-01-01T00:00:00Z">
  <w:r><w:delText>texto eliminado</w:delText></w:r>
</w:del>

Dentro de <w:del>: Usar <w:delText> em vez de <w:t>, e <w:delInstrText> em vez de <w:instrText>.

Edicoes minimas - marcar apenas o que muda:

<!-- Alterar "30 dias" para "60 dias" -->
<w:r><w:t>O prazo e de </w:t></w:r>
<w:del w:id="1" w:author="Claude" w:date="...">
  <w:r><w:delText>30</w:delText></w:r>
</w:del>
<w:ins w:id="2" w:author="Claude" w:date="...">
  <w:r><w:t>60</w:t></w:r>
</w:ins>
<w:r><w:t> dias.</w:t></w:r>

Eliminar paragrafos/itens de lista inteiros - ao remover TODO o conteudo de um paragrafo, marcar tambem o paragraph mark como eliminado para fundir com o proximo paragrafo. Adicionar <w:del/> dentro de <w:pPr><w:rPr>:

<w:p>
  <w:pPr>
    <w:numPr>...</w:numPr>  <!-- numeracao de lista se presente -->
    <w:rPr>
      <w:del w:id="1" w:author="Claude" w:date="2025-01-01T00:00:00Z"/>
    </w:rPr>
  </w:pPr>
  <w:del w:id="2" w:author="Claude" w:date="2025-01-01T00:00:00Z">
    <w:r><w:delText>Conteudo inteiro do paragrafo a ser eliminado...</w:delText></w:r>
  </w:del>
</w:p>

Sem o <w:del/> em <w:pPr><w:rPr>, aceitar alteracoes deixa um paragrafo/item de lista vazio.

Rejeitar insercao de outro autor - aninhar eliminacao dentro da insercao:

<w:ins w:author="Maria" w:id="5">
  <w:del w:author="Claude" w:id="10">
    <w:r><w:delText>texto inserido por ela</w:delText></w:r>
  </w:del>
</w:ins>

Restaurar eliminacao de outro autor - adicionar insercao depois (nao modificar a eliminacao):

<w:del w:author="Maria" w:id="5">
  <w:r><w:delText>texto eliminado</w:delText></w:r>
</w:del>
<w:ins w:author="Claude" w:id="10">
  <w:r><w:t>texto eliminado</w:t></w:r>
</w:ins>

Comentarios

Apos executar comment.py (ver Passo 2), adicionar marcadores ao document.xml. Para respostas, usar flag --parent e aninhar marcadores dentro dos do pai.

CRITICO: <w:commentRangeStart> e <w:commentRangeEnd> sao siblings de <w:r>, nunca dentro de <w:r>.

<!-- Marcadores de comentario sao filhos directos de w:p, nunca dentro de w:r -->
<w:commentRangeStart w:id="0"/>
<w:del w:id="1" w:author="Claude" w:date="2025-01-01T00:00:00Z">
  <w:r><w:delText>eliminado</w:delText></w:r>
</w:del>
<w:r><w:t> mais texto</w:t></w:r>
<w:commentRangeEnd w:id="0"/>
<w:r><w:rPr><w:rStyle w:val="CommentReference"/></w:rPr><w:commentReference w:id="0"/></w:r>

<!-- Comentario 0 com resposta 1 aninhada dentro -->
<w:commentRangeStart w:id="0"/>
  <w:commentRangeStart w:id="1"/>
  <w:r><w:t>texto</w:t></w:r>
  <w:commentRangeEnd w:id="1"/>
<w:commentRangeEnd w:id="0"/>
<w:r><w:rPr><w:rStyle w:val="CommentReference"/></w:rPr><w:commentReference w:id="0"/></w:r>
<w:r><w:rPr><w:rStyle w:val="CommentReference"/></w:rPr><w:commentReference w:id="1"/></w:r>

Imagens

  1. Adicionar ficheiro de imagem a word/media/
  2. Adicionar relacao a word/_rels/document.xml.rels:
<Relationship Id="rId5" Type=".../image" Target="media/image1.png"/>
  1. Adicionar content type a [Content_Types].xml:
<Default Extension="png" ContentType="image/png"/>
  1. Referenciar no document.xml:
<w:drawing>
  <wp:inline>
    <wp:extent cx="914400" cy="914400"/>  <!-- EMUs: 914400 = 1 polegada -->
    <a:graphic>
      <a:graphicData uri=".../picture">
        <pic:pic>
          <pic:blipFill><a:blip r:embed="rId5"/></pic:blipFill>
        </pic:pic>
      </a:graphicData>
    </a:graphic>
  </wp:inline>
</w:drawing>

Dependencias

  • pandoc: Extracao de texto
  • docx: npm install -g docx (novos documentos)
  • LibreOffice: Conversao PDF (auto-configurado para ambientes sandbox via scripts/office/soffice.py)
  • Poppler: pdftoppm para imagens

Integracao Descomplicar

MCPs disponiveis

MCP Uso
mcp__filesystem__* Ler/escrever ficheiros .docx locais, listar directorios
mcp__google-workspace__* Upload para Google Drive, conversao para Google Docs
mcp__ssh-unified__* Operacoes em ficheiros .docx em servidores remotos

Workflow tipico

  1. Criar documento com docx-js conforme instrucoes acima
  2. Validar com scripts/office/validate.py
  3. Guardar via mcp__filesystem__write_file ou directamente no path do projecto
  4. Upload (opcional) via mcp__google-workspace__drive_upload_file para partilha com cliente

Convencoes Descomplicar

  • Formato de data em documentos: DD-MM-YYYY (ex: 06-03-2026)
  • Formato monetario: 1.234,56 EUR (separador milhar ponto, decimal virgula)
  • Fonte padrao: Arial 12pt
  • Tamanho pagina padrao: A4 (11906 x 16838 DXA)
  • Autor para tracked changes: "Claude" (salvo indicacao contraria)
  • Idioma do documento: PT-PT salvo indicacao contraria

Versao: 1.0.0 | Autor: Descomplicar®