<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Minion Engine — Seu time de AI rodando em Docker Sandboxes</title>
<style>
:root {
--bg: #0d1117;
--bg2: #161b22;
--bg3: #1c2333;
--border: #30363d;
--text: #e6edf3;
--text-dim: #8b949e;
--accent: #58a6ff;
--green: #3fb950;
--yellow: #d29922;
--red: #f85149;
--purple: #bc8cff;
--cyan: #39d353;
--orange: #f0883e;
--pink: #f778ba;
--code-bg: #0d1117;
--card-shadow: 0 2px 12px rgba(0,0,0,0.4);
--accent-glow: rgba(88,166,255,0.12);
--green-glow: rgba(63,185,80,0.12);
--yellow-glow: rgba(210,153,34,0.12);
--red-glow: rgba(248,81,73,0.12);
--purple-glow: rgba(188,140,255,0.12);
--orange-glow: rgba(240,136,62,0.12);
--cyan-glow: rgba(57,211,83,0.12);
--pink-glow: rgba(247,120,186,0.12);
--radius: 8px;
}
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; scroll-padding-top: 32px; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.7;
}
.nav {
position: fixed;
top: 0; left: 0;
width: 260px;
height: 100vh;
background: var(--bg2);
border-right: 1px solid var(--border);
padding: 24px 0;
overflow-y: auto;
z-index: 100;
}
.nav-logo {
padding: 0 20px 20px;
border-bottom: 1px solid var(--border);
margin-bottom: 16px;
}
.nav-logo h2 {
font-size: 1.1rem;
font-weight: 800;
background: linear-gradient(135deg, var(--cyan), var(--accent));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.nav-logo span {
font-size: 11px;
color: var(--text-dim);
display: block;
margin-top: 2px;
}
.nav-group-title {
font-size: 10px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.12em;
color: var(--text-dim);
padding: 12px 20px 6px;
}
.nav a {
display: block;
padding: 6px 20px 6px 28px;
color: var(--text-dim);
text-decoration: none;
font-size: 13px;
transition: color .15s, background .15s;
border-left: 2px solid transparent;
}
.nav a:hover { color: var(--text); background: rgba(255,255,255,0.03); }
.nav a.active {
color: var(--cyan);
border-left-color: var(--cyan);
background: var(--cyan-glow);
font-weight: 600;
}
.main {
margin-left: 260px;
min-height: 100vh;
}
.hero {
background: linear-gradient(135deg, #0d1117 0%, #161b22 50%, #1a1e2e 100%);
border-bottom: 1px solid var(--border);
padding: 80px 48px 60px;
text-align: center;
position: relative;
overflow: hidden;
}
.hero::before {
content: '';
position: absolute;
top: -50%; left: -50%;
width: 200%; height: 200%;
background: radial-gradient(circle at 30% 50%, var(--cyan-glow) 0%, transparent 50%),
radial-gradient(circle at 70% 80%, var(--accent-glow) 0%, transparent 50%);
animation: heroGlow 8s ease-in-out infinite alternate;
}
@keyframes heroGlow { from { opacity: .5; } to { opacity: 1; } }
.hero-content { position: relative; z-index: 1; max-width: 750px; margin: 0 auto; }
.hero h1 {
font-size: 3rem;
font-weight: 900;
letter-spacing: -0.04em;
margin-bottom: 12px;
background: linear-gradient(135deg, var(--cyan), var(--accent));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.hero p {
font-size: 1.1rem;
color: var(--text-dim);
max-width: 620px;
margin: 0 auto 24px;
}
.hero-badges {
display: flex;
gap: 10px;
justify-content: center;
flex-wrap: wrap;
}
.badge {
font-size: 12px;
font-weight: 600;
padding: 4px 14px;
border-radius: 999px;
border: 1px solid var(--border);
background: var(--bg2);
color: var(--text-dim);
}
.badge.accent { border-color: var(--accent); color: var(--accent); background: var(--accent-glow); }
.badge.green { border-color: var(--green); color: var(--green); background: var(--green-glow); }
.badge.purple { border-color: var(--purple); color: var(--purple); background: var(--purple-glow); }
.badge.orange { border-color: var(--orange); color: var(--orange); background: var(--orange-glow); }
.badge.yellow { border-color: var(--yellow); color: var(--yellow); background: var(--yellow-glow); }
.badge.cyan { border-color: var(--cyan); color: var(--cyan); background: var(--cyan-glow); }
.container {
max-width: 920px;
margin: 0 auto;
padding: 48px 48px 0;
}
section {
margin-bottom: 72px;
}
.section-label {
font-size: 10px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.12em;
color: var(--cyan);
margin-bottom: 8px;
}
section > h2 {
font-size: 1.6rem;
font-weight: 700;
letter-spacing: -0.02em;
margin-bottom: 8px;
}
section > h2 + p {
color: var(--text-dim);
margin-bottom: 24px;
font-size: 1rem;
}
h3 {
font-size: 1.15rem;
font-weight: 700;
margin: 32px 0 12px;
}
h4 {
font-size: 0.95rem;
font-weight: 700;
margin: 20px 0 8px;
color: var(--text);
}
p { margin-bottom: 12px; }
p.dim { color: var(--text-dim); }
ul, ol { margin-bottom: 12px; padding-left: 24px; }
li { color: var(--text-dim); font-size: 0.92rem; margin-bottom: 4px; }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin: 16px 0; }
.grid-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; margin: 16px 0; }
.grid-4 { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 16px; margin: 16px 0; }
.card {
background: var(--bg2);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 24px;
box-shadow: var(--card-shadow);
}
.card h4 {
font-size: 1rem;
margin: 0 0 8px;
}
.card p { color: var(--text-dim); font-size: 0.92rem; margin: 0; }
.card .card-icon {
width: 36px; height: 36px;
border-radius: 8px;
display: flex; align-items: center; justify-content: center;
font-size: 18px; margin-bottom: 12px;
}
.recipe-card {
background: var(--bg2);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 28px;
margin-bottom: 24px;
box-shadow: var(--card-shadow);
position: relative;
}
.recipe-card::before {
content: '';
position: absolute;
top: 0; left: 0;
width: 4px; height: 100%;
border-radius: var(--radius) 0 0 var(--radius);
}
.recipe-card.cyan-border { border-color: rgba(57,211,83,0.4); }
.recipe-card.cyan-border::before { background: var(--cyan); }
.recipe-card.accent-border { border-color: rgba(88,166,255,0.4); }
.recipe-card.accent-border::before { background: var(--accent); }
.recipe-card.orange-border { border-color: rgba(240,136,62,0.4); }
.recipe-card.orange-border::before { background: var(--orange); }
.recipe-card.purple-border { border-color: rgba(188,140,255,0.4); }
.recipe-card.purple-border::before { background: var(--purple); }
.recipe-card.green-border { border-color: rgba(63,185,80,0.4); }
.recipe-card.green-border::before { background: var(--green); }
.recipe-card.yellow-border { border-color: rgba(210,153,34,0.4); }
.recipe-card.yellow-border::before { background: var(--yellow); }
.recipe-card.red-border { border-color: rgba(248,81,73,0.4); }
.recipe-card.red-border::before { background: var(--red); }
.recipe-card h3 {
margin: 0 0 8px;
font-size: 1.1rem;
}
.recipe-card h3 .recipe-badge {
display: inline-block;
font-size: 10px;
font-weight: 700;
padding: 2px 8px;
border-radius: 4px;
text-transform: uppercase;
letter-spacing: 0.04em;
vertical-align: middle;
margin-left: 8px;
}
.recipe-card.cyan-border h3 { color: var(--cyan); }
.recipe-card.cyan-border h3 .recipe-badge { background: var(--cyan-glow); color: var(--cyan); border: 1px solid rgba(57,211,83,0.3); }
.recipe-card.accent-border h3 { color: var(--accent); }
.recipe-card.accent-border h3 .recipe-badge { background: var(--accent-glow); color: var(--accent); border: 1px solid rgba(88,166,255,0.3); }
.recipe-card.orange-border h3 { color: var(--orange); }
.recipe-card.orange-border h3 .recipe-badge { background: var(--orange-glow); color: var(--orange); border: 1px solid rgba(240,136,62,0.3); }
.recipe-card.purple-border h3 { color: var(--purple); }
.recipe-card.purple-border h3 .recipe-badge { background: var(--purple-glow); color: var(--purple); border: 1px solid rgba(188,140,255,0.3); }
.recipe-card.green-border h3 { color: var(--green); }
.recipe-card.green-border h3 .recipe-badge { background: var(--green-glow); color: var(--green); border: 1px solid rgba(63,185,80,0.3); }
.recipe-card.yellow-border h3 { color: var(--yellow); }
.recipe-card.yellow-border h3 .recipe-badge { background: var(--yellow-glow); color: var(--yellow); border: 1px solid rgba(210,153,34,0.3); }
.recipe-card.red-border h3 { color: var(--red); }
.recipe-card.red-border h3 .recipe-badge { background: var(--red-glow); color: var(--red); border: 1px solid rgba(248,81,73,0.3); }
.recipe-card > p { color: var(--text-dim); font-size: 0.92rem; }
.recipe-steps {
margin: 16px 0 0;
padding: 0;
list-style: none;
}
.recipe-steps li {
color: var(--text-dim);
font-size: 0.9rem;
padding: 4px 0 4px 20px;
position: relative;
}
.recipe-steps li::before {
content: '';
position: absolute;
left: 4px; top: 12px;
width: 6px; height: 6px;
border-radius: 50%;
background: var(--border);
}
.recipe-steps li code { font-size: 12px; }
.terminal {
background: var(--code-bg);
border: 1px solid var(--border);
border-radius: var(--radius);
overflow: hidden;
margin: 20px 0;
box-shadow: var(--card-shadow);
}
.terminal-bar {
background: var(--bg3);
padding: 10px 16px;
display: flex;
align-items: center;
gap: 8px;
border-bottom: 1px solid var(--border);
}
.terminal-dot {
width: 12px; height: 12px;
border-radius: 50%;
}
.terminal-dot.red { background: var(--red); }
.terminal-dot.yellow { background: var(--yellow); }
.terminal-dot.green { background: var(--green); }
.terminal-title {
flex: 1;
text-align: center;
font-size: 12px;
color: var(--text-dim);
font-weight: 500;
}
.terminal-body {
padding: 16px 20px;
font-family: 'SF Mono', SFMono-Regular, ui-monospace, 'Cascadia Code', monospace;
font-size: 13px;
line-height: 1.6;
overflow-x: auto;
white-space: pre;
}
.terminal-body .prompt { color: var(--green); }
.terminal-body .ok { color: var(--green); }
.terminal-body .err { color: var(--red); }
.terminal-body .warn { color: var(--yellow); }
.terminal-body .info { color: var(--accent); }
.terminal-body .dim { color: var(--text-dim); }
.terminal-body .bold { color: #fff; font-weight: 700; }
.terminal-body .purple { color: var(--purple); }
.terminal-body .orange { color: var(--orange); }
.terminal-body .cyan { color: var(--cyan); }
pre {
background: var(--code-bg);
border: 1px solid var(--border);
border-radius: 6px;
padding: 16px 20px;
overflow-x: auto;
font-size: 13px;
line-height: 1.6;
margin: 16px 0;
font-family: 'SF Mono', SFMono-Regular, ui-monospace, monospace;
}
code {
font-family: 'SF Mono', SFMono-Regular, ui-monospace, monospace;
font-size: 0.88em;
}
:not(pre) > code {
background: var(--bg3);
border: 1px solid var(--border);
border-radius: 4px;
padding: 2px 6px;
color: var(--accent);
}
.cmd { color: var(--green); }
.flag { color: var(--yellow); }
.str { color: var(--orange); }
.cmt { color: var(--text-dim); font-style: italic; }
.key { color: var(--cyan); }
.val { color: var(--orange); }
.diagram-container {
background: var(--bg2);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 32px 24px 24px;
margin: 24px 0;
overflow-x: auto;
}
.diagram-title {
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--text-dim);
margin-bottom: 20px;
text-align: center;
}
.diagram-container svg {
display: block;
margin: 0 auto;
}
.flow-steps {
position: relative;
padding-left: 48px;
margin: 24px 0;
}
.flow-steps::before {
content: '';
position: absolute;
left: 17px; top: 24px; bottom: 24px;
width: 2px;
background: var(--border);
}
.flow-step {
position: relative;
margin-bottom: 28px;
}
.flow-step:last-child { margin-bottom: 0; }
.flow-step-num {
position: absolute;
left: -48px; top: 0;
width: 34px; height: 34px;
border-radius: 50%;
display: flex; align-items: center; justify-content: center;
font-size: 13px;
font-weight: 800;
background: var(--cyan-glow);
color: var(--cyan);
border: 2px solid var(--cyan);
z-index: 1;
}
.flow-step-num.green { background: var(--green-glow); color: var(--green); border-color: var(--green); }
.flow-step-num.purple { background: var(--purple-glow); color: var(--purple); border-color: var(--purple); }
.flow-step-num.accent { background: var(--accent-glow); color: var(--accent); border-color: var(--accent); }
.flow-step-num.yellow { background: var(--yellow-glow); color: var(--yellow); border-color: var(--yellow); }
.flow-step-num.orange { background: var(--orange-glow); color: var(--orange); border-color: var(--orange); }
.flow-step-num.red { background: var(--red-glow); color: var(--red); border-color: var(--red); }
.flow-step h4 { margin: 4px 0 6px; font-size: 0.95rem; }
.flow-step p { color: var(--text-dim); font-size: 0.9rem; margin: 0 0 8px; }
.tip {
background: var(--bg2);
border: 1px solid var(--border);
border-left: 3px solid var(--accent);
border-radius: var(--radius);
padding: 16px 20px;
margin: 20px 0;
font-size: 0.92rem;
}
.tip .tip-title {
font-weight: 700;
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.06em;
margin-bottom: 6px;
}
.tip p, .tip code { font-size: 0.9rem; }
.tip p { color: var(--text-dim); margin-bottom: 4px; }
.tip .tip-title { color: var(--accent); }
.tip.warn { border-left-color: var(--yellow); }
.tip.warn .tip-title { color: var(--yellow); }
.tip.err { border-left-color: var(--red); }
.tip.err .tip-title { color: var(--red); }
.tip.ok { border-left-color: var(--green); }
.tip.ok .tip-title { color: var(--green); }
.tip.docker { border-left-color: var(--accent); }
.tip.docker .tip-title { color: var(--accent); }
table {
width: 100%;
border-collapse: collapse;
margin: 16px 0;
font-size: 0.9rem;
}
th, td {
padding: 10px 14px;
text-align: left;
border: 1px solid var(--border);
}
th {
background: var(--bg3);
font-weight: 700;
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--text-dim);
}
td { color: var(--text-dim); }
td code { font-size: 12px; }
.faq-item {
background: var(--bg2);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 20px 24px;
margin-bottom: 12px;
}
.faq-item .faq-q {
font-weight: 700;
font-size: 0.95rem;
color: var(--text);
margin-bottom: 8px;
}
.faq-item .faq-a {
color: var(--text-dim);
font-size: 0.9rem;
margin: 0;
}
footer {
border-top: 1px solid var(--border);
padding: 32px 48px;
text-align: center;
color: var(--text-dim);
font-size: 13px;
}
.sandbox-flow {
display: flex;
align-items: center;
gap: 0;
margin: 24px 0;
overflow-x: auto;
padding: 16px 0;
}
.sandbox-flow-node {
background: var(--bg2);
border: 2px solid var(--border);
border-radius: var(--radius);
padding: 14px 18px;
text-align: center;
white-space: nowrap;
font-size: 0.88rem;
font-weight: 600;
min-width: 130px;
}
.sandbox-flow-node.docker {
border-color: var(--accent);
background: var(--accent-glow);
color: var(--accent);
}
.sandbox-flow-node.safe {
border-color: var(--green);
background: var(--green-glow);
color: var(--green);
}
.sandbox-flow-node.destroy {
border-color: var(--red);
background: var(--red-glow);
color: var(--red);
}
.sandbox-flow-arrow {
color: var(--text-dim);
font-size: 20px;
padding: 0 8px;
flex-shrink: 0;
}
@media (max-width: 900px) {
.grid-3, .grid-4 { grid-template-columns: 1fr; }
.grid-2 { grid-template-columns: 1fr; }
}
@media (max-width: 768px) {
.nav { display: none; }
.main { margin-left: 0; }
.hero { padding: 56px 24px 40px; }
.hero h1 { font-size: 2rem; }
.container { padding: 32px 20px 0; }
footer { padding: 24px 20px; }
.sandbox-flow { flex-wrap: wrap; justify-content: center; }
}
</style>
</head>
<body>
<nav class="nav" id="nav">
<div class="nav-logo">
<h2>Minion Engine</h2>
<span>Seu time de AI em Docker</span>
</div>
<div class="nav-group-title">Inicio</div>
<a href="#hero">Visao Geral</a>
<a href="#o-que-sao">O que sao Minions?</a>
<a href="#sandbox">Como funciona o Sandbox</a>
<a href="#instalacao">Instalacao</a>
<div class="nav-group-title">Cenarios de Uso</div>
<a href="#cenario-pr" style="color:var(--cyan);font-weight:700">Analisar uma PR</a>
<a href="#cenario-issue">Resolver Issue</a>
<a href="#cenario-security">Security Audit</a>
<a href="#cenario-refactor">Refactoring Seguro</a>
<a href="#cenario-flaky">Flaky Test Fix</a>
<a href="#cenario-docs">Gerar Documentacao</a>
<div class="nav-group-title">Recursos Avancados</div>
<a href="#typed-outputs">Typed Outputs</a>
<a href="#session-continuity">Session Continuity</a>
<a href="#async-steps">Async Steps</a>
<a href="#script-step">Rhai Scripts</a>
<a href="#chat-sessions">Chat Sessions</a>
<a href="#template-power">Template Step & Accessors</a>
<a href="#collect-reduce">collect/reduce</a>
<a href="#plugins-events">Plugins & Events</a>
<div class="nav-group-title">Pratico</div>
<a href="#setup">Setup no seu projeto</a>
<a href="#comparacao">Com vs Sem Sandbox</a>
<div class="nav-group-title">Referencia</div>
<a href="#cli">CLI Reference</a>
<a href="#arquitetura">Arquitetura</a>
<a href="#faq">FAQ</a>
</nav>
<div class="main">
<header class="hero" id="hero">
<div class="hero-content">
<h1>Minion Engine</h1>
<p>AI workflow engine que torna seu codigo mais robusto, seguro e inteligente — tudo dentro de Docker sandboxes.</p>
<div class="hero-badges">
<span class="badge cyan">Sandbox-First</span>
<span class="badge accent">Docker Isolation</span>
<span class="badge purple">Claude Code AI</span>
<span class="badge green">Self-Healing</span>
<span class="badge orange">YAML Declarativo</span>
<span class="badge yellow">10 Step Types</span>
<span class="badge">Async Steps</span>
<span class="badge">Rhai Scripts</span>
<span class="badge">Plugin System</span>
<span class="badge">Event Bus</span>
</div>
</div>
</header>
<div class="container">
<section>
<div class="section-label">01 — Por que Minion Engine?</div>
<h2>Seu Time de AI Rodando Localmente</h2>
<p>Como o Stripe Minions, mas rodando na sua maquina com Docker sandboxes em vez de AWS. Cada acao roda isolada em um container — seu codigo esta seguro.</p>
<div class="grid-3">
<div class="card">
<div class="card-icon" style="background:var(--accent-glow);color:var(--accent);font-size:20px;">
🐳
</div>
<h4 style="color:var(--accent)">Sandbox-First</h4>
<p>Cada step roda isolado em Docker. Se algo der errado, o container e destruido. Seu codigo original permanece intocado.</p>
</div>
<div class="card">
<div class="card-icon" style="background:var(--purple-glow);color:var(--purple);font-size:20px;">
🤖
</div>
<h4 style="color:var(--purple)">AI-Powered</h4>
<p>Claude Code planeja, implementa, revisa e corrige — autonomamente. Voce define o workflow, os minions executam.</p>
</div>
<div class="card">
<div class="card-icon" style="background:var(--green-glow);color:var(--green);font-size:20px;">
🔄
</div>
<h4 style="color:var(--green)">Self-Healing</h4>
<p>Lint falhou? Testes quebraram? Os minions auto-corrigem e tentam de novo. Gates com retry automatico ate 3 rounds.</p>
</div>
</div>
</section>
<section id="o-que-sao">
<div class="section-label">02 — Conceito</div>
<h2>O que sao Minions?</h2>
<p>Em vez de um unico agente de AI com acesso total ao seu sistema, voce tem multiplos <strong>minions especializados</strong> que trabalham em sandboxes isolados. Se um minion cometer um erro, o container e destruido — impacto zero.</p>
<div class="terminal">
<div class="terminal-bar">
<div class="terminal-dot red"></div>
<div class="terminal-dot yellow"></div>
<div class="terminal-dot green"></div>
<div class="terminal-title">Filosofia: Engine controla, Minions executam</div>
</div>
<div class="terminal-body"><span class="bold">Engine:</span> <span class="dim">"Minion, implemente o plano"</span>
<span class="purple">Minion:</span> <span class="dim">*implementa dentro do container*</span>
<span class="bold">Engine:</span> <span class="dim">"Obrigado. Agora EU rodo lint."</span> <span class="cmt">← deterministico</span>
<span class="bold">Engine:</span> <span class="err">"Lint falhou.</span> <span class="dim">Minion, corrija."</span>
<span class="purple">Minion:</span> <span class="dim">*corrige dentro do container*</span>
<span class="bold">Engine:</span> <span class="ok">"Lint passou.</span> <span class="dim">EU rodo testes."</span>
<span class="bold">Engine:</span> <span class="ok">"Tudo OK.</span> <span class="dim">Copiando resultados de volta."</span>
<span class="bold">Engine:</span> <span class="cyan">"Container destruido.</span> <span class="ok">Seu projeto esta seguro."</span></div>
</div>
<h3>O Fluxo Sandbox</h3>
<div class="sandbox-flow">
<div class="sandbox-flow-node">📁 Seu Projeto</div>
<div class="sandbox-flow-arrow">→</div>
<div class="sandbox-flow-node docker">🐳 Docker Container</div>
<div class="sandbox-flow-arrow">→</div>
<div class="sandbox-flow-node" style="border-color:var(--purple);color:var(--purple);background:var(--purple-glow);">🤖 Minion trabalha</div>
<div class="sandbox-flow-arrow">→</div>
<div class="sandbox-flow-node safe">📦 Resultados copiados</div>
<div class="sandbox-flow-arrow">→</div>
<div class="sandbox-flow-node destroy">🗑 Container destruido</div>
</div>
<div class="tip ok">
<div class="tip-title">Por que isso importa?</div>
<p>AI agents tradicionais tem acesso direto ao seu filesystem. Se o agente deletar algo errado, instalar um pacote malicioso, ou corromper sua build — voce limpa a bagunca manualmente. Com sandbox, o pior que acontece e voce destruir o container e tentar de novo.</p>
</div>
</section>
<section id="sandbox">
<div class="section-label">03 — Docker Sandbox</div>
<h2>🐳 Como Funciona o Sandbox</h2>
<p>Tres modos de sandboxing. Escolha o nivel de isolamento ideal para seu caso.</p>
<div class="grid-3">
<div class="card">
<div class="card-icon" style="background:var(--cyan-glow);color:var(--cyan);font-size:18px;">🐳</div>
<h4 style="color:var(--cyan)">Modo 1: Default (FullWorkflow)</h4>
<p><strong>FullWorkflow</strong> — tudo roda dentro do Docker <strong>por padrao</strong>. O workspace inteiro e copiado para o container. Resultados copiados de volta ao final.</p>
<pre style="margin:12px 0 0;font-size:12px"><span class="cmd">minion execute</span> workflow.yaml
<span class="cmt"># sandbox ON por padrao!</span>
<span class="cmt"># para desativar:</span>
<span class="cmd">minion execute</span> workflow.yaml <span class="flag">--no-sandbox</span></pre>
</div>
<div class="card">
<div class="card-icon" style="background:var(--accent-glow);color:var(--accent);font-size:18px;">🤖</div>
<h4 style="color:var(--accent)">Modo 2: AgentOnly</h4>
<p><strong>config.agent.sandbox: true</strong> — somente steps de AI (<code>agent</code>) rodam isolados. Commands rodam localmente.</p>
<pre style="margin:12px 0 0;font-size:12px"><span class="key">config:</span>
<span class="key">agent:</span>
<span class="key">sandbox:</span> <span class="val">true</span></pre>
</div>
<div class="card">
<div class="card-icon" style="background:var(--purple-glow);color:var(--purple);font-size:18px;">⚙</div>
<h4 style="color:var(--purple)">Modo 3: Devbox</h4>
<p><strong>Full config</strong> — imagem customizada, regras de rede, limites de recursos. Controle total.</p>
<pre style="margin:12px 0 0;font-size:12px"><span class="key">sandbox:</span>
<span class="key">enabled:</span> <span class="val">true</span>
<span class="key">image:</span> <span class="str">"node:20"</span></pre>
</div>
</div>
<h3>Configuracao Completa do Devbox</h3>
<pre><span class="key">config:</span>
<span class="key">global:</span>
<span class="key">sandbox:</span>
<span class="key">enabled:</span> <span class="val">true</span>
<span class="key">image:</span> <span class="str">"minion-sandbox:latest"</span> <span class="cmt"># imagem com git,gh,node,cargo,claude</span>
<span class="cmt"># Credenciais: env vars do host forwardados ao container</span>
<span class="cmt"># Se omitido, auto-forward: ANTHROPIC_API_KEY, OPENAI_API_KEY, GH_TOKEN, GITHUB_TOKEN</span>
<span class="key">env:</span>
- <span class="str">ANTHROPIC_API_KEY</span>
- <span class="str">GH_TOKEN</span>
- <span class="str">NPM_TOKEN</span>
<span class="cmt"># Volumes montados read-only (credenciais do host)</span>
<span class="cmt"># Se omitido, auto-monta: ~/.config/gh, ~/.claude, ~/.ssh, ~/.gitconfig</span>
<span class="key">volumes:</span>
- <span class="str">"~/.config/gh:/root/.config/gh:ro"</span>
- <span class="str">"~/.claude:/root/.claude:ro"</span>
- <span class="str">"~/.ssh:/root/.ssh:ro"</span>
- <span class="str">"~/.gitconfig:/root/.gitconfig:ro"</span>
<span class="cmt"># Excluir do workspace copy (economiza tempo)</span>
<span class="key">exclude:</span>
- <span class="str">node_modules</span>
- <span class="str">target</span>
- <span class="str">.git/objects</span>
<span class="key">dns:</span> <span class="val">["8.8.8.8"]</span> <span class="cmt"># DNS confiavel</span>
<span class="key">network:</span>
<span class="key">allow:</span> <span class="val">["api.anthropic.com", "api.github.com"]</span> <span class="cmt"># whitelist</span>
<span class="key">deny:</span> <span class="val">["0.0.0.0/0"]</span> <span class="cmt"># bloqueia tudo mais</span>
<span class="key">resources:</span>
<span class="key">cpus:</span> <span class="val">2.0</span>
<span class="key">memory:</span> <span class="str">"4g"</span></pre>
<div class="tip docker">
<div class="tip-title">🐳 Zero-Config Smart Defaults</div>
<p>Se voce nao especificar <code>env:</code> ou <code>volumes:</code>, o engine faz tudo automaticamente: forwarda <code>ANTHROPIC_API_KEY</code>, <code>GH_TOKEN</code>, monta <code>~/.config/gh</code>, <code>~/.ssh</code> e <code>~/.gitconfig</code> (read-only) e <code>~/.claude</code> (read-write, para sessoes do Claude CLI). O <code>gh</code>, <code>claude</code>, <code>git push</code> e API calls funcionam out-of-the-box.</p>
</div>
<h3>Build da Imagem de Referencia</h3>
<pre><span class="cmt"># Inclui: git, gh, jq, curl, node, npm, cargo, clippy, python3, claude CLI</span>
<span class="cmd">docker build</span> -f Dockerfile.sandbox -t minion-sandbox:latest .</pre>
</section>
<section id="instalacao">
<div class="section-label">04 — Instalacao</div>
<h2>Instalacao Rapida</h2>
<div class="grid-2">
<div class="card">
<h4 style="color:var(--cyan)">cargo install (recomendado)</h4>
<p>Instala via crates.io — requer Rust 1.75+.</p>
<pre style="margin:12px 0 0"><span class="cmd">cargo install</span> minion-engine
<span class="cmd">minion</span> <span class="flag">--version</span></pre>
</div>
<div class="card">
<h4 style="color:var(--green)">Build from source</h4>
<p>Clone o repositorio e compile.</p>
<pre style="margin:12px 0 0"><span class="cmd">git clone</span> <span class="str">https://github.com/
allanbrunobr/minion-engine.git</span>
<span class="cmd">cd</span> minion-engine
<span class="cmd">cargo install</span> <span class="flag">--path .</span></pre>
</div>
</div>
<div class="tip">
<div class="tip-title">Pre-requisitos</div>
<p><strong>Docker Desktop 4.40+</strong> (sandbox e ON por padrao). <code>claude</code> CLI instalado e autenticado (para steps agent). <code>gh</code> CLI (para workflows GitHub). <code>ANTHROPIC_API_KEY</code> (para steps chat).</p>
</div>
</section>
<section id="cenario-pr">
<div class="section-label">05 — Cenario 1</div>
<h2>Entrei num projeto — quero analisar uma PR</h2>
<p>Voce acabou de entrar no time e quer revisar a PR #142. O minion analisa arquivo por arquivo, em paralelo, dentro de um sandbox.</p>
<div class="terminal">
<div class="terminal-bar">
<div class="terminal-dot red"></div>
<div class="terminal-dot yellow"></div>
<div class="terminal-dot green"></div>
<div class="terminal-title">Terminal — ~/projects/my-saas</div>
</div>
<div class="terminal-body"><span class="prompt">$</span> <span class="cmd">cd</span> ~/projects/my-saas
<span class="prompt">$</span> <span class="cmd">minion execute</span> code-review <span class="flag">--verbose</span> <span class="flag">--</span> 142
<span class="cyan">🐳</span> <span class="bold">Sandbox created</span> <span class="dim">(node:20, 2 CPUs, 4GB RAM)</span>
<span class="dim"> workspace copied to /workspace</span>
<span class="ok">✓</span> fetch_pr_diff <span class="dim">1.4s</span> <span class="dim">cmd</span> <span class="dim">gh pr diff 142</span>
<span class="ok">✓</span> list_changed_files <span class="dim">0.3s</span> <span class="dim">cmd</span>
<span class="purple">◉</span> review_files <span class="dim">28.7s</span> <span class="purple">map(4)</span> <span class="dim">8 files, concurrency:4</span>
<span class="ok">✓</span> src/api/auth.ts <span class="dim">6.2s</span> <span class="purple">agent</span> <span class="err">2 critical</span>
<span class="ok">✓</span> src/api/users.ts <span class="dim">5.8s</span> <span class="purple">agent</span> <span class="warn">1 medium</span>
<span class="ok">✓</span> src/lib/db.ts <span class="dim">7.1s</span> <span class="purple">agent</span> <span class="ok">clean</span>
<span class="ok">✓</span> src/lib/cache.ts <span class="dim">4.3s</span> <span class="purple">agent</span> <span class="warn">1 low</span>
<span class="ok">✓</span> <span class="dim">... +4 files</span>
<span class="info">●</span> consolidate_report <span class="dim">8.3s</span> <span class="info">chat</span> <span class="dim">Critical → High → Medium → Low</span>
<span class="ok">✓</span> post_pr_comment <span class="dim">1.1s</span> <span class="dim">cmd</span> <span class="dim">gh pr comment 142</span>
<span class="ok">✓</span> <span class="bold">Complete</span> in <span class="cyan">40.1s</span> <span class="dim">—</span> <span class="purple">12.3k tokens</span> <span class="dim">—</span> <span class="ok">$0.06</span>
<span class="cyan">🐳</span> <span class="dim">Results copied back. Container destroyed.</span></div>
</div>
<h3>O que aconteceu passo a passo</h3>
<div class="flow-steps">
<div class="flow-step">
<div class="flow-step-num">1</div>
<h4>🐳 Container Docker criado, workspace copiado</h4>
<p>Todo o diretorio do projeto e copiado para <code>/workspace</code> dentro do container.</p>
</div>
<div class="flow-step">
<div class="flow-step-num green">2</div>
<h4><code>gh pr diff 142</code> → busca o diff da PR</h4>
<p>Roda dentro do container. O diff completo e salvo no Context Store.</p>
</div>
<div class="flow-step">
<div class="flow-step-num accent">3</div>
<h4>Lista arquivos alterados</h4>
<p>Extrai a lista de arquivos do diff para iterar depois.</p>
</div>
<div class="flow-step">
<div class="flow-step-num purple">4</div>
<h4>Para CADA arquivo (paralelo, concurrency:4), AI revisa</h4>
<p>Bugs, seguranca, performance, boas praticas. Cada review roda em paralelo com ate 4 minions simultaneos.</p>
</div>
<div class="flow-step">
<div class="flow-step-num accent">5</div>
<h4>Consolida em relatorio (Critical → High → Medium → Low)</h4>
<p>Um step <code>chat</code> (barato e rapido) sintetiza todas as reviews em um relatorio ordenado por severidade.</p>
</div>
<div class="flow-step">
<div class="flow-step-num green">6</div>
<h4>Posta como comentario na PR</h4>
<p><code>gh pr comment 142 --body "..."</code> — o relatorio aparece direto no GitHub.</p>
</div>
<div class="flow-step">
<div class="flow-step-num red">7</div>
<h4>📦 Resultados copiados de volta, 🗑 container destruido</h4>
<p>Nada fica para tras. Seu projeto original nao foi tocado.</p>
</div>
</div>
<h3>YAML do Workflow: <code>code-review.yaml</code></h3>
<pre><span class="key">name:</span> <span class="val">code-review</span>
<span class="key">version:</span> <span class="val">1</span>
<span class="key">description:</span> <span class="str">"Review a PR file-by-file for bugs, security, and performance"</span>
<span class="key">config:</span>
<span class="key">global:</span>
<span class="key">timeout:</span> <span class="val">300s</span>
<span class="key">sandbox:</span>
<span class="key">enabled:</span> <span class="val">true</span>
<span class="key">image:</span> <span class="str">"node:20"</span>
<span class="key">agent:</span>
<span class="key">model:</span> <span class="val">claude-sonnet-4-20250514</span>
<span class="key">scopes:</span>
<span class="key">review_single_file:</span> <span class="cmt"># scope reutilizavel</span>
<span class="key">steps:</span>
<span class="key">- name:</span> <span class="val">review</span>
<span class="key">type:</span> <span class="val">agent</span>
<span class="key">prompt:</span> <span class="str">|</span>
<span class="str">Review {{ scope.value }} from this PR diff for:</span>
<span class="str">1. Bugs and logic errors</span>
<span class="str">2. Security vulnerabilities</span>
<span class="str">3. Performance issues</span>
<span class="str">4. Best practices</span>
<span class="key">steps:</span>
<span class="key">- name:</span> <span class="val">fetch_pr_diff</span>
<span class="key">type:</span> <span class="val">cmd</span>
<span class="key">command:</span> <span class="str">"gh pr diff {{ target }}"</span>
<span class="key">- name:</span> <span class="val">list_changed_files</span>
<span class="key">type:</span> <span class="val">cmd</span>
<span class="key">command:</span> <span class="str">"gh pr diff {{ target }} --name-only"</span>
<span class="key">- name:</span> <span class="val">review_files</span> <span class="cmt"># map paralelo!</span>
<span class="key">type:</span> <span class="val">map</span>
<span class="key">scope:</span> <span class="val">review_single_file</span>
<span class="key">items:</span> <span class="str">"{{ steps.list_changed_files.stdout | split(pat='\n') }}"</span>
<span class="key">concurrency:</span> <span class="val">4</span>
<span class="key">- name:</span> <span class="val">consolidate_report</span>
<span class="key">type:</span> <span class="val">chat</span>
<span class="key">prompt:</span> <span class="str">|</span>
<span class="str">Consolidate these reviews into a report ordered by severity:</span>
<span class="str">{{ steps.review_files.outputs | join(sep='\n---\n') }}</span>
<span class="key">- name:</span> <span class="val">post_pr_comment</span>
<span class="key">type:</span> <span class="val">cmd</span>
<span class="key">command:</span> <span class="str">"gh pr comment {{ target }} --body '{{ steps.consolidate_report.response }}'"</span></pre>
</section>
<section id="cenario-issue">
<div class="section-label">06 — Cenario 2</div>
<h2>Preciso resolver uma issue do GitHub</h2>
<p>A issue #247 descreve um bug. O minion le a issue, planeja, implementa, passa por lint gate e test gate, e abre um PR — tudo dentro do sandbox.</p>
<div class="terminal">
<div class="terminal-bar">
<div class="terminal-dot red"></div>
<div class="terminal-dot yellow"></div>
<div class="terminal-dot green"></div>
<div class="terminal-title">Terminal — Fix Issue #247</div>
</div>
<div class="terminal-body"><span class="prompt">$</span> <span class="cmd">minion execute</span> fix-issue <span class="flag">--verbose</span> <span class="flag">--</span> 247
<span class="cyan">🐳</span> <span class="bold">Sandbox created</span> <span class="dim">(node:20, 2 CPUs, 4GB RAM)</span>
<span class="ok">✓</span> fetch_issue <span class="dim">1.2s</span> <span class="dim">cmd</span> <span class="dim">gh issue view 247</span>
<span class="ok">✓</span> find_relevant_files <span class="dim">0.8s</span> <span class="dim">cmd</span>
<span class="purple">◉</span> plan <span class="dim">12.3s</span> <span class="purple">agent</span> <span class="dim">2.1k tokens</span>
<span class="ok">✓</span> validate_plan <span class="dim">0.0s</span> <span class="dim">gate</span> <span class="ok">plan is substantive</span>
<span class="purple">◉</span> implement <span class="dim">45.7s</span> <span class="purple">agent</span> <span class="dim">8.4k tokens</span>
<span class="orange">↻</span> lint_gate <span class="dim">18.2s</span> <span class="orange">repeat(2/3)</span> <span class="dim">failed round 1, fixed round 2</span>
<span class="ok">✓</span> test_gate <span class="dim">34.1s</span> <span class="ok">repeat(1/2)</span> <span class="ok">passed first try</span>
<span class="ok">✓</span> create_branch <span class="dim">0.2s</span> <span class="dim">cmd</span>
<span class="ok">✓</span> commit_and_push <span class="dim">2.4s</span> <span class="dim">cmd</span>
<span class="ok">✓</span> create_pr <span class="dim">1.8s</span> <span class="dim">cmd</span>
<span class="ok">✓</span> <span class="bold">Complete</span> in <span class="cyan">117.2s</span> <span class="dim">—</span> <span class="purple">10.5k tokens</span> <span class="dim">—</span> <span class="ok">$0.08</span>
<span class="info">PR: https://github.com/org/repo/pull/42</span>
<span class="cyan">🐳</span> <span class="dim">Results copied back. Container destroyed.</span></div>
</div>
<h3>Pipeline completo</h3>
<div class="flow-steps">
<div class="flow-step">
<div class="flow-step-num">1</div>
<h4>🐳 Sandbox criado</h4>
<p>Container Docker sobe com a imagem configurada. Workspace copiado.</p>
</div>
<div class="flow-step">
<div class="flow-step-num green">2</div>
<h4><code>gh issue view 247</code> — le a issue</h4>
<p>O titulo, corpo e labels da issue sao capturados para contexto.</p>
</div>
<div class="flow-step">
<div class="flow-step-num accent">3</div>
<h4>Encontra arquivos relevantes a partir do corpo da issue</h4>
<p>Busca por nomes de arquivo, classes ou funcoes mencionados na issue.</p>
</div>
<div class="flow-step">
<div class="flow-step-num purple">4</div>
<h4>AI planeja a implementacao</h4>
<p>Step <code>agent</code> cria um plano detalhado com os arquivos a modificar.</p>
</div>
<div class="flow-step">
<div class="flow-step-num yellow">5</div>
<h4>Gate valida que o plano e substantivo</h4>
<p>Se o plano for vazio ou generico demais, o workflow falha antes de gastar tokens implementando.</p>
</div>
<div class="flow-step">
<div class="flow-step-num purple">6</div>
<h4>AI implementa o fix</h4>
<p>Claude Code escreve o codigo dentro do container, seguindo o plano aprovado.</p>
</div>
<div class="flow-step">
<div class="flow-step-num orange">7</div>
<h4>Lint Gate (3 rounds): lint → falhou → AI corrige → lint de novo</h4>
<p><code>repeat</code> com <code>max_iterations: 3</code>. Se lint passar, faz <code>break</code>. Se falhar, o minion corrige e tenta de novo.</p>
</div>
<div class="flow-step">
<div class="flow-step-num orange">8</div>
<h4>Test Gate (2 rounds): test → falhou → AI corrige → test de novo</h4>
<p>Mesma logica do lint gate, mas rodando <code>npm test</code> ou equivalente.</p>
</div>
<div class="flow-step">
<div class="flow-step-num green">9</div>
<h4>Cria branch, commita, pusha, abre PR</h4>
<p>Steps <code>cmd</code> deterministicos: <code>git checkout -b</code>, <code>git commit</code>, <code>git push</code>, <code>gh pr create</code>.</p>
</div>
<div class="flow-step">
<div class="flow-step-num red">10</div>
<h4>📦 Resultados copiados de volta, 🗑 container destruido</h4>
<p>O PR ja esta no GitHub. O container e descartado.</p>
</div>
</div>
</section>
<section id="cenario-security">
<div class="section-label">07 — Cenario 3</div>
<h2>Security Audit do meu projeto</h2>
<p>Revisao arquivo por arquivo com checklist OWASP, consolidada em um relatorio para o CISO.</p>
<div class="recipe-card red-border">
<h3>🛡 Security Audit <span class="recipe-badge">OWASP</span></h3>
<p>Analise de seguranca profunda. Cada arquivo e revisado individualmente em paralelo, depois consolidado em um relatorio unico com severidade e recomendacoes.</p>
<ul class="recipe-steps">
<li>🐳 Sandbox criado com network restrita (apenas APIs necessarias)</li>
<li>Lista todos os arquivos em <code>src/api/</code></li>
<li>Para CADA arquivo (paralelo, concurrency:4), AI analisa OWASP Top 10</li>
<li>Injection, broken auth, sensitive data exposure, XXE, broken access control...</li>
<li>Consolida em relatorio de CISO com severidade Critical/High/Medium/Low</li>
<li>Salva como <code>security-report.md</code></li>
<li>🗑 Container destruido</li>
</ul>
</div>
<div class="terminal">
<div class="terminal-bar">
<div class="terminal-dot red"></div>
<div class="terminal-dot yellow"></div>
<div class="terminal-dot green"></div>
<div class="terminal-title">Terminal — Security Audit</div>
</div>
<div class="terminal-body"><span class="prompt">$</span> <span class="cmd">minion execute</span> security-audit \
<span class="flag">--args</span> <span class="str">'{"path": "src/api/"}'</span>
<span class="cyan">🐳</span> <span class="bold">Sandbox created</span> <span class="dim">(node:20, network: api.anthropic.com only)</span>
<span class="ok">✓</span> list_files <span class="dim">0.2s</span> <span class="dim">cmd</span> <span class="dim">find src/api/ -name '*.ts'</span>
<span class="purple">◉</span> audit_files <span class="dim">52.4s</span> <span class="purple">map(4)</span> <span class="dim">12 files, concurrency:4</span>
<span class="err">●</span> auth.ts <span class="dim">8.2s</span> <span class="err">3 critical findings</span>
<span class="warn">●</span> payments.ts <span class="dim">7.1s</span> <span class="warn">2 high findings</span>
<span class="ok">●</span> health.ts <span class="dim">3.2s</span> <span class="ok">clean</span>
<span class="dim"> ... +9 files</span>
<span class="info">●</span> consolidate <span class="dim">6.8s</span> <span class="info">chat</span> <span class="dim">CISO report generated</span>
<span class="ok">✓</span> save_report <span class="dim">0.1s</span> <span class="dim">cmd</span> <span class="dim">security-report.md</span>
<span class="ok">✓</span> <span class="bold">Complete</span> in <span class="cyan">59.8s</span> <span class="dim">—</span> <span class="purple">18.2k tokens</span> <span class="dim">—</span> <span class="ok">$0.09</span>
<span class="cyan">🐳</span> <span class="dim">Container destroyed.</span></div>
</div>
</section>
<section id="cenario-refactor">
<div class="section-label">08 — Cenario 4</div>
<h2>Refactoring Seguro</h2>
<p>Extrair logica, renomear, reorganizar — com lint gate e test gate garantindo que nada quebrou.</p>
<div class="recipe-card purple-border">
<h3>🔧 Refactoring com Safety Net <span class="recipe-badge">sandbox</span></h3>
<p>O minion usa <code>chat</code> (barato) para planejar e <code>agent</code> para implementar. Gates de lint e test garantem que o refactoring nao quebrou nada.</p>
<ul class="recipe-steps">
<li>🐳 Sandbox criado</li>
<li><code>chat</code> LLM planeja o refactoring (rapido e barato)</li>
<li><code>agent</code> implementa as mudancas</li>
<li>Lint gate (3 rounds): se falhar, AI corrige</li>
<li>Test gate (2 rounds): se falhar, AI corrige</li>
<li>Cria branch e PR com descricao detalhada</li>
<li>🗑 Container destruido — se algo deu errado, nenhum dano</li>
</ul>
</div>
<div class="terminal">
<div class="terminal-bar">
<div class="terminal-dot red"></div>
<div class="terminal-dot yellow"></div>
<div class="terminal-dot green"></div>
<div class="terminal-title">Terminal — Refactoring</div>
</div>
<div class="terminal-body"><span class="prompt">$</span> <span class="cmd">minion execute</span> refactor \
<span class="flag">--</span> <span class="str">"extract auth logic from UserController"</span>
<span class="cyan">🐳</span> <span class="bold">Sandbox created</span>
<span class="info">●</span> plan_refactor <span class="dim">4.2s</span> <span class="info">chat</span> <span class="dim">1.2k tokens (barato!)</span>
<span class="purple">◉</span> implement <span class="dim">38.5s</span> <span class="purple">agent</span> <span class="dim">6.8k tokens</span>
<span class="ok">✓</span> lint_gate <span class="dim">12.1s</span> <span class="ok">repeat(1/3)</span>
<span class="ok">✓</span> test_gate <span class="dim">28.3s</span> <span class="ok">repeat(1/2)</span>
<span class="ok">✓</span> create_pr <span class="dim">3.2s</span> <span class="dim">cmd</span>
<span class="ok">✓</span> <span class="bold">Complete</span> in <span class="cyan">86.3s</span> <span class="dim">—</span> <span class="purple">8.0k tokens</span> <span class="dim">—</span> <span class="ok">$0.05</span>
<span class="info">PR: https://github.com/org/repo/pull/43</span>
<span class="cyan">🐳</span> <span class="dim">Container destroyed.</span></div>
</div>
<div class="tip ok">
<div class="tip-title">Por que chat + agent?</div>
<p>Usar <code>chat</code> para planejamento e ~10x mais barato que <code>agent</code>. O <code>chat</code> nao tem acesso ao filesystem (nao precisa), e o <code>agent</code> so e chamado quando realmente precisa escrever codigo. Economia inteligente de tokens.</p>
</div>
</section>
<section id="cenario-flaky">
<div class="section-label">09 — Cenario 5</div>
<h2>Flaky Test Fix</h2>
<p>Aquele teste que as vezes passa e as vezes falha. O minion analisa, diagnostica e corrige.</p>
<div class="recipe-card yellow-border">
<h3>🎯 Flaky Test Diagnosis & Fix <span class="recipe-badge">auto-fix</span></h3>
<p>Roda o teste multiplas vezes para confirmar flakiness, analisa o padrao de falha, e implementa o fix.</p>
<ul class="recipe-steps">
<li>🐳 Sandbox criado</li>
<li>Roda o teste 5 vezes para coletar padroes de falha</li>
<li>AI analisa: race condition? timeout? state leaking? mock instavel?</li>
<li>AI implementa o fix</li>
<li>Roda o teste 10 vezes para confirmar estabilidade</li>
<li>Gate: se passou 10/10, cria PR</li>
<li>🗑 Container destruido</li>
</ul>
</div>
<div class="terminal">
<div class="terminal-bar">
<div class="terminal-dot red"></div>
<div class="terminal-dot yellow"></div>
<div class="terminal-dot green"></div>
<div class="terminal-title">Terminal — Flaky Test Fix</div>
</div>
<div class="terminal-body"><span class="prompt">$</span> <span class="cmd">minion execute</span> flaky-test-fix \
<span class="flag">--</span> <span class="str">"tests/api/payment.test.ts"</span>
<span class="cyan">🐳</span> <span class="bold">Sandbox created</span>
<span class="ok">✓</span> run_5x <span class="dim">18.5s</span> <span class="dim">cmd</span> <span class="warn">3/5 passed (flaky confirmed)</span>
<span class="purple">◉</span> diagnose <span class="dim">8.2s</span> <span class="purple">agent</span> <span class="dim">race condition in async setup</span>
<span class="purple">◉</span> fix <span class="dim">22.1s</span> <span class="purple">agent</span> <span class="dim">added proper await + cleanup</span>
<span class="ok">✓</span> run_10x <span class="dim">35.4s</span> <span class="dim">cmd</span> <span class="ok">10/10 passed</span>
<span class="ok">✓</span> create_pr <span class="dim">2.8s</span> <span class="dim">cmd</span>
<span class="ok">✓</span> <span class="bold">Complete</span> in <span class="cyan">87.0s</span> <span class="dim">—</span> <span class="purple">5.1k tokens</span> <span class="dim">—</span> <span class="ok">$0.03</span>
<span class="cyan">🐳</span> <span class="dim">Container destroyed.</span></div>
</div>
</section>
<section id="cenario-docs">
<div class="section-label">10 — Cenario 6</div>
<h2>Gerar Documentacao</h2>
<p>O minion analisa cada modulo do projeto e gera documentacao atualizada automaticamente.</p>
<div class="recipe-card green-border">
<h3>📝 Generate Documentation <span class="recipe-badge">auto-docs</span></h3>
<p>Analisa a estrutura do projeto, gera docs para cada modulo, e consolida em um README ou site de documentacao.</p>
<ul class="recipe-steps">
<li>🐳 Sandbox criado</li>
<li>Mapeia a estrutura do projeto (modulos, exports, types)</li>
<li>Para CADA modulo (paralelo), AI gera documentacao</li>
<li>Consolida em docs/ com indice e navegacao</li>
<li>Cria PR com a documentacao atualizada</li>
<li>🗑 Container destruido</li>
</ul>
</div>
<div class="terminal">
<div class="terminal-bar">
<div class="terminal-dot red"></div>
<div class="terminal-dot yellow"></div>
<div class="terminal-dot green"></div>
<div class="terminal-title">Terminal — Generate Docs</div>
</div>
<div class="terminal-body"><span class="prompt">$</span> <span class="cmd">minion execute</span> generate-docs
<span class="cyan">🐳</span> <span class="bold">Sandbox created</span>
<span class="ok">✓</span> map_project <span class="dim">0.6s</span> <span class="dim">cmd</span> <span class="dim">14 modules found</span>
<span class="purple">◉</span> generate_docs <span class="dim">42.3s</span> <span class="purple">map(4)</span> <span class="dim">14 modules, concurrency:4</span>
<span class="info">●</span> create_index <span class="dim">5.1s</span> <span class="info">chat</span> <span class="dim">index + navigation</span>
<span class="ok">✓</span> create_pr <span class="dim">2.4s</span> <span class="dim">cmd</span>
<span class="ok">✓</span> <span class="bold">Complete</span> in <span class="cyan">50.4s</span> <span class="dim">—</span> <span class="purple">22.1k tokens</span> <span class="dim">—</span> <span class="ok">$0.11</span>
<span class="cyan">🐳</span> <span class="dim">Container destroyed.</span></div>
</div>
</section>
<section id="typed-outputs">
<div class="section-label">11 — Recursos Avancados</div>
<h2>Typed Output Parsing</h2>
<p>Em vez de tratar tudo como string, declare <code>output_type</code> em qualquer step e o engine parseia automaticamente o resultado.</p>
<div class="terminal">
<div class="terminal-bar">
<div class="terminal-dot red"></div>
<div class="terminal-dot yellow"></div>
<div class="terminal-dot green"></div>
<span class="terminal-title">workflow.yaml — output_type em acao</span>
</div>
<div class="terminal-body"><span class="dim">steps:</span>
- name: get_metrics
type: cmd
run: "curl -s https://api.example.com/metrics"
<span class="cyan">output_type: json</span> <span class="dim"># json | integer | lines | boolean | text</span>
- name: count_files
type: cmd
run: "find src -name '*.rs' | wc -l"
<span class="cyan">output_type: integer</span>
- name: check_coverage
type: cmd
run: "cargo tarpaulin --print-summary | grep 'coverage'"
<span class="cyan">output_type: lines</span>
- name: report
type: agent
prompt: |
<span class="dim"># Acesse campos tipados diretamente:</span>
Metricas: <span class="green">{{ get_metrics.output.cpu_usage }}</span>
Total de arquivos: <span class="green">{{ count_files.output }}</span> <span class="dim"># ja e i64, nao string</span>
Linhas de coverage: <span class="green">{{ check_coverage.output[0] }}</span></div>
</div>
<div class="info-card" style="border-color:var(--cyan);">
<strong style="color:var(--cyan)">5 tipos suportados:</strong>
<code>json</code> → serde_json::Value com acesso por dot notation •
<code>integer</code> → i64 •
<code>lines</code> → Vec<String> com acesso por indice •
<code>boolean</code> → true/false •
<code>text</code> → String (default)
</div>
</section>
<section id="session-continuity">
<div class="section-label">12 — Recursos Avancados</div>
<h2>Session Continuity — Resume & Fork</h2>
<p>O Claude Code mantém sessões. Com <code>resume</code> e <code>fork_session</code>, agentes continuam de onde pararam ou bifurcam investigações paralelas.</p>
<div class="terminal">
<div class="terminal-bar">
<div class="terminal-dot red"></div>
<div class="terminal-dot yellow"></div>
<div class="terminal-dot green"></div>
<span class="terminal-title">session-workflow.yaml — resume + fork</span>
</div>
<div class="terminal-body"><span class="dim">steps:</span>
- name: planner
type: agent
prompt: "Analise o projeto e crie um plano de refactoring"
- name: implementer
type: agent
prompt: "Execute o plano"
config:
<span class="cyan">resume: planner</span> <span class="dim"># continua a sessao do planner</span>
<span class="dim"># Fork: 2 agentes exploram abordagens diferentes</span>
- name: approach_a
type: agent
prompt: "Implemente usando Strategy pattern"
config:
<span class="purple">fork_session: planner</span> <span class="dim"># mesma base, branch A</span>
- name: approach_b
type: agent
prompt: "Implemente usando State machine"
config:
<span class="purple">fork_session: planner</span> <span class="dim"># mesma base, branch B</span>
<span class="dim"># Acesse session_id em templates:</span>
- name: compare
type: agent
prompt: |
Compare as sessoes:
A: <span class="green">{{ approach_a.session_id }}</span>
B: <span class="green">{{ approach_b.session_id }}</span></div>
</div>
</section>
<section id="async-steps">
<div class="section-label">13 — Recursos Avancados</div>
<h2>Async Steps — Background Execution</h2>
<p>Qualquer step pode rodar em background com <code>async_exec: true</code>. O engine faz await automaticamente quando voce referencia o output.</p>
<div class="terminal">
<div class="terminal-bar">
<div class="terminal-dot red"></div>
<div class="terminal-dot yellow"></div>
<div class="terminal-dot green"></div>
<span class="terminal-title">async-workflow.yaml — 3 tarefas em paralelo</span>
</div>
<div class="terminal-body"><span class="dim">steps:</span>
<span class="dim"># Dispara 3 steps simultaneamente:</span>
- name: lint
type: cmd
run: "cargo clippy 2>&1"
<span class="orange">async_exec: true</span>
- name: test
type: cmd
run: "cargo test 2>&1"
<span class="orange">async_exec: true</span>
- name: audit
type: cmd
run: "cargo audit 2>&1"
<span class="orange">async_exec: true</span>
<span class="dim"># Quando voce referencia o output, o engine faz await automatico:</span>
- name: report
type: agent
prompt: |
Resultados (auto-awaited):
Lint: <span class="green">{{ lint.output }}</span> <span class="dim"># ← await lint aqui</span>
Test: <span class="green">{{ test.output }}</span> <span class="dim"># ← await test aqui</span>
Audit: <span class="green">{{ audit.output }}</span> <span class="dim"># ← await audit aqui</span>
<span class="dim"># No final do workflow, qualquer step async pendente</span>
<span class="dim"># e await'd automaticamente (nada se perde).</span></div>
</div>
<div class="info-card" style="border-color:var(--orange);">
<strong style="color:var(--orange)">Como funciona:</strong>
1. <code>async_exec: true</code> → <code>tokio::spawn</code> imediato •
2. Output referenciado em template → auto-await transparente •
3. Final do workflow → await-all de tudo que ficou pendente
</div>
</section>
<section id="script-step">
<div class="section-label">14 — Recursos Avancados</div>
<h2>Script Step — Rhai Inline</h2>
<p>Transformacoes de dados sem spawnar processos externos. O step <code>script</code> usa <a href="https://rhai.rs" style="color:var(--accent)">Rhai</a>, uma linguagem de scripting nativa em Rust com sandbox de 1M operacoes.</p>
<div class="terminal">
<div class="terminal-bar">
<div class="terminal-dot red"></div>
<div class="terminal-dot yellow"></div>
<div class="terminal-dot green"></div>
<span class="terminal-title">script-workflow.yaml — transformacao inline</span>
</div>
<div class="terminal-body"><span class="dim">steps:</span>
- name: get_data
type: cmd
run: 'echo "alice,bob,charlie"'
- name: transform
<span class="purple">type: script</span>
run: |
<span class="dim">// Leia do contexto</span>
let raw = <span class="cyan">ctx_get</span>("get_data");
let names = raw.split(",");
let result = [];
for name in names {
result.push(name.to_upper());
}
<span class="dim">// Escreva de volta no contexto</span>
<span class="cyan">ctx_set</span>("uppercase_names", result);
<span class="dim">// O ultimo valor e o output do step</span>
result.len()
- name: use_result
type: agent
prompt: |
Transformou <span class="green">{{ transform.output }}</span> nomes.
<span class="dim"># ctx_set tambem injeta no contexto global</span></div>
</div>
<div class="info-card" style="border-color:var(--purple);">
<strong style="color:var(--purple)">API Rhai disponivel:</strong>
<code>ctx_get(key)</code> → le qualquer valor do contexto •
<code>ctx_set(key, value)</code> → escreve no contexto •
Limit de 1M operacoes • Sem acesso a filesystem/rede (sandboxed por design)
</div>
</section>
<section id="chat-sessions">
<div class="section-label">15 — Recursos Avancados</div>
<h2>Chat Sessions & Truncation</h2>
<p>Steps <code>chat</code> agora mantêm historico de conversa entre chamadas. Configure estrategias de truncation para nao estourar a context window.</p>
<div class="terminal">
<div class="terminal-bar">
<div class="terminal-dot red"></div>
<div class="terminal-dot yellow"></div>
<div class="terminal-dot green"></div>
<span class="terminal-title">chat-session.yaml — multi-turn com truncation</span>
</div>
<div class="terminal-body"><span class="dim">scopes:</span>
interview:
steps:
- name: ask
type: chat
prompt: "{{ scope_value }}"
config:
model: claude-sonnet-4-20250514
<span class="green">session: "main_chat"</span> <span class="dim"># nome da sessao</span>
<span class="green">truncation_strategy: last</span> <span class="dim"># manter ultimas N msgs</span>
<span class="green">truncation_count: 20</span> <span class="dim"># N = 20</span>
<span class="dim">steps:</span>
- name: q1
type: call
scope: interview
initial_value: "O que e o projeto?"
- name: q2
type: call
scope: interview
initial_value: "Quais sao os riscos?"
<span class="dim"># q2 tem acesso automatico ao historico de q1</span>
- name: q3
type: call
scope: interview
initial_value: "Resuma tudo."
<span class="dim"># q3 tem q1 + q2 no historico (truncado a 20 msgs)</span></div>
</div>
<div class="info-card" style="border-color:var(--green);">
<strong style="color:var(--green)">5 estrategias de truncation:</strong>
<code>none</code> → manter tudo •
<code>last(N)</code> → ultimas N mensagens •
<code>first(N)</code> → primeiras N •
<code>first_last(F,L)</code> → primeiras F + ultimas L •
<code>sliding_window(T)</code> → caber em T tokens
</div>
</section>
<section id="template-power">
<div class="section-label">16 — Recursos Avancados</div>
<h2>Templates: Step Type + Accessors (?, !, from)</h2>
<p>O <code>template</code> e um dos 10 step types do engine. Entenda <strong>por que ele existe</strong> e como os accessors <code>?</code>, <code>!</code>, <code>from()</code> funcionam.</p>
<h3>Por que <code>type: template</code> existe?</h3>
<div class="tip ok">
<div class="tip-title">O problema que template resolve</div>
<p>Quando um prompt de AI fica grande (50+ linhas com instrucoes, contexto de multiplos steps, condicionais), colocar tudo inline no YAML vira um pesadelo de manutencao. E quando voce quer <strong>reutilizar o mesmo prompt</strong> em workflows diferentes, tem que copiar e colar.</p>
</div>
<p>O step <code>template</code> resolve isso: ele renderiza um arquivo <code>.md.tera</code> externo com <strong>zero custo de API</strong> — roda 100% localmente. O resultado pode ser usado como input para um step <code>agent</code> ou <code>chat</code> posterior.</p>
<div class="grid-2">
<div class="card" style="border-color:var(--red);">
<h4 style="color:var(--red)">❌ Sem template (prompt inline)</h4>
<pre style="font-size:11px;margin:8px 0 0;">- name: implement
type: agent
prompt: |
Implemente o plano abaixo.
## Plano
{{ steps.plan.response }}
## Regras do Projeto
{% if steps.rules is defined %}
{{ steps.rules.stdout }}
{% endif %}
## Instrucoes
- Nao rode testes
- Nao crie arquivos extras
- Siga convencoes do projeto
... <span class="dim">(50+ linhas de YAML)</span></pre>
</div>
<div class="card" style="border-color:var(--green);">
<h4 style="color:var(--green)">✅ Com template (arquivo separado)</h4>
<pre style="font-size:11px;margin:8px 0 0;">- name: build_prompt
type: template <span class="dim"># zero custo</span>
<span class="dim"># renderiza prompts/build_prompt.md.tera</span>
- name: implement
type: agent
prompt: "{{ steps.build_prompt.response }}"</pre>
<p style="margin-top:8px;font-size:12px;color:var(--muted);">O arquivo <code>prompts/build_prompt.md.tera</code> contem as 50+ linhas com logica Tera, reutilizavel por qualquer workflow.</p>
</div>
</div>
<div class="info-card" style="border-color:var(--cyan);margin-top:16px;">
<strong style="color:var(--cyan)">Quando usar <code>type: template</code>?</strong><br>
• Prompts complexos com 20+ linhas de instrucoes e condicionais Tera<br>
• Mesmo prompt reutilizado em multiplos workflows (DRY)<br>
• Gerar texto localmente (relatorios, configs, changelogs) sem chamar AI<br>
• Compor um mega-prompt a partir de outputs de varios steps anteriores
</div>
<h3>Accessors: 3 modos de acesso a dados</h3>
<p>Dentro de qualquer template (inline ou arquivo <code>.md.tera</code>), voce tem tres modos de acessar variaveis:</p>
<div class="terminal">
<div class="terminal-bar">
<div class="terminal-dot red"></div>
<div class="terminal-dot yellow"></div>
<div class="terminal-dot green"></div>
<span class="terminal-title">template-patterns.yaml — 3 accessors + from()</span>
</div>
<div class="terminal-body"><span class="dim">steps:</span>
- name: maybe_skip
type: gate
condition: "{{ should_analyze }}"
- name: analyze
type: agent
prompt: "Analise os dados"
- name: report
type: agent
prompt: |
<span class="dim"># Normal: falha se nao existir</span>
Nome do projeto: <span class="green">{{ project_name }}</span>
<span class="dim"># Safe (?): retorna "" se step foi skipped</span>
Analise: <span class="cyan">{{ analyze.output<strong>?</strong> }}</span>
<span class="dim"># Strict (!): ERRO explicito se nao existir</span>
Config obrigatoria: <span class="red">{{ database_url<strong>!</strong> }}</span>
<span class="dim"># from(): acesse outputs de QUALQUER scope</span>
Dado de outro scope: <span class="purple">{{ from("global_setup").output }}</span>
Campo aninhado: <span class="purple">{{ from("api_call").output.data.id }}</span></div>
</div>
<div class="grid-3" style="margin-top:20px;">
<div class="card" style="border-color:var(--green);">
<h4 style="color:var(--green)">{{ x }} — Normal</h4>
<p>Erro se <code>x</code> nao existe. Use para dados obrigatorios.</p>
</div>
<div class="card" style="border-color:var(--cyan);">
<h4 style="color:var(--cyan)">{{ x? }} — Safe</h4>
<p>Retorna <code>""</code> se missing. Use para steps condicionais (gate skip).</p>
</div>
<div class="card" style="border-color:var(--red);">
<h4 style="color:var(--red)">{{ x! }} — Strict</h4>
<p>Erro imediato com mensagem clara. Use para fail-fast em configs.</p>
</div>
</div>
</section>
<section id="collect-reduce">
<div class="section-label">17 — Recursos Avancados</div>
<h2>Map collect/reduce</h2>
<p>Steps <code>map</code> agora coletam e reduzem resultados automaticamente. Sem precisar de um step extra para agregar.</p>
<div class="terminal">
<div class="terminal-bar">
<div class="terminal-dot red"></div>
<div class="terminal-dot yellow"></div>
<div class="terminal-dot green"></div>
<span class="terminal-title">collect-reduce.yaml — analise de modulos</span>
</div>
<div class="terminal-body"><span class="dim">scopes:</span>
analyze_module:
steps:
- name: review
type: agent
prompt: "Analise {{ scope_value }} e de nota 0-100"
output_type: integer
<span class="dim">steps:</span>
- name: review_all
type: map
items: "auth,payments,users,notifications"
scope: analyze_module
parallel: 4
config:
<span class="cyan">collect: json</span> <span class="dim"># text | all | json</span>
<span class="orange">reduce: sum</span> <span class="dim"># concat | sum | count | min | max | filter</span>
<span class="dim"># Resultado: soma das notas de todos os modulos</span>
- name: verdict
type: agent
prompt: |
Score total: <span class="green">{{ review_all.output }}</span> <span class="dim"># e.g. 340 (soma)</span></div>
</div>
<div class="info-card" style="border-color:var(--cyan);">
<strong style="color:var(--cyan)">Operacoes disponiveis:</strong><br>
<strong>collect:</strong> <code>text</code> (concatena stdout) • <code>json</code> (array JSON) • <code>all</code> (struct completa)<br>
<strong>reduce:</strong> <code>concat</code> • <code>sum</code> • <code>count</code> • <code>min</code> • <code>max</code> • <code>filter</code> (com reduce_condition)
</div>
</section>
<section id="plugins-events">
<div class="section-label">18 — Recursos Avancados</div>
<h2>Plugin System & Event Bus</h2>
<p>Estenda o engine com step types customizados via plugins <code>.dylib/.so</code>. Observe tudo com o event bus e webhooks.</p>
<div class="grid-2">
<div class="card" style="border-color:var(--purple);">
<h4 style="color:var(--purple)">Plugin System</h4>
<div class="terminal" style="margin:12px 0 0;">
<div class="terminal-body" style="font-size:12px;"><span class="dim">config:</span>
<span class="purple">plugins:</span>
- name: kubernetes
path: ./plugins/k8s.dylib
- name: terraform
path: ./plugins/tf.so
<span class="dim">steps:</span>
- name: deploy
<span class="purple">type: kubernetes</span> <span class="dim"># tipo customizado!</span>
config:
namespace: production
image: myapp:latest</div>
</div>
<p style="margin-top:10px;font-size:13px;color:var(--text-dim)">
Implemente o trait <code>PluginStep</code> em Rust, compile como <code>.dylib</code>, e o engine carrega automaticamente via <code>libloading</code>.
</p>
</div>
<div class="card" style="border-color:var(--orange);">
<h4 style="color:var(--orange)">Event Bus</h4>
<div class="terminal" style="margin:12px 0 0;">
<div class="terminal-body" style="font-size:12px;"><span class="dim">config:</span>
<span class="orange">events:</span>
webhook: https://slack.com/api/hook
file: ./logs/events.jsonl
<span class="dim"># Eventos emitidos automaticamente:</span>
<span class="dim"># StepStarted, StepCompleted, StepFailed</span>
<span class="dim"># WorkflowStarted, WorkflowCompleted</span>
<span class="dim"># SandboxCreated, SandboxDestroyed</span></div>
</div>
<p style="margin-top:10px;font-size:13px;color:var(--text-dim)">
Cada evento tem <code>step_name</code>, <code>duration_ms</code>, <code>timestamp</code>. Subscribers: webhook (HTTP POST) ou file (JSONL append).
</p>
</div>
</div>
</section>
<section id="setup">
<div class="section-label">19 — Guia Pratico</div>
<h2>Setup no Seu Projeto</h2>
<p>Como adicionar Minion Engine a qualquer projeto existente em 5 passos.</p>
<div class="flow-steps">
<div class="flow-step">
<div class="flow-step-num">1</div>
<h4>Instale o minion</h4>
<pre><span class="cmd">cargo install</span> minion-engine <span class="cmt"># ou brew/binary</span></pre>
</div>
<div class="flow-step">
<div class="flow-step-num green">2</div>
<h4>Crie um workflow a partir de template</h4>
<pre><span class="cmd">minion init</span> code-review <span class="flag">--template</span> code-review</pre>
</div>
<div class="flow-step">
<div class="flow-step-num accent">3</div>
<h4>Customize lint/test para seu stack</h4>
<p>Edite o YAML gerado para usar os comandos corretos do seu projeto.</p>
<div class="grid-2" style="margin-top:12px">
<div class="card" style="padding:16px">
<h4 style="color:var(--green);font-size:0.85rem;margin:0 0 6px">Node.js</h4>
<pre style="margin:0;font-size:11px"><span class="key">lint_cmd:</span> <span class="str">"npm run lint"</span>
<span class="key">test_cmd:</span> <span class="str">"npm test"</span></pre>
</div>
<div class="card" style="padding:16px">
<h4 style="color:var(--accent);font-size:0.85rem;margin:0 0 6px">Python</h4>
<pre style="margin:0;font-size:11px"><span class="key">lint_cmd:</span> <span class="str">"ruff check ."</span>
<span class="key">test_cmd:</span> <span class="str">"pytest"</span></pre>
</div>
<div class="card" style="padding:16px">
<h4 style="color:var(--orange);font-size:0.85rem;margin:0 0 6px">Rust</h4>
<pre style="margin:0;font-size:11px"><span class="key">lint_cmd:</span> <span class="str">"cargo clippy"</span>
<span class="key">test_cmd:</span> <span class="str">"cargo test"</span></pre>
</div>
<div class="card" style="padding:16px">
<h4 style="color:var(--cyan);font-size:0.85rem;margin:0 0 6px">Go</h4>
<pre style="margin:0;font-size:11px"><span class="key">lint_cmd:</span> <span class="str">"golangci-lint run"</span>
<span class="key">test_cmd:</span> <span class="str">"go test ./..."</span></pre>
</div>
</div>
</div>
<div class="flow-step">
<div class="flow-step-num purple">4</div>
<h4>Sandbox ja e o padrao!</h4>
<p>Nao precisa configurar nada — o sandbox Docker ja e ativado automaticamente. Para configuracao avancada (imagem, rede, recursos), veja a secao <a href="#sandbox">Docker Sandbox</a>.</p>
</div>
<div class="flow-step">
<div class="flow-step-num green">5</div>
<h4>Execute!</h4>
<pre><span class="cmd">minion execute</span> code-review <span class="flag">--verbose</span> <span class="flag">--</span> 142
<span class="cmt"># sandbox ON por padrao — seu projeto esta seguro</span></pre>
</div>
</div>
</section>
<section id="comparacao">
<div class="section-label">20 — Comparacao</div>
<h2>🐳 Com e Sem Sandbox</h2>
<p>O sandbox e o padrao — veja por que isso e importante.</p>
<table>
<thead>
<tr>
<th></th>
<th>Sem Sandbox</th>
<th>🐳 Com Sandbox</th>
</tr>
</thead>
<tbody>
<tr>
<td style="font-weight:700;color:var(--text)">Seguranca</td>
<td style="color:var(--red)">❌ Agent acessa tudo no filesystem</td>
<td style="color:var(--green)">✔ Isolado em container Docker</td>
</tr>
<tr>
<td style="font-weight:700;color:var(--text)">Se der errado</td>
<td style="color:var(--red)">😱 Cleanup manual, git reset, rezar</td>
<td style="color:var(--green)">🗑 Container destruido, zero impacto</td>
</tr>
<tr>
<td style="font-weight:700;color:var(--text)">Network</td>
<td style="color:var(--red)">🌐 Acesso total a internet</td>
<td style="color:var(--green)">🔒 Allow/deny list configuravel</td>
</tr>
<tr>
<td style="font-weight:700;color:var(--text)">Resources</td>
<td style="color:var(--red)">♾ Sem limite de CPU/memoria</td>
<td style="color:var(--green)">⚙ CPU e memoria limitados</td>
</tr>
<tr>
<td style="font-weight:700;color:var(--text)">Reprodutibilidade</td>
<td style="color:var(--yellow)">⚠ Depende do estado da maquina</td>
<td style="color:var(--green)">✔ Ambiente limpo e consistente</td>
</tr>
<tr>
<td style="font-weight:700;color:var(--text)">CI/CD</td>
<td style="color:var(--yellow)">⚠ Precisa de permissoes especiais</td>
<td style="color:var(--green)">✔ Roda em qualquer runner com Docker</td>
</tr>
</tbody>
</table>
<div class="tip warn">
<div class="tip-title">Padrao Seguro</div>
<p>O sandbox e <strong>ON por padrao</strong> — voce nao precisa fazer nada para ativa-lo. O overhead e minimo (3-5s para criar/destruir o container) e a seguranca e enorme. Use <code>--no-sandbox</code> apenas durante desenvolvimento local rapido de um workflow.</p>
</div>
</section>
<section id="cli">
<div class="section-label">21 — CLI Reference</div>
<h2>Todos os Comandos</h2>
<p>Referencia rapida do <code>minion</code> CLI.</p>
<table>
<thead>
<tr><th>Comando</th><th>Descricao</th><th>Flags Principais</th></tr>
</thead>
<tbody>
<tr>
<td><code>minion execute <yaml> [flags] -- [target]</code></td>
<td>Executa um workflow</td>
<td><code>--verbose</code> <code>--quiet</code> <code>--json</code> <code>--dry-run</code> <code>--no-sandbox</code> <code>--resume <step></code> <code>--var KEY=VAL</code> <code>--args '{}'</code></td>
</tr>
<tr>
<td><code>minion validate <yaml></code></td>
<td>Valida YAML sem executar</td>
<td>—</td>
</tr>
<tr>
<td><code>minion list</code></td>
<td>Lista workflows disponiveis</td>
<td>—</td>
</tr>
<tr>
<td><code>minion init <name></code></td>
<td>Cria workflow a partir de template</td>
<td><code>--template <name></code> <code>--output <dir></code></td>
</tr>
<tr>
<td><code>minion inspect <yaml></code></td>
<td>Mostra config resolvida e dependency graph</td>
<td>—</td>
</tr>
</tbody>
</table>
<h3>Flags do <code>execute</code></h3>
<div class="grid-2">
<div class="card">
<h4 style="color:var(--cyan)">🐳 --no-sandbox</h4>
<p>Desativa o Docker sandbox (que e <strong>ON por padrao</strong>). Use apenas para desenvolvimento local rapido. Sem sandbox, o agent roda direto na sua maquina.</p>
</div>
<div class="card">
<h4 style="color:var(--yellow)">--dry-run</h4>
<p>Mostra quais steps seriam executados sem executar nada. Arvore visual com tipos, commands e config resolvida.</p>
</div>
<div class="card">
<h4 style="color:var(--green)">--json</h4>
<p>Output estruturado em JSON. Suprime spinners e cores. Ideal para integracao com pipelines CI/CD.</p>
</div>
<div class="card">
<h4 style="color:var(--orange)">--resume <step></h4>
<p>Retoma execucao a partir de um step especifico. Carrega outputs anteriores do state file salvo.</p>
</div>
<div class="card">
<h4 style="color:var(--purple)">--verbose</h4>
<p>Mostra output completo de cada step, incluindo stdout/stderr de commands e tokens usados por agents.</p>
</div>
<div class="card">
<h4 style="color:var(--accent)">--var KEY=VAL</h4>
<p>Passa variaveis extras para o workflow. Acessiveis via <code>{{ vars.KEY }}</code> nos templates Tera.</p>
</div>
</div>
</section>
<section id="arquitetura">
<div class="section-label">22 — Arquitetura</div>
<h2>Diagrama de Arquitetura</h2>
<p>Fluxo completo: do YAML ao resultado, passando pelo Docker sandbox.</p>
<div class="diagram-container">
<div class="diagram-title">Fluxo de Execucao com Docker Sandbox</div>
<svg width="820" height="590" viewBox="0 0 820 590" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="20" y="30" width="140" height="60" rx="8" fill="#161b22" stroke="#39d353" stroke-width="2"/>
<text x="90" y="55" text-anchor="middle" fill="#39d353" font-size="11" font-weight="700">workflow.yaml</text>
<text x="90" y="72" text-anchor="middle" fill="#8b949e" font-size="10">+ target + args</text>
<path d="M160 60 L200 60" stroke="#30363d" stroke-width="2" marker-end="url(#arrowhead2)"/>
<rect x="200" y="35" width="100" height="50" rx="8" fill="#161b22" stroke="#58a6ff" stroke-width="2"/>
<text x="250" y="65" text-anchor="middle" fill="#58a6ff" font-size="12" font-weight="700">Parser</text>
<path d="M300 60 L340 60" stroke="#30363d" stroke-width="2" marker-end="url(#arrowhead2)"/>
<rect x="340" y="35" width="100" height="50" rx="8" fill="#161b22" stroke="#d29922" stroke-width="2"/>
<text x="390" y="65" text-anchor="middle" fill="#d29922" font-size="12" font-weight="700">Validator</text>
<path d="M440 60 L480 60" stroke="#30363d" stroke-width="2" marker-end="url(#arrowhead2)"/>
<rect x="480" y="20" width="140" height="80" rx="8" fill="#161b22" stroke="#bc8cff" stroke-width="2"/>
<text x="550" y="50" text-anchor="middle" fill="#bc8cff" font-size="13" font-weight="800">ENGINE</text>
<text x="550" y="68" text-anchor="middle" fill="#8b949e" font-size="10">dispatch loop</text>
<text x="550" y="83" text-anchor="middle" fill="#8b949e" font-size="10">config resolution</text>
<path d="M550 100 L550 140" stroke="#30363d" stroke-width="2" marker-end="url(#arrowhead2)"/>
<rect x="40" y="145" width="740" height="290" rx="12" fill="rgba(88,166,255,0.04)" stroke="#58a6ff" stroke-width="2" stroke-dasharray="8 4"/>
<text x="410" y="170" text-anchor="middle" fill="#58a6ff" font-size="13" font-weight="800">Docker Container</text>
<text x="410" y="186" text-anchor="middle" fill="#8b949e" font-size="10">/workspace — copia isolada do seu projeto</text>
<rect x="65" y="200" width="125" height="38" rx="6" fill="#0d1117" stroke="#39d353" stroke-width="1.5"/>
<text x="127" y="224" text-anchor="middle" fill="#39d353" font-size="11" font-weight="700">cmd</text>
<rect x="205" y="200" width="125" height="38" rx="6" fill="#0d1117" stroke="#bc8cff" stroke-width="1.5"/>
<text x="267" y="224" text-anchor="middle" fill="#bc8cff" font-size="11" font-weight="700">agent</text>
<rect x="345" y="200" width="125" height="38" rx="6" fill="#0d1117" stroke="#58a6ff" stroke-width="1.5"/>
<text x="407" y="224" text-anchor="middle" fill="#58a6ff" font-size="11" font-weight="700">chat</text>
<rect x="485" y="200" width="125" height="38" rx="6" fill="#0d1117" stroke="#d29922" stroke-width="1.5"/>
<text x="547" y="224" text-anchor="middle" fill="#d29922" font-size="11" font-weight="700">gate</text>
<rect x="625" y="200" width="125" height="38" rx="6" fill="#0d1117" stroke="#f0883e" stroke-width="1.5"/>
<text x="687" y="224" text-anchor="middle" fill="#f0883e" font-size="11" font-weight="700">repeat</text>
<rect x="65" y="248" width="125" height="38" rx="6" fill="#0d1117" stroke="#f778ba" stroke-width="1.5"/>
<text x="127" y="272" text-anchor="middle" fill="#f778ba" font-size="11" font-weight="700">map</text>
<rect x="205" y="248" width="125" height="38" rx="6" fill="#0d1117" stroke="#79c0ff" stroke-width="1.5"/>
<text x="267" y="272" text-anchor="middle" fill="#79c0ff" font-size="11" font-weight="700">parallel</text>
<rect x="345" y="248" width="125" height="38" rx="6" fill="#0d1117" stroke="#7ee787" stroke-width="1.5"/>
<text x="407" y="272" text-anchor="middle" fill="#7ee787" font-size="11" font-weight="700">call</text>
<rect x="485" y="248" width="125" height="38" rx="6" fill="#0d1117" stroke="#ffa657" stroke-width="1.5"/>
<text x="547" y="272" text-anchor="middle" fill="#ffa657" font-size="11" font-weight="700">template</text>
<rect x="625" y="248" width="125" height="38" rx="6" fill="#0d1117" stroke="#ff7b72" stroke-width="1.5"/>
<text x="687" y="272" text-anchor="middle" fill="#ff7b72" font-size="11" font-weight="700">script (Rhai)</text>
<path d="M550 140 L127 200" stroke="#30363d" stroke-width="1" stroke-dasharray="4"/>
<path d="M550 140 L267 200" stroke="#30363d" stroke-width="1" stroke-dasharray="4"/>
<path d="M550 140 L407 200" stroke="#30363d" stroke-width="1" stroke-dasharray="4"/>
<path d="M550 140 L547 200" stroke="#30363d" stroke-width="1" stroke-dasharray="4"/>
<path d="M550 140 L687 200" stroke="#30363d" stroke-width="1" stroke-dasharray="4"/>
<rect x="65" y="310" width="280" height="50" rx="8" fill="#161b22" stroke="#39d353" stroke-width="2"/>
<text x="205" y="333" text-anchor="middle" fill="#39d353" font-size="12" font-weight="700">Context Store</text>
<text x="205" y="348" text-anchor="middle" fill="#8b949e" font-size="9">outputs + variaveis + templates (?, !, from())</text>
<rect x="360" y="310" width="190" height="50" rx="8" fill="#161b22" stroke="#ffa657" stroke-width="2"/>
<text x="455" y="333" text-anchor="middle" fill="#ffa657" font-size="12" font-weight="700">EventBus</text>
<text x="455" y="348" text-anchor="middle" fill="#8b949e" font-size="9">webhook + file subscribers</text>
<rect x="565" y="310" width="190" height="50" rx="8" fill="#161b22" stroke="#ff7b72" stroke-width="2"/>
<text x="660" y="333" text-anchor="middle" fill="#ff7b72" font-size="12" font-weight="700">Plugin Registry</text>
<text x="660" y="348" text-anchor="middle" fill="#8b949e" font-size="9">.dylib/.so dynamic loading</text>
<path d="M410 286 L410 310" stroke="#30363d" stroke-width="2" marker-end="url(#arrowhead2)"/>
<path d="M410 435 L410 470" stroke="#58a6ff" stroke-width="2" marker-end="url(#arrowhead-blue)"/>
<rect x="160" y="475" width="200" height="55" rx="8" fill="#161b22" stroke="#3fb950" stroke-width="2"/>
<text x="260" y="500" text-anchor="middle" fill="#3fb950" font-size="12" font-weight="700">Copy Results Back</text>
<text x="260" y="517" text-anchor="middle" fill="#8b949e" font-size="10">arquivos modificados, reports</text>
<rect x="460" y="475" width="200" height="55" rx="8" fill="#161b22" stroke="#f85149" stroke-width="2"/>
<text x="560" y="500" text-anchor="middle" fill="#f85149" font-size="12" font-weight="700">Destroy Container</text>
<text x="560" y="517" text-anchor="middle" fill="#8b949e" font-size="10">zero rastros, zero impacto</text>
<rect x="650" y="20" width="155" height="80" rx="8" fill="#161b22" stroke="#d29922" stroke-width="1.5" stroke-dasharray="4"/>
<text x="727" y="45" text-anchor="middle" fill="#d29922" font-size="11" font-weight="700">Config 4-Layer</text>
<text x="727" y="62" text-anchor="middle" fill="#8b949e" font-size="9">global → type</text>
<text x="727" y="75" text-anchor="middle" fill="#8b949e" font-size="9">pattern → step</text>
<text x="727" y="88" text-anchor="middle" fill="#8b949e" font-size="9">inline override</text>
<path d="M650 60 L620 60" stroke="#d29922" stroke-width="1" stroke-dasharray="3"/>
<rect x="65" y="375" width="690" height="40" rx="6" fill="#0d1117" stroke="#f85149" stroke-width="1"/>
<text x="410" y="400" text-anchor="middle" fill="#f85149" font-size="10" font-weight="700">Network Rules (allow/deny list) • CPU/Memory Limits • Async Futures Pool</text>
<defs>
<marker id="arrowhead2" markerWidth="10" markerHeight="7" refX="10" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" fill="#30363d"/>
</marker>
<marker id="arrowhead-blue" markerWidth="10" markerHeight="7" refX="10" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" fill="#58a6ff"/>
</marker>
</defs>
</svg>
</div>
</section>
<section id="faq">
<div class="section-label">23 — FAQ</div>
<h2>Perguntas Frequentes</h2>
<div class="faq-item">
<div class="faq-q">Preciso de Docker instalado?</div>
<div class="faq-a">Sim, Docker Desktop 4.40+ e necessario pois o sandbox e <strong>ON por padrao</strong>. Sem Docker, use <code>--no-sandbox</code> — os workflows rodam direto na sua maquina, so nao tem o isolamento do container.</div>
</div>
<div class="faq-item">
<div class="faq-q">Funciona com qualquer linguagem?</div>
<div class="faq-a">Sim! O Minion Engine e agnostico de linguagem. Voce so precisa customizar os comandos de lint e test no YAML do workflow. Node, Python, Rust, Go, Java, Ruby, PHP — qualquer linguagem que rode no terminal funciona. A imagem Docker do sandbox tambem e configuravel.</div>
</div>
<div class="faq-item">
<div class="faq-q">E seguro usar <code>--dangerously-skip-permissions</code>?</div>
<div class="faq-a">Dentro do sandbox, sim. O container e isolado — mesmo que o agent faca algo inesperado, nao afeta sua maquina. A flag so e perigosa quando usada <strong>sem</strong> sandbox, pois da ao Claude Code acesso irrestrito ao seu filesystem.</div>
</div>
<div class="faq-item">
<div class="faq-q">Posso usar em CI/CD?</div>
<div class="faq-a">Sim! Use a flag <code>--json</code> para output estruturado sem spinners e cores. O sandbox ja e ON por padrao, entao o isolamento no runner de CI vem de graca. Funciona com GitHub Actions, GitLab CI, CircleCI, ou qualquer plataforma que tenha Docker disponivel.</div>
</div>
<div class="faq-item">
<div class="faq-q">Quanto custa?</div>
<div class="faq-a">O Minion Engine em si e <strong>gratuito e open-source</strong>. Voce so paga pelo uso das APIs de AI (Anthropic/OpenAI). Um fix-issue tipico consome ~10-15k tokens (~$0.05-0.10). Steps <code>cmd</code>, <code>gate</code>, <code>repeat</code>, <code>template</code> sao gratuitos — rodam localmente sem API calls.</div>
</div>
<div class="faq-item">
<div class="faq-q">E se o agent fizer besteira?</div>
<div class="faq-a">Com o sandbox (padrao): o container e destruido e seu codigo original permanece intocado. Se voce usou <code>--no-sandbox</code>: voce pode usar <code>--resume</code> para retomar de um ponto anterior, ou <code>git reset</code>. Por isso o sandbox e o padrao — a seguranca e o principal diferencial.</div>
</div>
<div class="faq-item">
<div class="faq-q">Qual a diferenca entre <code>agent</code> e <code>chat</code>?</div>
<div class="faq-a"><code>agent</code> usa o Claude Code CLI completo — pode ler/escrever arquivos, rodar comandos no filesystem. <code>chat</code> faz uma chamada direta a API do LLM — mais rapido e barato, mas sem acesso ao filesystem. Use <code>agent</code> para implementar codigo. Use <code>chat</code> para planejamento, analise e sumarizacao.</div>
</div>
<div class="faq-item">
<div class="faq-q">Como fazer debug de um workflow?</div>
<div class="faq-a">Use <code>--dry-run</code> para visualizar sem executar. Use <code>--verbose</code> para ver output completo de cada step. Use <code>minion inspect</code> para ver config resolvida e dependency graph. Use <code>--json</code> para output parseavel em scripts.</div>
</div>
</section>
</div>
<footer>
Minion Engine — Seu time de AI rodando em Docker Sandboxes — Open Source<br>
<span style="font-size:11px;color:var(--text-dim)">Built with Rust + Tokio + Tera + Claude Code CLI | Inspired by Stripe Minions</span>
</footer>
</div>
<script>
(function(){
const nav = document.getElementById('nav');
const links = nav.querySelectorAll('a[href^="#"]');
const sections = [];
links.forEach(a => {
const id = a.getAttribute('href').slice(1);
const el = document.getElementById(id);
if(el) sections.push({a, el});
});
function update(){
let current = sections[0];
const scrollY = window.scrollY + 80;
sections.forEach(s => { if(s.el.offsetTop <= scrollY) current = s; });
links.forEach(a => a.classList.remove('active'));
if(current) current.a.classList.add('active');
}
window.addEventListener('scroll', update, {passive:true});
update();
})();
</script>
</body>
</html>