Última revisão: maio de 2026
Exercite os temas do exame CCA-F no seu terminal — comandos do Claude Code CLI, chamadas à API da Anthropic, servidores MCP e padrões multi-agente, cada um vinculado a um domínio do exame.
Ao final deste laboratório, você terá instalado o Claude Code, configurado um projeto com CLAUDE.md, criado um comando de barra personalizado, conectado um servidor MCP, exercitado a API tool-use com saída estruturada, explorado o extended thinking, e construído um pipeline supervisor multiagente — cobrindo todos os cinco domínios do exame CCA-F a partir do seu terminal. Nenhuma conta na nuvem ou cobrança é necessária; tudo roda localmente.
node --version)ANTHROPIC_API_KEY em seu shell (export ANTHROPIC_API_KEY=sk-ant-...)mkdir cca-f-lab && cd cca-f-lab)Chamadas de API para Anthropic incorrem em cobranças baseadas no uso. As etapas 6–8 e 10 usam claude-sonnet-4-6, que custa aproximadamente $3/milhão de tokens de entrada e $15/milhão de tokens de saída. O custo total para este laboratório é tipicamente inferior a $0.15. O extended thinking (Etapa 7) usa tokens de "pensamento" adicionais cobrados à taxa de saída.
Claude Code é a CLI que o exame CCA-F testa mais diretamente — configuração, hooks, comandos de barra e modos de permissão, tudo reside aqui. Começamos instalando-o globalmente para que cada etapa posterior possa chamar claude.
Após a instalação, um rápido claude --version prova que o binário está no seu PATH, e claude --print-system-prompt confirma que a chave de API é válida (ele faz uma chamada leve por baixo dos panos).
# Install Claude Code globally
npm install -g @anthropic-ai/claude-code
# Verify installation
claude --version
# Confirm API connectivity (prints the built-in system prompt)
claude --print-system-prompt | head -20O exame testa intensamente a hierarquia CLAUDE.md de três níveis: usuário (~/.claude/CLAUDE.md), projeto (raiz do repositório) e módulo (subdiretórios). Cada nível herda do anterior e pode sobrescrevê-lo.
Nós criaremos um arquivo de nível de projeto que define convenções de codificação e um arquivo de nível de usuário que define preferências pessoais. Quando o Claude Code lê o projeto, ele mescla todos os três níveis — exatamente o comportamento que o exame pergunta.
# Create project root CLAUDE.md
cat > CLAUDE.md << 'EOF'
# Project: CCA-F Lab
## Coding conventions
- Use TypeScript for all new files
- Prefer const over let
- Use single quotes for strings
- No semicolons (Prettier default)
## Testing
- Run `npm test` before committing
- All new functions must have at least one test
EOF
# Create user-level CLAUDE.md (applies to ALL your projects)
mkdir -p ~/.claude
cat > ~/.claude/CLAUDE.md << 'EOF'
# User preferences
- Be concise in responses
- Prefer functional programming patterns
- Always explain the "why" before showing code
EOF
# Verify Claude Code sees both files
claude "What instructions do you see in CLAUDE.md?" --printComandos de barra personalizados vivem em .claude/commands/ como arquivos Markdown. O nome do arquivo se torna o nome do comando (por exemplo, scaffold.md → /scaffold). O conteúdo do arquivo é o template do prompt — ele pode incluir $ARGUMENTS para entrada do usuário.
Este é um tópico de exame de alta frequência: onde os comandos residem, como os argumentos são passados e como eles diferem dos hooks.
# Create the commands directory
mkdir -p .claude/commands
# Create a scaffold command
cat > .claude/commands/scaffold.md << 'EOF'
Create a new TypeScript module named $ARGUMENTS with:
1. A main source file at src/$ARGUMENTS/index.ts
2. A test file at src/$ARGUMENTS/__tests__/index.test.ts
3. Export the module from the project root index.ts
Follow the coding conventions in CLAUDE.md.
EOF
# Test the command (Claude Code will execute it interactively)
claude /scaffold calculatorOs hooks executam comandos do shell em resposta a eventos do Claude Code. O exame testa três tipos de hook: PreToolUse (antes da execução de uma tool), PostToolUse (depois) e Notification (em mudanças de status). Os hooks são definidos em .claude/settings.json.
Nós adicionaremos um hook PostToolUse que executa um linter após cada edição de arquivo — um padrão de produção comum sobre o qual o exame pergunta com frequência.
# Initialize a package.json so we have a lint script
npm init -y
npm install --save-dev typescript @typescript-eslint/parser
# Create project-level settings with a post-tool hook
mkdir -p .claude
cat > .claude/settings.json << 'EOF'
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"command": "npx tsc --noEmit 2>&1 | head -5"
}
]
},
"permissions": {
"allow": [
"Read",
"Write",
"Edit"
]
}
}
EOF
# Verify settings are recognized
cat .claude/settings.jsonO Model Context Protocol (MCP) é um domínio central do exame. Servidores MCP expõem tools, resources e prompts para clientes LLM via um protocolo JSON-RPC padronizado. O transporte stdio é o mais simples — o servidor lê do stdin e escreve para o stdout.
Nós construiremos um servidor MCP mínimo que expõe uma tool get_weather, então configuraremos o Claude Code para se conectar a ele. Isso exercita o ciclo de vida completo do MCP testado no exame: definição da tool, conexão de transporte, invocação da tool e tratamento de resultados.
# Install the MCP SDK
npm install @modelcontextprotocol/sdk
# Create the MCP server
cat > mcp-weather.mjs << 'EOF'
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = new McpServer({ name: "weather", version: "1.0.0" });
server.tool("get_weather", { city: { type: "string" } }, async ({ city }) => ({
content: [{ type: "text", text: `Weather in ${city}: 72°F, sunny` }],
}));
const transport = new StdioServerTransport();
await server.connect(transport);
EOF
# Register the MCP server in Claude Code settings
cat > .claude/settings.json << 'EOF'
{
"mcpServers": {
"weather": {
"command": "node",
"args": ["mcp-weather.mjs"]
}
}
}
EOF
# Ask Claude Code to use the MCP tool
claude "What is the weather in Tokyo? Use the get_weather tool."O exame testa o fluxo de tool-use da Messages API em detalhes: você envia tools na requisição, o modelo responde com um bloco de conteúdo tool_use, você o executa e retorna um tool_result, então o modelo produz a resposta final.
Esta etapa usa curl para chamar a API diretamente — a abordagem mais alinhada ao exame, pois o exame testa o formato bruto da requisição/resposta, não wrappers de SDK.
# Call the Messages API with a tool definition
curl -s https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-sonnet-4-6",
"max_tokens": 1024,
"tools": [{
"name": "calculate",
"description": "Evaluate a math expression",
"input_schema": {
"type": "object",
"properties": {
"expression": { "type": "string", "description": "Math expression to evaluate" }
},
"required": ["expression"]
}
}],
"messages": [{
"role": "user",
"content": "What is 15% tip on a $85.50 dinner bill?"
}]
}' | python3 -m json.toolO extended thinking permite que o modelo use um bloco thinking para raciocinar passo a passo antes de responder. O exame testa quando usá-lo (raciocínio complexo, matemática, geração de código) e como configurar budget_tokens.
Nós enviamos um quebra-cabeça lógico intencionalmente complicado e comparamos as respostas com e sem extended thinking para ver a diferença de qualidade em primeira mão.
# Request WITH extended thinking
curl -s https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-sonnet-4-6",
"max_tokens": 16000,
"thinking": {
"type": "enabled",
"budget_tokens": 10000
},
"messages": [{
"role": "user",
"content": "A farmer has 17 sheep. All but 9 run away. How many does he have left? Explain your reasoning step by step."
}]
}' | python3 -m json.tool
# The response includes a "thinking" block showing the model's
# internal reasoning before the final answer.O prompt caching permite marcar partes da requisição como cacheáveis. Prefixes em cache custam 90% menos em chamadas subsequentes e têm latência adicional zero. O exame testa o posicionamento do bloco cache_control e os headers de cache-hit.
Nós enviamos o mesmo system prompt grande duas vezes e verificamos os headers da resposta para confirmar o cache hit na segunda chamada.
# First call — creates the cache entry
curl -s -D /dev/stderr https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-sonnet-4-6",
"max_tokens": 256,
"system": [{
"type": "text",
"text": "You are a helpful assistant specialized in cloud architecture. You follow AWS Well-Architected Framework principles. You always recommend infrastructure as code. You prefer Terraform over CloudFormation. You prioritize security and cost optimization.",
"cache_control": { "type": "ephemeral" }
}],
"messages": [{ "role": "user", "content": "How should I set up VPC peering?" }]
}' > /dev/null 2>&1
# Second call — should hit the cache (check usage.cache_read_input_tokens)
curl -s https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-sonnet-4-6",
"max_tokens": 256,
"system": [{
"type": "text",
"text": "You are a helpful assistant specialized in cloud architecture. You follow AWS Well-Architected Framework principles. You always recommend infrastructure as code. You prefer Terraform over CloudFormation. You prioritize security and cost optimization.",
"cache_control": { "type": "ephemeral" }
}],
"messages": [{ "role": "user", "content": "What about NAT gateway sizing?" }]
}' | python3 -c "import sys,json; d=json.load(sys.stdin); print(f\"Cache read tokens: {d['usage'].get('cache_read_input_tokens', 0)}\")"O exame testa como executar o Claude Code de forma não interativa — a flag --print envia o resultado para o stdout sem uma sessão interativa, e --output-format json fornece saída estruturada para scripting.
Este é o padrão usado em pipelines de CI: fornecer um prompt, obter um resultado, analisá-lo programaticamente.
# Headless mode: prompt in, text out
claude --print "List 3 TypeScript best practices, one per line"
# JSON output for programmatic use
claude --print --output-format json "What is 2+2?"
# Pipe a file for code review (CI pattern)
echo 'const x: any = "hello";' > example.ts
claude --print "Review this TypeScript file for type safety issues: $(cat example.ts)"O Domínio 1 (Agentic Architecture, 27%) é o de maior peso no exame. O padrão supervisor — um orquestrador despachando para sub-agentes especialistas, cada um com seu próprio system prompt e conjunto de tools — é a arquitetura mais testada.
Nós construiremos um script Node.js autocontido que implementa um supervisor coordenando dois especialistas: um pesquisador que lê arquivos e resume, e um escritor que produz a saída. O supervisor decompõe uma tarefa, delega a cada especialista via chamadas de API separadas e agrega os resultados. Execute-o no terminal e observe a delegação acontecer ao vivo.
# Install the Anthropic SDK
npm install @anthropic-ai/sdk
# Create sample data for the agents to work with
cat > sales-data.csv << 'EOF'
month,revenue,units
Jan,12500,150
Feb,15200,180
Mar,11800,140
Apr,18900,220
May,22100,260
Jun,19500,230
EOF
# Create the multi-agent supervisor script
cat > supervisor.mjs << 'SCRIPT'
import Anthropic from "@anthropic-ai/sdk";
import { readFileSync } from "fs";
const client = new Anthropic();
async function callAgent(role, systemPrompt, userMessage) {
console.log(`\n--- ${role} agent ---`);
const response = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 1024,
system: systemPrompt,
messages: [{ role: "user", content: userMessage }],
});
const text = response.content
.filter((b) => b.type === "text")
.map((b) => b.text)
.join("\n");
console.log(text);
return text;
}
// --- Supervisor: decompose, delegate, aggregate ---
const data = readFileSync("sales-data.csv", "utf-8");
console.log("=== SUPERVISOR: Decomposing task ===");
console.log("Task: Analyze sales data and write a brief executive summary.\n");
console.log("Step 1: Delegate analysis to Researcher agent");
console.log("Step 2: Delegate writing to Writer agent");
console.log("Step 3: Combine results\n");
// Sub-agent 1: Researcher — extracts insights
const analysis = await callAgent(
"Researcher",
"You are a data analyst. Extract key trends, highs, lows, and growth rates. Be precise with numbers. Output bullet points only.",
`Analyze this CSV data:\n\n${data}`
);
// Sub-agent 2: Writer — produces the summary from the analysis
const summary = await callAgent(
"Writer",
"You are a business writer. Write a 3-sentence executive summary from the analysis provided. Use a professional tone. Include specific numbers.",
`Write an executive summary based on these findings:\n\n${analysis}`
);
console.log("\n=== SUPERVISOR: Final aggregated output ===");
console.log(summary);
SCRIPT
# Run the supervisor
node supervisor.mjsEste laboratório roda inteiramente localmente — sem recursos de nuvem para derrubar.
# Remove the lab directory
cd .. && rm -rf cca-f-lab
# Optionally remove the user-level CLAUDE.md we created
rm -f ~/.claude/CLAUDE.md
# Optionally uninstall Claude Code
npm uninstall -g @anthropic-ai/claude-code
Este laboratório foca em exercícios práticos de CLI e API. Ele não aborda:
screenshots; não é prático em um laboratório apenas de terminal.batch assíncrono é conceitualmente simples, mas leva minutos para ser concluído; o Playbook cobre o formato da requisição.Browse e Playbook.