TL;DR
Converta um arquivo de agente de IA para 10 IDEs em 3 etapas: (1) Analise o frontmatter YAML com as funções bash `get_field()`, `get_body()` e `to_kebab()`, (2) Transforme para formatos específicos de ferramentas usando `convert.sh` (Claude Code `.md`, Cursor `.mdc`, Aider `CONVENTIONS.md`, Windsurf `.windsurfrules`), (3) Instale nos caminhos corretos com `install.sh`. Escreva uma vez, converta automaticamente, implante em todo lugar.
Um arquivo de agente. Dez IDEs. Aprenda como o projeto The Agency converte um único arquivo Markdown para funcionar com Claude Code, Cursor, Aider, Windsurf, GitHub Copilot e mais de 6 outras ferramentas.
Você escreve um agente de IA. Agora você quer ele disponível em:
- Claude Code (arquivos `.md` em `~/.claude/agents/`)
- Cursor (arquivos `.mdc` em `.cursor/rules/`)
- Aider (um único `CONVENTIONS.md` na raiz do projeto)
- Windsurf (um único arquivo `.windsurfrules`)
- GitHub Copilot (arquivos `.md` em `~/.github/agents/`)
- E mais de 5 outras ferramentas
Você escreve 10 versões? Não. Você escreve uma vez, converte automaticamente.
O projeto The Agency resolve isso com dois scripts bash:
- `convert.sh` — Transforma arquivos de agente em formatos específicos de ferramentas
- `install.sh` — Copia arquivos convertidos para os caminhos corretos
Neste tutorial, você fará engenharia reversa de ambos os scripts. Você aprenderá como analisar frontmatter YAML, extrair conteúdo do corpo e construir pipelines de conversão para qualquer ferramenta.
O Formato do Agente
Cada agente na The Agency usa a mesma estrutura:
---
name: API Tester
description: Specialized in API testing with Apidog, Postman, and automated validation
color: purple
emoji: 🧪
vibe: Breaks APIs before users do.
---
# API Tester Agent Personality
You are **API Tester**, an expert in API validation...
## Identity & Memory
- Role: API testing specialist
- Personality: Thorough, skeptical, evidence-focused
...
O arquivo tem duas partes:
- Frontmatter — Metadados YAML entre delimitadores `---`
- Corpo — Conteúdo Markdown após o segundo `---`
Conversão significa: extrair campos do frontmatter, transformar o corpo para o formato alvo, escrever no caminho correto.
Etapa 1: Analisar o Frontmatter YAML
Crie `parse-frontmatter.sh`:
#!/usr/bin/env bash
#
# parse-frontmatter.sh — Extract YAML frontmatter fields from agent files
#
set -euo pipefail
# Extract a single field value from YAML frontmatter
# Usage: get_field <field> <file>
get_field() {
local field="$1" file="$2"
awk -v f="$field" '
/^---$/ { fm++; next }
fm == 1 && $0 ~ "^" f ": " {
sub("^" f ": ", "");
print;
exit
}
' "$file"
}
# Strip frontmatter, return only body
# Usage: get_body <file>
get_body() {
awk 'BEGIN{fm=0} /^---$/{fm++; next} fm>=2{print}' "$1"
}
# Convert name to kebab-case slug
# Usage: to_kebab "API Tester" → api-tester
to_kebab() {
echo "$1" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g'
}
# Demo
if [[ "${1:-}" == "--demo" ]]; then
AGENT_FILE="${2:-test-agent.md}"
echo "File: $AGENT_FILE"
echo "Name: $(get_field 'name' "$AGENT_FILE")"
echo "Description: $(get_field 'description' "$AGENT_FILE")"
echo "Slug: $(to_kebab "$(get_field 'name' "$AGENT_FILE")")"
echo "---"
echo "Body preview:"
get_body "$AGENT_FILE" | head -10
fi
Teste-o:
chmod +x parse-frontmatter.sh
./parse-frontmatter.sh --demo engineering-backend-architect.md
Saída:
File: engineering-backend-architect.md
Name: Backend Architect
Description: Senior backend architect specializing in scalable system design...
Slug: backend-architect
---
Body preview:
# Backend Architect Agent Personality
You are **Backend Architect**, a senior backend architect...
Etapa 2: Converter para o Formato Claude Code
Claude Code usa arquivos `.md` brutos. Nenhuma conversão necessária — apenas copie:
convert_claude_code() {
local agent_file="$1"
local dest="$HOME/.claude/agents/"
mkdir -p "$dest"
cp "$agent_file" "$dest/"
echo " Claude Code: $(basename "$agent_file")"
}
Etapa 3: Converter para o Formato Cursor
Cursor usa arquivos `.mdc` com um campo `description` no frontmatter:
convert_cursor() {
local agent_file="$1"
local name=$(get_field 'name' "$agent_file")
local description=$(get_field 'description' "$agent_file")
local slug=$(to_kebab "$name")
local body=$(get_body "$agent_file")
local output=".cursor/rules/agency-${slug}.mdc"
mkdir -p "$(dirname "$output")"
cat > "$output" << EOF
---
description: Agency agent: $description
---
$body
EOF
echo " Cursor: agency-${slug}.mdc"
}
Entrada:
---
name: API Tester
description: Specialized in API testing...
---
# API Tester Agent...
Saída (`.mdc`):
---
description: Agency agent: Specialized in API testing...
---
# API Tester Agent...
Etapa 4: Converter para o Formato Aider
Aider usa um único arquivo `CONVENTIONS.md` contendo todos os agentes:
convert_aider() {
local agent_file="$1"
local output="CONVENTIONS.md"
# Append with separator
echo "" >> "$output"
echo "---" >> "$output"
echo "" >> "$output"
cat "$agent_file" >> "$output"
echo " Aider: appended to $output"
}
Construa o arquivo completo:
build_aider() {
local output="CONVENTIONS.md"
echo "# Agency Agents for Aider" > "$output"
echo "" >> "$output"
echo "This file contains all Agency agents for Aider integration." >> "$output"
echo "" >> "$output"
for agent_file in engineering/*.md design/*.md testing/*.md; do
convert_aider "$agent_file"
done
}
Etapa 5: Converter para o Formato Windsurf
Windsurf usa um único arquivo `.windsurfrules` (semelhante ao Aider):
convert_windsurf() {
local agent_file="$1"
local output=".windsurfrules"
echo "" >> "$output"
echo "---" >> "$output"
echo "" >> "$output"
cat "$agent_file" >> "$output"
echo " Windsurf: appended to $output"
}
Etapa 6: Converter para o Formato Antigravity
Antigravity (Gemini) usa arquivos `SKILL.md` em subdiretórios:
convert_antigravity() {
local agent_file="$1"
local name=$(get_field 'name' "$agent_file")
local slug=$(to_kebab "$name")
local output="integrations/antigravity/skills/agency-${slug}/SKILL.md"
mkdir -p "$(dirname "$output")"
cat > "$output" << EOF
# Agency Agent: $name
$(get_body "$agent_file")
EOF
echo " Antigravity: agency-${slug}/SKILL.md"
}
Etapa 7: Converter para o Formato OpenClaw
OpenClaw usa três arquivos por agente (`SOUL.md`, `AGENTS.md`, `IDENTITY.md`):
convert_openclaw() {
local agent_file="$1"
local name=$(get_field 'name' "$agent_file")
local description=$(get_field 'description' "$agent_file")
local slug=$(to_kebab "$name")
local body=$(get_body "$agent_file")
local output_dir="integrations/openclaw/agency-${slug}"
mkdir -p "$output_dir"
# SOUL.md - Main agent definition
cat > "$output_dir/SOUL.md" << EOF
# $name
$description
---
$body
EOF
# AGENTS.md - Agent capabilities
cat > "$output_dir/AGENTS.md" << EOF
# Agent Capabilities: $name
- Specialized expertise in domain
- Deliverable-focused output
- Success metrics defined
See SOUL.md for full definition.
EOF
# IDENTITY.md - Agent identity
cat > "$output_dir/IDENTITY.md" << EOF
# Identity: $name
- Name: $name
- Description: $description
- Source: The Agency (agency-agents repo)
EOF
echo " OpenClaw: agency-${slug}/"
}
Etapa 8: O Script `convert.sh` Completo
Aqui está o script de conversão completo (simplificado):
#!/usr/bin/env bash
#
# convert.sh — Convert all Agency agents to tool-specific formats
#
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
OUT_DIR="$REPO_ROOT/integrations"
# Frontmatter helpers
get_field() {
local field="$1" file="$2"
awk -v f="$field" '
/^---$/ { fm++; next }
fm == 1 && $0 ~ "^" f ": " { sub("^" f ": ", ""); print; exit }
' "$file"
}
get_body() {
awk 'BEGIN{fm=0} /^---$/{fm++; next} fm>=2{print}' "$1"
}
to_kebab() {
echo "$1" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g'
}
# Conversion functions
convert_claude_code() {
local agent_file="$1"
local dest="$OUT_DIR/claude-code/"
mkdir -p "$dest"
cp "$agent_file" "$dest/"
}
convert_cursor() {
local agent_file="$1"
local name=$(get_field 'name' "$agent_file")
local slug=$(to_kebab "$name")
local body=$(get_body "$agent_file")
mkdir -p "$OUT_DIR/cursor/.cursor/rules/"
cat > "$OUT_DIR/cursor/.cursor/rules/agency-${slug}.mdc" << EOF
---
description: Agency agent: $(get_field 'description' "$agent_file")
---
$body
EOF
}
convert_aider() {
local output="$OUT_DIR/aider/CONVENTIONS.md"
echo "" >> "$output"
echo "---" >> "$output"
cat "$agent_file" >> "$output"
}
convert_windsurf() {
local output="$OUT_DIR/windsurf/.windsurfrules"
echo "" >> "$output"
echo "---" >> "$output"
cat "$agent_file" >> "$output"
}
# Main conversion loop
echo "Converting Agency agents..."
AGENT_DIRS=(engineering design testing marketing sales)
for dir in "${AGENT_DIRS[@]}"; do
for agent_file in "$REPO_ROOT/$dir"/*.md; do
[[ -f "$agent_file" ]] || continue
name=$(get_field 'name' "$agent_file")
echo "Processing: $name"
convert_claude_code "$agent_file"
convert_cursor "$agent_file"
done
done
# Build combined files
echo "# Agency Agents for Aider" > "$OUT_DIR/aider/CONVENTIONS.md"
for dir in "${AGENT_DIRS[@]}"; do
for agent_file in "$REPO_ROOT/$dir"/*.md; do
[[ -f "$agent_file" ]] || continue
convert_aider "$agent_file"
done
done
echo "# Agency Agents for Windsurf" > "$OUT_DIR/windsurf/.windsurfrules"
for dir in "${AGENT_DIRS[@]}"; do
for agent_file in "$REPO_ROOT/$dir"/*.md; do
[[ -f "$agent_file" ]] || continue
convert_windsurf "$agent_file"
done
done
echo "Conversion complete!"
echo " Claude Code: $OUT_DIR/claude-code/"
echo " Cursor: $OUT_DIR/cursor/.cursor/rules/"
echo " Aider: $OUT_DIR/aider/CONVENTIONS.md"
echo " Windsurf: $OUT_DIR/windsurf/.windsurfrules"
Execute-o:
chmod +x convert.sh
./convert.sh
Etapa 9: Instalar em Cada Ferramenta
Após a conversão, copie os arquivos para os caminhos específicos da ferramenta:
#!/usr/bin/env bash
#
# install.sh — Install converted agents to your local tools
#
set -euo pipefail
# Claude Code
install_claude_code() {
local src="$REPO_ROOT/integrations/claude-code/"
local dest="$HOME/.claude/agents/"
mkdir -p "$dest"
cp "$src"/*.md "$dest/"
echo "Claude Code: $(find "$dest" -name '*.md' | wc -l) agents installed"
}
# Cursor
install_cursor() {
local src="$REPO_ROOT/integrations/cursor/.cursor/rules/"
local dest="./.cursor/rules/"
mkdir -p "$dest"
cp "$src"/*.mdc "$dest/"
echo "Cursor: $(find "$dest" -name '*.mdc' | wc -l) rules installed"
}
# Aider
install_aider() {
local src="$REPO_ROOT/integrations/aider/CONVENTIONS.md"
local dest="./CONVENTIONS.md"
cp "$src" "$dest"
echo "Aider: CONVENTIONS.md installed"
}
# Windsurf
install_windsurf() {
local src="$REPO_ROOT/integrations/windsurf/.windsurfrules"
local dest="./.windsurfrules"
cp "$src" "$dest"
echo "Windsurf: .windsurfrules installed"
}
# Install all detected tools
install_all() {
if [[ -d "$HOME/.claude/agents/" ]]; then
install_claude_code
fi
if command -v cursor &>/dev/null || [[ -d "./.cursor/" ]]; then
install_cursor
fi
if command -v aider &>/dev/null; then
install_aider
fi
}
install_all
Comparação de Formatos
| Ferramenta | Formato | Escopo | Conversão |
|---|---|---|---|
| Claude Code | .md |
Global do usuário (~/.claude/agents/) |
Copia como está |
| Cursor | .mdc |
Projeto (.cursor/rules/) |
Adiciona frontmatter de descrição |
| Aider | CONVENTIONS.md |
Raiz do projeto | Concatena todos os agentes |
| Windsurf | .windsurfrules |
Raiz do projeto | Concatena todos os agentes |
| GitHub Copilot | .md |
Global do usuário (~/.github/agents/) |
Copia como está |
| Antigravity | SKILL.md |
Global do usuário (~/.gemini/antigravity/) |
Empacota em diretório de habilidade |
| OpenClaw | SOUL.md + outros |
Global do usuário (~/.openclaw/) |
Divide em 3 arquivos |
| Gemini CLI | Extensão | Global do usuário (~/.gemini/extensions/) |
Gera manifesto + habilidades |
| OpenCode | .md |
Projeto (.opencode/agents/) |
Copia como está |
| Qwen Code | .md |
Projeto (.qwen/agents/) |
Copia como SubAgente |
Crie Seu Próprio Script de Conversão
Modelo para adicionar uma nova ferramenta:
#!/usr/bin/env bash
# 1. Defina a função de conversão
convert_your_tool() {
local agent_file="$1"
local name=$(get_field 'name' "$agent_file")
local description=$(get_field 'description' "$agent_file")
local slug=$(to_kebab "$name")
local body=$(get_body "$agent_file")
# 2. Crie o caminho de saída
local output="path/to/your/tool/agency-${slug}.ext"
mkdir -p "$(dirname "$output")"
# 3. Escreva o conteúdo convertido
cat > "$output" << EOF
# Seu formato específico da ferramenta
# Use: $name, $description, $body
EOF
echo " YourTool: agency-${slug}.ext"
}
# 4. Adicione ao loop principal
for agent_file in engineering/*.md; do
convert_your_tool "$agent_file"
done
O Que Você Construiu
| Componente | Propósito |
|---|---|
get_field() |
Extrair valores do frontmatter YAML |
get_body() |
Remover frontmatter, retornar corpo markdown |
to_kebab() |
Converter nomes para slugs seguros para URL |
convert_cursor() |
Transformar para formato .mdc |
convert_aider() |
Concatenar em um único arquivo |
convert_windsurf() |
Concatenar em um único arquivo |
convert_antigravity() |
Criar diretórios de habilidades |
convert_openclaw() |
Dividir em 3 arquivos por agente |
install.sh |
Copiar para caminhos específicos da ferramenta |
Próximos Passos
Estenda os scripts:
- Adicione conversão paralela com `xargs -P` ou GNU parallel
- Adicione validação (verifique campos de frontmatter obrigatórios)
- Adicione modo de simulação (`--dry-run` flag)
Adicione mais ferramentas:
- Extensões do VS Code
- IDEs JetBrains
- Ferramentas internas personalizadas
Otimize para grandes repositórios:
- Armazene em cache o frontmatter analisado
- Use `find` com `-print0` para manipulação segura de arquivos
- Adicione barras de progresso para mais de 100 agentes
Solução de Problemas Comuns
O script de conversão falha com "bad substitution":
- Certifique-se de que está executando bash, não sh: `#!/usr/bin/env bash`
- Verifique a versão do bash: `bash --version` (deve ser 4.0+)
- Execute explicitamente com bash: `bash convert.sh`
- Procure por quebras de linha do Windows: `sed -i 's/\r$//' convert.sh`
Campos do frontmatter não estão sendo extraídos:
- Verifique se o formato YAML usa `: ` (dois pontos espaço) e não apenas `:`
- Verifique se há espaços extras antes dos nomes dos campos
- Certifique-se de que os delimitadores do frontmatter são exatamente `---` (3 hífens)
- Teste a análise manualmente: `./parse-frontmatter.sh --demo agent.md`
A geração de slugs cria nomes quebrados:
- Teste a função `to_kebab()` com casos extremos
- Lide com caracteres especiais: `to_kebab() { echo "$1" | iconv -f utf8 -t ascii//translit | ... }`
- Adicione um fallback para slugs vazios: `[[ -z "$slug" ]] && slug="unknown-agent"`
- Registre os nomes originais para depuração
Regras do Cursor não estão carregando:
- Verifique se os arquivos `.mdc` têm frontmatter válido com `description`
- Verifique a configuração MCP do Cursor: `.cursor/mcp.json`
- Certifique-se de que os arquivos estão em `.cursor/rules/` e não em `.cursor/agents/`
- Reinicie o Cursor após adicionar novas regras
A CONVENTIONS.md do Aider fica muito grande:
- Divida por categoria: `CONVENTIONS-engineering.md`, `CONVENTIONS-design.md`
- Implemente a poda automática para agentes obsoletos
- Adicione um índice no topo
- Considere arquivos por agente com diretivas de inclusão
Otimização de Desempenho para Grandes Conversões
Processamento Paralelo:
Para repositórios com mais de 100 agentes, use GNU parallel:
#!/usr/bin/env bash
# convert-parallel.sh
export OUT_DIR="$REPO_ROOT/integrations"
# Export functions for parallel use
export -f get_field get_body to_kebab convert_cursor convert_claude_code
# Find all agent files and process in parallel
find "$REPO_ROOT" -name "*.md" -type f | \
parallel -j 8 --progress '
name=$(get_field "name" {})
slug=$(to_kebab "$name")
echo "Converting: $name"
convert_cursor "{}"
convert_claude_code "{}"
'
echo "Parallel conversion complete!"
Conversão Incremental:
Converta apenas arquivos alterados:
#!/usr/bin/env bash
# convert-incremental.sh
CACHE_FILE="$REPO_ROOT/.conversion-cache"
# Load previous state
declare -A PREV_HASHES
if [[ -f "$CACHE_FILE" ]]; then
while IFS='=' read -r file hash; do
PREV_HASHES["$file"]="$hash"
done < "$CACHE_FILE"
fi
# Process each agent
for agent_file in engineering/*.md; do
CURRENT_HASH=$(md5sum "$agent_file" | cut -d' ' -f1)
PREV_HASH="${PREV_HASHES[$agent_file]:-}"
if [[ "$CURRENT_HASH" != "$PREV_HASH" ]]; then
echo "Changed: $agent_file"
convert_cursor "$agent_file"
convert_claude_code "$agent_file"
NEW_HASHES["$agent_file"]="$CURRENT_HASH"
else
echo "Unchanged: $agent_file"
fi
done
# Save cache
for file in "${!NEW_HASHES[@]}"; do
echo "$file=${NEW_HASHES[$file]}"
done > "$CACHE_FILE"
Rastreamento de Progresso:
Adicione progresso visual para conversões longas:
#!/usr/bin/env bash
total_files=$(find "$REPO_ROOT" -name "*.md" -type f | wc -l)
current=0
for agent_file in "$REPO_ROOT"/**/*.md; do
((current++))
percent=$((current * 100 / total_files))
# Progress bar
filled=$((percent / 5))
empty=$((20 - filled))
bar=$(printf '%*s' "$filled" | tr ' ' '#')
spaces=$(printf '%*s' "$empty" | tr ' ' ' ')
name=$(get_field 'name' "$agent_file")
echo -ne "\r[${bar}${spaces}] ${percent}% - $name"
convert_cursor "$agent_file"
done
echo -ne "\n"
Considerações de Segurança para Agentes Compartilhados
Validando Fontes de Agentes:
Ao baixar agentes de fontes externas:
#!/usr/bin/env bash
# validate-agent.sh
validate_agent() {
local file="$1"
# Check required frontmatter fields
local name=$(get_field 'name' "$file")
local description=$(get_field 'description' "$file")
if [[ -z "$name" ]]; then
echo "ERROR: Missing 'name' field in $file"
return 1
fi
if [[ -z "$description" ]]; then
echo "WARNING: Missing 'description' field in $file"
fi
# Check for malicious patterns in body
local body=$(get_body "$file")
if echo "$body" | grep -q 'rm -rf\|curl.*\|wget.*\|eval\|exec'; then
echo "WARNING: Potentially dangerous patterns in $file"
return 1
fi
echo "VALID: $name"
return 0
}
Execução de Agentes em Sandbox:
Para agentes não confiáveis, execute em ambientes isolados:
- Use contêineres Docker para execução de agentes
- Limite o acesso ao sistema de arquivos com montagens somente leitura
- Restrinja o acesso à rede a domínios específicos
- Registre todas as ações do agente para trilhas de auditoria
Um arquivo de agente. Dez IDEs. Dois scripts bash.
Esse é o poder da automação de conversão. Escreva uma vez, converta automaticamente, instale em todo lugar.
Sua vez: adicione suporte de conversão para sua ferramenta de IA favorita. Compartilhe o script. Torne os agentes portáteis.
Principais Conclusões
- Escreva uma vez, converta para mais de 10 formatos — Um único arquivo Markdown com frontmatter YAML se transforma em Claude Code, Cursor, Aider, Windsurf e mais de 6 outras ferramentas
- A análise Bash lida com a extração do frontmatter — `get_field()` extrai valores YAML, `get_body()` remove o frontmatter, `to_kebab()` cria slugs seguros para URL
- Formatos específicos de ferramentas exigem transformações diferentes — Claude Code copia como está, Cursor adiciona frontmatter de descrição, Aider/Windsurf concatenam todos os agentes
- Scripts de instalação copiam para os caminhos corretos — Ferramentas globais do usuário usam `~/.claude/agents/`, ferramentas de projeto usam `.cursor/rules/` ou arquivos na raiz do projeto
- Estenda com modelos para novas ferramentas — Defina a função `convert_your_tool()`, adicione ao loop principal, documente os requisitos de formato
FAQ
O que é convert.sh e como ele funciona? convert.sh é um script bash que analisa o frontmatter YAML de arquivos Markdown de agente, extrai o conteúdo do corpo e transforma cada agente para formatos específicos de ferramentas. Ele usa awk para análise, sed para conversão de slugs e heredocs para geração de saída.
Como funciona a análise de frontmatter em bash? A função `get_field()` usa awk para rastrear delimitadores de frontmatter (`---`), encontra a linha que corresponde ao nome do campo e extrai o valor. `get_body()` imprime todas as linhas após o segundo delimitador `---`.
Quais IDEs e ferramentas são suportadas? Claude Code (`.md`), Cursor (`.mdc`), Aider (`CONVENTIONS.md`), Windsurf (`.windsurfrules`), GitHub Copilot (`.md`), Antigravity (`SKILL.md`), OpenClaw (`SOUL.md` + 2 arquivos), extensões Gemini CLI, OpenCode e Qwen Code.
Como adiciono suporte de conversão para uma nova ferramenta? Crie uma função `convert_yourtool()` que extraia os campos do frontmatter, transforme o corpo para o formato da sua ferramenta e escreva no caminho correto. Adicione a chamada da função ao loop principal de conversão.
Posso executar conversões em paralelo para um processamento mais rápido? Sim. Use `xargs -P` ou GNU parallel para processar vários arquivos de agente simultaneamente. Para mais de 100 agentes, a conversão paralela pode reduzir o tempo de execução de minutos para segundos.
Como valido se os campos do frontmatter existem? Adicione verificações de validação na sua função de conversão: `[[ -z "$name" ]] && echo "Missing name field" && exit 1`. Execute a validação antes de escrever os arquivos de saída.
E se a conversão falhar para alguns agentes? Use `set -euo pipefail` para falhar rapidamente em erros. Adicione tratamento de erros com `|| continue` para pular arquivos quebrados. Registre as falhas em um arquivo separado para depuração.
