ganbatte-os 0.2.37 → 0.2.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/.gos/agents/profiles/ganbatte-os-master.md +100 -0
  2. package/.gos/libraries/caveman-rules.md +58 -0
  3. package/.gos/libraries/cloudflare-stack-kb.md +161 -0
  4. package/.gos/libraries/component-reuse-gate.md +75 -0
  5. package/.gos/libraries/default-stack-kb.md +98 -0
  6. package/.gos/libraries/engineering-best-practices.md +208 -0
  7. package/.gos/libraries/gos-compress-setup.md +62 -0
  8. package/.gos/libraries/intake-questions-mom-test.md +91 -0
  9. package/.gos/libraries/lucide-icons-policy.md +174 -0
  10. package/.gos/libraries/security-best-practices.md +138 -0
  11. package/.gos/libraries/supabase-stack-kb.md +124 -0
  12. package/.gos/libraries/timer-pattern-spec.md +252 -0
  13. package/.gos/libraries/typeform-pattern-spec.md +204 -0
  14. package/.gos/libraries/ui-guardrails-checklist.md +144 -0
  15. package/.gos/libraries/visual-diff-lenses.md +114 -0
  16. package/.gos/playbooks/audit-streaming-playbook.md +86 -0
  17. package/.gos/skills/adr-tech-decisions/SKILL.md +166 -0
  18. package/.gos/skills/audit-screenshots/SKILL.md +200 -142
  19. package/.gos/skills/cloudflare-pages-setup/SKILL.md +180 -0
  20. package/.gos/skills/figma-print-diff/SKILL.md +170 -0
  21. package/.gos/skills/gos-caveman/SKILL.md +110 -0
  22. package/.gos/skills/gos-compress/SKILL.md +134 -0
  23. package/.gos/skills/gos-compress/scripts/compress.py +346 -0
  24. package/.gos/skills/gos-compress/scripts/setup.py +91 -0
  25. package/.gos/skills/idea-intake/SKILL.md +147 -0
  26. package/.gos/skills/plan-blueprint/SKILL.md +18 -3
  27. package/.gos/skills/plan-to-tasks/SKILL.md +37 -1
  28. package/.gos/skills/prd-from-intake/SKILL.md +94 -0
  29. package/.gos/skills/prototype-orchestrator/SKILL.md +120 -0
  30. package/.gos/skills/registry.json +12 -1
  31. package/.gos/skills/timer-component-pattern/SKILL.md +245 -0
  32. package/.gos/skills/typeform-form-pattern/SKILL.md +210 -0
  33. package/.gos/skills/ui-guardrails/SKILL.md +111 -0
  34. package/.gos/templates/intakeTemplate.md +41 -0
  35. package/.gos/templates/planTemplate.md +25 -4
  36. package/.gos/templates/prdLeanTemplate.md +40 -0
  37. package/.gos/templates/taskTemplate.md +29 -5
  38. package/package.json +1 -1
@@ -0,0 +1,346 @@
1
+ """
2
+ compress.py — Script principal da skill sandeco-token-reduce.
3
+
4
+ Comprime texto com LLMLingua-2 e opcionalmente envia ao Claude.
5
+ Auto-detecta GPU.
6
+
7
+ Requer inicializacao previa com setup.py.
8
+
9
+ Modos:
10
+ So comprimir: python compress.py --file texto.txt --rate 0.4
11
+ Comprimir + salvar: python compress.py --file texto.txt --rate 0.4 --output comprimido.txt
12
+ Comprimir + Claude: python compress.py --file texto.txt --rate 0.4 --ask "Resuma este texto"
13
+ Saida JSON: python compress.py --file texto.txt --rate 0.4 --json
14
+ """
15
+
16
+ import argparse
17
+ import json as json_mod
18
+ import re
19
+ import sys
20
+ from pathlib import Path
21
+
22
+
23
+ SKILL_DIR = Path(__file__).parent.parent
24
+ VENV_DIR = SKILL_DIR / ".venv"
25
+
26
+
27
+ # -- Verificacao de ambiente ---------------------------------------------------
28
+
29
+ def check_environment():
30
+ """Verifica se o venv existe e se estamos rodando dentro dele."""
31
+ venv_python = VENV_DIR / "Scripts" / "python.exe"
32
+ if not venv_python.exists():
33
+ venv_python = VENV_DIR / "bin" / "python"
34
+
35
+ if not VENV_DIR.exists() or not venv_python.exists():
36
+ print("ERRO: A skill ainda nao foi inicializada.", file=sys.stderr)
37
+ print(f"Execute primeiro: python \"{SKILL_DIR / 'scripts' / 'setup.py'}\"",
38
+ file=sys.stderr)
39
+ sys.exit(1)
40
+
41
+ if sys.prefix == sys.base_prefix:
42
+ print(f"ERRO: Execute este script com o Python do venv:", file=sys.stderr)
43
+ print(f" \"{venv_python}\" \"{__file__}\" ...", file=sys.stderr)
44
+ sys.exit(1)
45
+
46
+
47
+ # -- Compressor ----------------------------------------------------------------
48
+
49
+ def detect_device() -> str:
50
+ try:
51
+ import torch
52
+ if torch.cuda.is_available():
53
+ return "cuda"
54
+ except ImportError:
55
+ pass
56
+ return "cpu"
57
+
58
+
59
+ MODEL_NAME = "microsoft/llmlingua-2-xlm-roberta-large-meetingbank"
60
+ CHUNK_MAX_TOKENS = 400
61
+ COMPRESS_KWARGS = dict(
62
+ force_tokens=[
63
+ # Estruturais
64
+ "\n", ".", ",", "?", "!", ":", ";",
65
+ # Negacoes PT
66
+ "não", "sem", "nenhum", "nunca", "nem", "nenhuma",
67
+ # Prioridade / obrigatoriedade
68
+ "Must", "must", "Obrigatória", "obrigatória",
69
+ # Operacionais
70
+ "npm", "run", "dev",
71
+ # Resiliencia / fallback
72
+ "retry", "fallback", "timeout", "WAL", "graciosamente",
73
+ # Metricas
74
+ "baseline", "target", "Baseline", "Target",
75
+ # Delimitadores de codigo inline
76
+ "`",
77
+ ],
78
+ force_reserve_digit=True,
79
+ drop_consecutive=True,
80
+ )
81
+
82
+
83
+ def load_compressor():
84
+ from llmlingua import PromptCompressor
85
+
86
+ device = detect_device()
87
+ print(f"Carregando LLMLingua-2 (device={device})...", file=sys.stderr)
88
+ return PromptCompressor(
89
+ model_name=MODEL_NAME,
90
+ use_llmlingua2=True,
91
+ device_map=device,
92
+ )
93
+
94
+
95
+ def load_tokenizer():
96
+ from transformers import AutoTokenizer
97
+ return AutoTokenizer.from_pretrained(MODEL_NAME)
98
+
99
+
100
+ # -- Pre-processamento markdown ------------------------------------------------
101
+
102
+ def tables_to_keyvalue(text: str) -> str:
103
+ """Converte tabelas markdown para formato key: value que sobrevive a compressao."""
104
+ lines = text.split('\n')
105
+ result = []
106
+ i = 0
107
+ while i < len(lines):
108
+ if lines[i].strip().startswith('|') and '|' in lines[i][1:]:
109
+ table_lines = []
110
+ while i < len(lines) and lines[i].strip().startswith('|'):
111
+ table_lines.append(lines[i])
112
+ i += 1
113
+ if len(table_lines) < 2:
114
+ result.extend(table_lines)
115
+ continue
116
+ headers = [h.strip() for h in table_lines[0].split('|')[1:-1]]
117
+ for tl in table_lines[1:]:
118
+ if re.match(r'^\s*\|[-:\s|]+\|\s*$', tl):
119
+ continue
120
+ values = [v.strip() for v in tl.split('|')[1:-1]]
121
+ for h, v in zip(headers, values):
122
+ if v:
123
+ result.append(f"{h}: {v}")
124
+ result.append('')
125
+ else:
126
+ result.append(lines[i])
127
+ i += 1
128
+ return '\n'.join(result)
129
+
130
+
131
+ def normalize_identifiers(text: str) -> str:
132
+ """Gruda prefixos de IDs aos digitos para que force_reserve_digit proteja o conjunto.
133
+ Ex: G-01 -> G01, RF-01 -> RF01, EC-04 -> EC04"""
134
+ return re.sub(r'\b(G|RF|RNF|NG|EC)-(\d+)', r'\1\2', text)
135
+
136
+
137
+ def strip_markdown(text: str) -> str:
138
+ """Remove decoracao markdown mantendo o conteudo textual."""
139
+ text = re.sub(r'^---+\s*$', '', text, flags=re.MULTILINE) # separadores
140
+ text = re.sub(r'\*\*(.+?)\*\*', r'\1', text) # **bold** -> texto
141
+ text = re.sub(r'^#{1,6}\s+', '', text, flags=re.MULTILINE) # ## headers -> texto
142
+ text = re.sub(r'- \[[ x]\]\s*', '', text) # checkboxes
143
+ text = re.sub(r'^```\w*\s*$', '', text, flags=re.MULTILINE) # code fences (triple)
144
+ text = re.sub(r'\n{3,}', '\n\n', text) # colapsar linhas vazias
145
+ return text.strip()
146
+
147
+
148
+ # -- Chunking ------------------------------------------------------------------
149
+
150
+ def split_into_chunks(text: str, tokenizer, max_tokens: int = CHUNK_MAX_TOKENS) -> list[str]:
151
+ """Divide texto em chunks de ate max_tokens, cortando em limites de linha."""
152
+ lines = text.split('\n')
153
+ chunks = []
154
+ current_lines = []
155
+ current_tokens = 0
156
+
157
+ for line in lines:
158
+ line_tokens = len(tokenizer.encode(line, add_special_tokens=False))
159
+ if current_tokens + line_tokens > max_tokens and current_lines:
160
+ chunks.append('\n'.join(current_lines))
161
+ current_lines = []
162
+ current_tokens = 0
163
+ current_lines.append(line)
164
+ current_tokens += line_tokens
165
+
166
+ if current_lines:
167
+ chunks.append('\n'.join(current_lines))
168
+
169
+ return chunks
170
+
171
+
172
+ # -- Compressao ----------------------------------------------------------------
173
+
174
+ def compress(text: str, rate: float) -> dict:
175
+ text = tables_to_keyvalue(text)
176
+ text = normalize_identifiers(text)
177
+ text = strip_markdown(text)
178
+ compressor = load_compressor()
179
+ tokenizer = load_tokenizer()
180
+
181
+ chunks = split_into_chunks(text, tokenizer)
182
+
183
+ if len(chunks) == 1:
184
+ result = compressor.compress_prompt(text, rate=rate, **COMPRESS_KWARGS)
185
+ return {
186
+ "compressed_prompt": result["compressed_prompt"],
187
+ "origin_tokens": result["origin_tokens"],
188
+ "compressed_tokens": result["compressed_tokens"],
189
+ "ratio": round(float(str(result["ratio"]).rstrip("x")), 2),
190
+ "saving": result["origin_tokens"] - result["compressed_tokens"],
191
+ "rate_requested": rate,
192
+ }
193
+
194
+ print(f"Texto dividido em {len(chunks)} chunks (max {CHUNK_MAX_TOKENS} tokens cada).",
195
+ file=sys.stderr)
196
+
197
+ compressed_parts = []
198
+ total_origin = 0
199
+ total_compressed = 0
200
+
201
+ for i, chunk in enumerate(chunks, 1):
202
+ r = compressor.compress_prompt(chunk, rate=rate, **COMPRESS_KWARGS)
203
+ compressed_parts.append(r["compressed_prompt"])
204
+ total_origin += r["origin_tokens"]
205
+ total_compressed += r["compressed_tokens"]
206
+ print(f" Chunk {i}/{len(chunks)}: {r['origin_tokens']} -> {r['compressed_tokens']} tokens",
207
+ file=sys.stderr)
208
+
209
+ ratio = round(total_origin / total_compressed, 2) if total_compressed > 0 else 0.0
210
+
211
+ return {
212
+ "compressed_prompt": "\n".join(compressed_parts),
213
+ "origin_tokens": total_origin,
214
+ "compressed_tokens": total_compressed,
215
+ "ratio": ratio,
216
+ "saving": total_origin - total_compressed,
217
+ "rate_requested": rate,
218
+ }
219
+
220
+
221
+ # -- Claude --------------------------------------------------------------------
222
+
223
+ def ask_claude(compressed_text: str, question: str, model: str, max_tokens: int) -> dict:
224
+ import anthropic
225
+
226
+ client = anthropic.Anthropic()
227
+ prompt = f"""Contexto (comprimido via LLMLingua-2 — tokens irrelevantes foram removidos,
228
+ mas o significado foi preservado):
229
+
230
+ {compressed_text}
231
+
232
+ Pergunta: {question}"""
233
+
234
+ response = client.messages.create(
235
+ model=model,
236
+ max_tokens=max_tokens,
237
+ messages=[{"role": "user", "content": prompt}],
238
+ )
239
+
240
+ answer = ""
241
+ for block in response.content:
242
+ if block.type == "text":
243
+ answer += block.text
244
+
245
+ return {
246
+ "answer": answer,
247
+ "model": model,
248
+ "input_tokens": response.usage.input_tokens,
249
+ "output_tokens": response.usage.output_tokens,
250
+ }
251
+
252
+
253
+ # -- CLI -----------------------------------------------------------------------
254
+
255
+ def parse_args():
256
+ p = argparse.ArgumentParser(
257
+ description="Comprime tokens com LLMLingua-2 (Microsoft)"
258
+ )
259
+ # Entrada
260
+ group = p.add_mutually_exclusive_group(required=True)
261
+ group.add_argument("--text", help="Texto a comprimir")
262
+ group.add_argument("--file", help="Caminho para arquivo de texto")
263
+
264
+ # Compressao
265
+ p.add_argument("--rate", type=float, default=0.4,
266
+ help="Fracao de tokens a manter: 0.5=leve, 0.4=padrao, 0.2=agressivo")
267
+
268
+ # Saida
269
+ p.add_argument("--output", "-o", help="Salva texto comprimido neste arquivo")
270
+ p.add_argument("--json", action="store_true",
271
+ help="Saida em JSON (util para integracao programatica)")
272
+
273
+ # Claude (opcional)
274
+ p.add_argument("--ask", help="Pergunta a enviar ao Claude com o contexto comprimido")
275
+ p.add_argument("--model", default="claude-sonnet-4-6",
276
+ help="Modelo Claude (padrao: claude-sonnet-4-6)")
277
+ p.add_argument("--max-tokens", type=int, default=4096,
278
+ help="Max tokens na resposta do Claude (padrao: 4096)")
279
+
280
+ return p.parse_args()
281
+
282
+
283
+ def main():
284
+ check_environment()
285
+
286
+ args = parse_args()
287
+
288
+ # Carregar texto
289
+ if args.file:
290
+ path = Path(args.file)
291
+ if not path.exists():
292
+ print(f"ERRO: arquivo nao encontrado: {path}", file=sys.stderr)
293
+ sys.exit(1)
294
+ text = path.read_text(encoding="utf-8")
295
+ else:
296
+ text = args.text
297
+
298
+ if not text.strip():
299
+ print("ERRO: texto vazio.", file=sys.stderr)
300
+ sys.exit(1)
301
+
302
+ # Comprimir
303
+ result = compress(text, args.rate)
304
+
305
+ # Salvar se pedido
306
+ if args.output:
307
+ out = Path(args.output)
308
+ out.parent.mkdir(parents=True, exist_ok=True)
309
+ out.write_text(result["compressed_prompt"], encoding="utf-8")
310
+ print(f"Salvo em: {out.resolve()}", file=sys.stderr)
311
+
312
+ # Perguntar ao Claude se pedido
313
+ claude_result = None
314
+ if args.ask:
315
+ claude_result = ask_claude(
316
+ result["compressed_prompt"], args.ask, args.model, args.max_tokens
317
+ )
318
+
319
+ # Saida
320
+ if args.json:
321
+ output = {
322
+ "compression": result,
323
+ }
324
+ if claude_result:
325
+ output["claude"] = claude_result
326
+ print(json_mod.dumps(output, ensure_ascii=False, indent=2))
327
+ else:
328
+ print(f"\nTokens originais: {result['origin_tokens']}")
329
+ print(f"Tokens comprimidos: {result['compressed_tokens']}")
330
+ print(f"Taxa de compressao: {result['ratio']}x")
331
+ print(f"Tokens economizados: {result['saving']}")
332
+
333
+ if not args.output:
334
+ print(f"\n--- Texto comprimido ---")
335
+ print(result["compressed_prompt"])
336
+ print("------------------------")
337
+
338
+ if claude_result:
339
+ print(f"\n--- Resposta do Claude ({args.model}) ---")
340
+ print(claude_result["answer"])
341
+ print(f"\nTokens Claude — input: {claude_result['input_tokens']}, "
342
+ f"output: {claude_result['output_tokens']}")
343
+
344
+
345
+ if __name__ == "__main__":
346
+ main()
@@ -0,0 +1,91 @@
1
+ """
2
+ setup.py — Inicializacao da skill sandeco-token-reduce.
3
+
4
+ Cria o .venv, instala dependencias e baixa o modelo LLMLingua-2.
5
+ Deve ser executado uma unica vez antes de usar a skill.
6
+
7
+ Uso:
8
+ python setup.py
9
+ """
10
+
11
+ import subprocess
12
+ import sys
13
+ from pathlib import Path
14
+
15
+ SKILL_DIR = Path(__file__).parent.parent
16
+ VENV_DIR = SKILL_DIR / ".venv"
17
+ PACKAGES = ["llmlingua", "anthropic"]
18
+
19
+
20
+ def venv_python():
21
+ """Retorna o caminho do Python dentro do .venv (Windows e Unix)."""
22
+ win = VENV_DIR / "Scripts" / "python.exe"
23
+ unix = VENV_DIR / "bin" / "python"
24
+ return win if win.exists() else unix
25
+
26
+
27
+ def run(cmd, **kwargs):
28
+ print(f" $ {' '.join(str(c) for c in cmd)}")
29
+ result = subprocess.run(cmd, **kwargs)
30
+ if result.returncode != 0:
31
+ print(f"\nERRO: comando falhou com codigo {result.returncode}")
32
+ sys.exit(result.returncode)
33
+
34
+
35
+ def main():
36
+ print("=" * 60)
37
+ print(" sandeco-token-reduce — Inicializacao")
38
+ print("=" * 60)
39
+ print(f"\n Skill dir: {SKILL_DIR}")
40
+ print(f" Venv dir: {VENV_DIR}\n")
41
+
42
+ # 1. Criar o venv
43
+ if not VENV_DIR.exists():
44
+ print("[1/4] Criando ambiente virtual (.venv)...")
45
+ run([sys.executable, "-m", "venv", str(VENV_DIR)])
46
+ print(" OK\n")
47
+ else:
48
+ print("[1/4] .venv ja existe, pulando criacao.\n")
49
+
50
+ python = venv_python()
51
+ if not python.exists():
52
+ print(f"ERRO: Python do venv nao encontrado em {python}")
53
+ sys.exit(1)
54
+
55
+ # 2. Atualizar pip
56
+ print("[2/4] Atualizando pip...")
57
+ run([str(python), "-m", "pip", "install", "--upgrade", "pip", "-q"])
58
+ print(" OK\n")
59
+
60
+ # 3. Instalar pacotes
61
+ print(f"[3/4] Instalando dependencias: {', '.join(PACKAGES)}")
62
+ print(" (isso pode levar alguns minutos na primeira vez)")
63
+ run([str(python), "-m", "pip", "install"] + PACKAGES + ["-q"])
64
+ print(" OK\n")
65
+
66
+ # 4. Baixar o modelo LLMLingua-2 (faz uma compressao minima para forcar o download)
67
+ print("[4/4] Baixando modelo LLMLingua-2 (~1 GB na primeira vez)...")
68
+ print(" (o modelo fica em cache em ~/.cache/huggingface/)")
69
+ download_script = (
70
+ "from llmlingua import PromptCompressor; "
71
+ "c = PromptCompressor("
72
+ "model_name='microsoft/llmlingua-2-xlm-roberta-large-meetingbank', "
73
+ "use_llmlingua2=True, device_map='cpu'); "
74
+ "r = c.compress_prompt('Hello world test.', rate=0.5); "
75
+ "print(' Modelo carregado com sucesso!')"
76
+ )
77
+ run([str(python), "-c", download_script])
78
+ print()
79
+
80
+ # Resumo
81
+ print("=" * 60)
82
+ print(" Inicializacao concluida!")
83
+ print("=" * 60)
84
+ print(f"\n Python do venv: {python}")
85
+ print(f"\n A skill esta pronta para uso.")
86
+ print(f" Peca ao Claude para comprimir um texto!")
87
+ print()
88
+
89
+
90
+ if __name__ == "__main__":
91
+ main()
@@ -0,0 +1,147 @@
1
+ ---
2
+ name: idea-intake
3
+ description: >
4
+ Entrevista guiada estilo Mom Test + SPIN para extrair a ideia de um usuario nao-tecnico
5
+ e transformar em intake.md estruturado. Pergunta-a-pergunta adaptativo, em PT-BR, ate ter
6
+ problema, persona, jobs-to-be-done, telas-chave e metrica de sucesso. Output unico:
7
+ docs/intake/INTAKE-NNN-<slug>/intake.md.
8
+ argument-hint: "<frase curta da ideia ou 'continuar' para retomar sessao>"
9
+ allowedTools: [Read, Glob, Grep, Bash, Write, Edit, AskUserQuestion]
10
+ sourceDocs:
11
+ - libraries/intake-questions-mom-test.md
12
+ - templates/intakeTemplate.md
13
+ use-when:
14
+ - usuario nao-tecnico chega com uma ideia ainda crua ("queria um app que...")
15
+ - antes de qualquer plan-blueprint ou design quando nao existe PRD
16
+ - quando a saida final esperada e um prototipo descartavel/MVP
17
+ do-not-use-for:
18
+ - quando o usuario ja tem PRD (use prd-from-intake apontando para o doc)
19
+ - tarefas tecnicas concretas (use plan-blueprint direto)
20
+ metadata:
21
+ category: discovery
22
+ ---
23
+
24
+ Voce esta executando como **Entrevistador de Discovery** via skill `idea-intake`. Conduz uma entrevista pergunta-a-pergunta com um usuario nao-tecnico, em PT-BR, ate produzir um intake.md completo que servira de input para `prd-from-intake`.
25
+
26
+ ## Contrato
27
+
28
+ 1. NUNCA pergunte mais de 1 coisa por vez. Uma pergunta. Espera resposta. Proxima pergunta.
29
+ 2. Linguagem coloquial, sem jargao tecnico. Se precisar perguntar algo tecnico, traduzir em analogia ("imagina que sua ideia precisa de um caderno onde a informacao fica salva mesmo se voce fechar o app — pra voce isso e importante?").
30
+ 3. Maximo de 15 perguntas. Se atingir o teto, fecha com o que tem.
31
+ 4. Persistir progresso em `.gos-local/intake-session.json` apos cada pergunta respondida (resume com `*idea-intake continuar`).
32
+ 5. Output final unico: `docs/intake/INTAKE-NNN-<slug>/intake.md`. NUNCA escrever em outros lugares.
33
+
34
+ ## Estrutura da entrevista (5 blocos, 2-3 perguntas cada)
35
+
36
+ ### Bloco 1 — Problema (Mom Test: presente, nao futuro)
37
+
38
+ - "Me conta uma situacao real, nas ultimas semanas, em que voce ou alguem que voce conhece passou por esse problema." (forca historia concreta)
39
+ - "Como voce resolveu na hora? Mesmo que mal resolvido."
40
+ - "O que mais te incomodou nessa hora?"
41
+
42
+ Anti-padrao: nao perguntar "voce pagaria por uma solucao?" ou "seria legal se...?". Mom Test rejeita hipoteticos.
43
+
44
+ ### Bloco 2 — Persona
45
+
46
+ - "Quem mais alem de voce viveria isso? Tenta descrever uma pessoa especifica (nao um cargo)."
47
+ - "Essa pessoa esta em qual contexto quando o problema bate? (no celular, na rua, no escritorio, com filho do lado, etc.)"
48
+
49
+ ### Bloco 3 — Jobs-to-be-done
50
+
51
+ - "Se essa solucao existisse magicamente amanha, qual seria a primeira coisa que voce faria com ela?"
52
+ - "E o que voce QUERIA que ela NAO fizesse? (limites)"
53
+
54
+ ### Bloco 4 — Telas-chave (extracao visual sem jargao)
55
+
56
+ Adaptativo. Pergunta varia conforme tipo de produto (app/site/dashboard/automacao). Padrao:
57
+
58
+ - "Imagina que voce abriu o produto agora. O que voce ESPERA ver na primeira tela?"
59
+ - "Tem alguma tela que voce sabe que vai precisar mas nao sabe explicar como? Tenta desenhar com palavras."
60
+ - "Tem algum produto que ja faz parecido e te inspira? (link, nome, ou descricao)"
61
+
62
+ ### Bloco 5 — Sucesso e escopo descartavel
63
+
64
+ CRITICO: explicitar que a maioria dos MVPs serao descartaveis (uso unico). Pergunta:
65
+
66
+ - "Esse produto e pra usar UMA vez (validar uma ideia, mostrar pra alguem, testar conceito) ou voce quer manter rodando por meses?"
67
+ - "Como voce vai saber, depois de usar, que valeu a pena? (metrica em linguagem humana — 'minha mae conseguiu agendar sozinha', 'consegui fechar 1 venda')"
68
+
69
+ ## Pre-flight (gate)
70
+
71
+ 1. Se `$ARGUMENTS` == "continuar": ler `.gos-local/intake-session.json`. Se nao existir, abortar com "Nenhuma sessao em curso. Comece com `*idea-intake <sua ideia>`."
72
+ 2. Se `$ARGUMENTS` e frase curta: criar nova sessao, slug = kebab-case dos primeiros 4 substantivos. Persistir em `.gos-local/intake-session.json`.
73
+ 3. Verificar se existe `libraries/intake-questions-mom-test.md` no projeto (em projetos que consomem o G-OS via `.gos/`). Se sim, ler para enriquecer perguntas com banco contextualizado.
74
+
75
+ ## Persistencia
76
+
77
+ `.gos-local/intake-session.json`:
78
+
79
+ ```json
80
+ {
81
+ "session_id": "intake-2026-05-09T14-22-03",
82
+ "slug": "agendamento-mae",
83
+ "ideia_seed": "queria um app que minha mae use pra...",
84
+ "block": 3,
85
+ "qa": [
86
+ { "block": 1, "q": "...", "a": "..." }
87
+ ],
88
+ "started_at": "<iso>",
89
+ "updated_at": "<iso>"
90
+ }
91
+ ```
92
+
93
+ ## Saida final (intake.md)
94
+
95
+ ```markdown
96
+ ---
97
+ intake_id: INTAKE-NNN-<slug>
98
+ status: pronto-para-prd
99
+ descartavel: true|false
100
+ created_at: <iso>
101
+ ---
102
+
103
+ # <Titulo curto da ideia>
104
+
105
+ ## Problema (em uma frase)
106
+ <sintese feita pelo agente, validada com o usuario antes de fechar>
107
+
108
+ ## Historias reais coletadas
109
+ - <bullet 1>
110
+ - <bullet 2>
111
+
112
+ ## Persona
113
+ <descricao em prosa, contexto incluido>
114
+
115
+ ## Jobs-to-be-done
116
+ - Quando <situacao>, eu quero <acao>, para que <resultado>.
117
+
118
+ ## Limites (o que NAO fazer)
119
+ - <bullet>
120
+
121
+ ## Telas-chave (visao bruta)
122
+ 1. <tela 1 — descricao em palavras leigas>
123
+ 2. <tela 2>
124
+
125
+ ## Inspiracoes
126
+ - <link ou nome>
127
+
128
+ ## Escopo
129
+ - Descartavel: <sim|nao>
130
+ - Vida util esperada: <uma vez|semanas|meses|continuo>
131
+
132
+ ## Metrica de sucesso (linguagem humana)
133
+ <frase do usuario>
134
+
135
+ ## Proximo passo
136
+ - Rodar `*prd-from-intake INTAKE-NNN-<slug>` para gerar PRD lean.
137
+ ```
138
+
139
+ ## Regras criticas
140
+
141
+ - **Falsificar antes de fechar**: ao final do bloco 5, mostrar resumo em 5 bullets e perguntar "isso reflete o que voce quer?". Se usuario corrigir algo, voltar 1 bloco.
142
+ - **Sem chumbar tecnologia**: nao mencionar React, Cloudflare, Supabase, banco, API. Decisoes tecnicas sao da `adr-tech-decisions`, NAO daqui.
143
+ - **Descartavel-first**: se usuario indicar uso unico, marcar `descartavel: true` no frontmatter — `prd-from-intake` e `adr-tech-decisions` usam isso para dimensionar arquitetura (sem auth complexa, sem CI/CD elaborado, etc.).
144
+
145
+ ## Input
146
+
147
+ $ARGUMENTS
@@ -27,9 +27,16 @@ Você está executando como **Tech Lead Frontend / Arquiteto Sênior** via skill
27
27
 
28
28
  1. Escrever `plan.md` + `context.md`.
29
29
  2. **Invocar `plan-to-tasks`** apontando para o `plan.md` recém-criado — gera os `T-NN*.md` em `tasks/`.
30
- 3. Atualizar `progress.txt` (skill `progress-tracker set`).
31
- 4. **Rodar `node <repo>/.gos/scripts/integrations/check-plan.js <plan-dir>`** — gate determinístico.
32
- 5. Exit 0 → devolver "plano criado" com resumo. Exit != 0 → regerar tasks 1x e re-rodar; se persistir, ABORTAR e devolver a saída do check-plan ao usuário.
30
+ 3. **Invocar `ui-guardrails <plan-dir>`** — bloqueia se faltar estado/responsivo/a11y/tokens em qualquer task de UI. Skip permitido se `descartavel: true` no frontmatter (passa a warning).
31
+ 4. Atualizar `progress.txt` (skill `progress-tracker set`).
32
+ 5. **Rodar `node <repo>/.gos/scripts/integrations/check-plan.js <plan-dir>`** gate determinístico.
33
+ 6. (Opcional, default ligado) Comprimir secoes prosa do plan.md via `gos-caveman full` — preserva codigo/tabelas/frontmatter, comprime ## Contexto e ## Notas.
34
+ 7. Exit 0 → devolver "plano criado" com resumo. Exit != 0 → regerar tasks 1x e re-rodar; se persistir, ABORTAR e devolver a saída do check-plan ao usuário.
35
+
36
+ ### Flags de token-control
37
+ - `--no-compress` — desliga gos-caveman (default ligado).
38
+ - `--no-guardrails` — pula ui-guardrails (apenas para descartaveis).
39
+ - `--compress-context` — comprime docs/stack.md + ADRs antes de injetar (via gos-compress, requer setup).
33
40
 
34
41
  Plano sem tasks (tasks/ vazio ou ausente) é falha — não é "plano parcial". Skill que devolve "plano criado" sem ter rodado o check-plan está em estado inválido.
35
42
 
@@ -205,6 +212,9 @@ Para cada elemento mapeado:
205
212
 
206
213
  Regras de geração de tasks (cobertura de comportamento + overrides):
207
214
 
215
+ - **Modelo O QUE / ONDE / COMO / POR QUE**: cada task nasce respondendo as 4 perguntas (Contexto=por que, Objetivo+Entrega=o que, Arquivos=onde, Plano de execução=como). O `plan-to-tasks` materializa isso a partir do `## Plano de execução` (como) + `context.md` `## Arquivos relevantes` (onde). Task sem path concreto em `## Arquivos` é malformada.
216
+ - **Tabela de regressão + Anti-padrões**: o `plan.md` preenche `## Tabela de regressão` (fluxos a não quebrar) e `## Anti-padrões` (proibições, derivadas das memórias do projeto). `validate-plan` confere ambos no fechamento.
217
+
208
218
  - Toda interação em `## Interações & Estados` deve gerar **ao menos 1 task** com `interaction_target:` apontando pra ela. Se uma task cobre múltiplas interações, listar todos os slugs.
209
219
  - Toda linha de `## Page-level overrides` com decisão **(b)** gera task de variant na story (`area: ui-ux`, `agent:ux-design-expert`); decisões **(a)** e **(c)** geram tasks na página (`area: frontend`, `agent:dev`). Em ambos os casos, frontmatter da task declara `override_target:` apontando pro slug.
210
220
  - Tasks de seed data (quando aplicável — Tabela ou Form com fields no Figma) declaram fields obrigatórios e referenciam o checklist "Seed popula TODOS os campos exibidos".
@@ -218,6 +228,11 @@ Se a análise identificar mais de 3 seções autônomas (modais, drawers, sub-ro
218
228
 
219
229
  Frontmatter linka via `parent_plan` / `children_plans`.
220
230
 
231
+ > **Quando NAO usar plan-blueprint**: `plan-blueprint` e' "1 tela = 1 plano" (implantacao do zero). Para
232
+ > auditoria visual que acumula correcoes de **N telas em UM plano de fix** (confronto Figma x implementado,
233
+ > task por insumo), use `audit-screenshots` (orquestrador streaming) — ele reusa esta Fase 1.3 (mapeamento +
234
+ > reuso de componente) e `figma-print-diff` como primitivas.
235
+
221
236
  ## Saída
222
237
 
223
238
  Para cada plano (incluindo filhos), os 4 passos abaixo são **obrigatórios e atômicos** — `*plan` NÃO termina sem todos. Falhar qualquer um aborta com erro explícito (não retornar plano-sem-tasks ao usuário; foi exatamente isso que motivou o bug do PLAN-006).
@@ -16,6 +16,34 @@ metadata:
16
16
 
17
17
  You are operating as a **Tasks Writer** for the G-OS project, following the G-OS Agent-Driven Agile methodology.
18
18
 
19
+ ## UI Guardrails embarcados (CRITICO para tasks de UI)
20
+
21
+ Toda task com `area: ui-ux` ou `area: frontend` que represente uma tela DEVE nascer com seções obrigatórias para evitar que codegen gere UI incompleta (gargalo conhecido do framework):
22
+
23
+ ```markdown
24
+ ## Estados visuais
25
+ - [ ] Loading: <skeleton ou spinner declarado>
26
+ - [ ] Empty: <copy + ilustracao + CTA>
27
+ - [ ] Error: <mensagem + recovery>
28
+ - [ ] Success (se aplicavel): <toast/inline>
29
+
30
+ ## Responsividade
31
+ - [ ] Mobile (<768px): <comportamento>
32
+ - [ ] Tablet: <comportamento>
33
+ - [ ] Desktop: <default>
34
+
35
+ ## A11y minimo
36
+ - [ ] Roles ARIA aplicados
37
+ - [ ] aria-label em icon buttons
38
+ - [ ] Focus order definido (>3 elementos)
39
+ - [ ] Contraste AA verificado
40
+
41
+ ## Tokens DS
42
+ - [ ] 0 valores hardcoded fora do scale do DS
43
+ ```
44
+
45
+ Detalhe: ver `libraries/ui-guardrails-checklist.md`. Validacao final: `*ui-guardrails <plan-dir>` (chamado por plan-blueprint apos plan-to-tasks). Em planos com `descartavel: true`, secoes viram warning.
46
+
19
47
  ## Input
20
48
  $ARGUMENTS
21
49
 
@@ -56,7 +84,15 @@ Campos obrigatórios do frontmatter (do `taskTemplate.md`, presentes em CADA T-N
56
84
  - **`status: pendente`** — invariante. Sem isso o `progress-tracker` não consegue transicionar e o `*execute-plan`/`*validate-plan` quebram.
57
85
  - `valida_em`, `depends_on_backend: []`, `interaction_target: []`, `override_target: []`, `assignees: []`, `links: []`
58
86
 
59
- Body: copiar as seções do `taskTemplate.md` (`## Contexto`, `## Objetivo`, `## Plano de execução`, `## Critérios de aceitação (DoD)`, `## Riscos & Rollback`) — **NÃO** adicionar seção `## Status` no body. Status vive APENAS no frontmatter.
87
+ Body: copiar as seções do `taskTemplate.md` — **NÃO** adicionar seção `## Status` no body. Status vive APENAS no frontmatter.
88
+
89
+ **Modelo O QUE / ONDE / COMO / POR QUE (obrigatório)**: toda task gerada DEVE responder às 4 perguntas, sem placeholder:
90
+ - **POR QUE** → `## Contexto` (gap/motivação, link ao plano pai).
91
+ - **O QUE** → `## Objetivo` + `### Entrega` (entregável observável).
92
+ - **ONDE** → `## Arquivos` (tabela com `criar`/`editar`/`deletar` + path exato — extraído do `context.md` `## Arquivos relevantes` e do `## Plano de execução` do plano pai).
93
+ - **COMO** → `## Plano de execução` (passos acionáveis).
94
+
95
+ Task com `## Arquivos` vazio ou genérico (sem path concreto) é malformada — o executor não pode adivinhar onde mexer. Regenerar.
60
96
 
61
97
  ### Phase 3.5 — Verificação pós-geração (gate)
62
98