Habilidade de Timeboxer de Agenda de Reunião
De Wikiprompt, a enciclopédia livre de prompts
Habilidade de Timeboxer de Agenda de Reunião Uma skill/agente completa que transforma uma lista bruta de tópicos de reunião em uma agenda com tempo definido, responsáveis, resultados esperados, verificações de margem e detecção de "cheiro de agenda". Inclui um script em Python para agendamento e ajuste, além de materiais de referência e um exemplo prático.
Conteúdo do PromptSalvar
🌐
---
name: agenda-reuniao-com-tempo-limitado
description: Transforma uma lista bruta de tópicos de reunião em uma pauta com blocos de tempo, horários de início e término, responsáveis e um resultado claro para cada item (informar, discutir, decidir, brainstorm, revisar), verifica se cabe no horário com uma margem de segurança, sinaliza problemas de pauta como decisões atrasadas ou apressadas, muitos updates de status, itens grandes demais e falta de pausas, e escreve uma pauta pronta para envio e leitura prévia. Use quando um usuário pedir "me ajude a planejar esta reunião", "esta pauta cabe em uma hora?", "deixe esta pauta mais enxuta", ou compartilhar uma lista de tópicos para uma reunião de equipe, workshop, offsite ou revisão.
---
# Organizador de Pauta com Tempo Limitado
Você ajuda pessoas a conduzir reuniões que terminam no horário e produzem decisões. Você transforma uma lista de tópicos em um cronograma realista, dá a cada item um responsável e um propósito, tira os updates de status da sala, e torna a matemática do tempo visível para que ninguém descubra no minuto 55 que a decisão principal não tem mais tempo.
## Arquivos nesta habilidade
- `scripts/timebox_agenda.py` - agenda cada item, verifica o ajuste com o horário e a margem de segurança, sinaliza problemas de pauta, e pode ajustar os itens ao horário em passos de 5 minutos (apenas biblioteca padrão do Python 3)
- `references/timeboxing-principles.md` - quanto tempo as coisas realmente levam, resultados dos itens, ordenação, margens de segurança e pausas
- `references/facilitation-moves.md` - técnicas para manter cada tipo de item dentro do seu bloco de tempo, e o que fazer quando um estourar
- `templates/agenda.md` - o formato de entrada da pauta e a pauta para enviar
- `examples/example-roadmap-meeting.md` - um exemplo corrigido de uma reunião de planejamento de uma hora sobrecarregada
## Fluxo de trabalho
### 1. Colete os fatos
Pergunte, ou assuma e diga:
- Propósito da reunião em uma frase: o que deve ser verdade quando ela terminar?
- Horário de início e duração (ou horário de término), número de participantes, presencial ou remoto.
- Tópicos, cada um com um responsável e o que o grupo deve fazer com ele: informar, atualizar, discutir, brainstorm, revisar ou decidir.
- Restrições rígidas: pessoas que chegam atrasadas ou saem cedo, pausas fixas.
### 2. Escreva o rascunho da pauta
Use o formato de entrada em `templates/agenda.md` (uma linha por item: `minutos | tópico | responsável | resultado`). Use `?` para uma duração que ninguém sabe ainda. Estime as durações com `references/timeboxing-principles.md`.
### 3. Execute o organizador de tempo
```bash
python3 scripts/timebox_agenda.py agenda.txt
python3 scripts/timebox_agenda.py agenda.txt --fit # ajusta ao horário em passos de 5 minutos
python3 scripts/timebox_agenda.py agenda.json --json
```
Ele imprime o cronograma com horários de relógio, a margem de segurança e os achados: ALTO quando a pauta não cabe, AVISO para problemas, INFO para tempo não planejado e o custo da reunião em horas-pessoa. `--fit` corta itens de status primeiro, depois ajusta todo o resto; ele nunca reordena itens, então verifique a ordem você mesmo depois.
Se você não puder executar o script, faça a matemática do relógio manualmente, item por item, e diga isso.
### 4. Corrija a pauta, não apenas os números
Trabalhe nos achados nesta ordem:
1. Remova ou reduza updates de status e anúncios: mova-os para uma leitura prévia escrita.
2. Coloque as decisões no início (primeira metade) e dê a cada uma pelo menos 10 minutos mais uma proposta escrita enviada com antecedência.
3. Dê a cada item um responsável e um resultado; remova "AOB" ou transforme-o em uma revisão de 5 minutos do estacionamento.
4. Divida itens com mais de 45 minutos; adicione uma pausa a cada 60 a 90 minutos.
5. Se ainda não couber, proponha o que cortar ou mover para outra reunião ou para assíncrono, e diga o que se perde.
Execute o script novamente até não haver achados ALTO e todo AVISO esteja corrigido ou explicado.
### 5. Entregue
Preencha a pauta para enviar de `templates/agenda.md`: propósito, resultados desejados, o cronograma com horários, leituras prévias com responsáveis e prazos, e a regra do estacionamento. Adicione uma ou duas dicas de facilitação por item arriscado de `references/facilitation-moves.md`. Siga o estilo de `examples/example-roadmap-meeting.md`.
## Regras
- Nunca faça a matemática funcionar reduzindo uma decisão abaixo do que ela precisa; corte ou mova outra coisa, ou recomende um horário mais longo.
- Mantenha uma margem de segurança: cerca de 5 minutos por hora, 10 por cento para workshops.
- Diga claramente quando uma reunião não deve acontecer (sem decisões, nada para discutir) e sugira a alternativa assíncrona.
- Respeite a cultura e as restrições do usuário; sugira, não dê lições.
- Os horários são locais para a reunião; para participantes remotos em outros fusos, mencione, mas não converta a menos que peçam.
## Princípios de blocos de tempo
### Cada item precisa de um resultado
| Resultado | O que o grupo faz | Tempo típico | Notas |
|---|---|---|---|
| informar | Ouvir algo, fazer uma pergunta de esclarecimento | 2 a 5 min | Melhor como leitura prévia escrita. |
| atualizar | Status de pessoas ou equipes | 1 a 2 min por pessoa | Geralmente assíncrono; mantenha apenas bloqueios ao vivo. |
| discutir | Explorar um tópico, compartilhar visões, sem decisão ainda | 10 a 20 min | Diga o que a discussão alimenta (uma decisão na próxima semana, um documento). |
| brainstorm | Gerar opções | 15 a 30 min | Precisa de uma pergunta enquadrada e um método (escrita silenciosa primeiro). |
| revisar | Dar feedback sobre um rascunho, design ou plano | 15 a 40 min | Envie o material com antecedência; combine que tipo de feedback é desejado. |
| decidir | Escolher entre opções e se comprometer | 10 a 30 min | Precisa de uma proposta escrita, as opções, o tomador de decisão e a regra de decisão. |
| pausa | Descansar | 5 a 15 min | A cada 60 a 90 minutos. |
Se um item não tem um resultado claro, pergunte: "O que será diferente depois deste item?" Se a resposta for "nada", corte-o.
### Quanto tempo as coisas realmente levam
- Apresentações: cerca de 1 minuto por pessoa para um grupo novo, 0 para uma equipe regular.
- Cada pessoa falando uma vez sobre um tópico: cerca de 1,5 a 2 minutos por pessoa. Oito pessoas, uma rodada, são 15 minutos.
- Compartilhamento de tela e início: 2 a 3 minutos, mais para reuniões remotas com novas ferramentas.
- Uma decisão com desacordo real: dobre a estimativa, ou divida em "discutir" agora e "decidir" na próxima vez.
- Itens no final da pauta andam mais rápido, mas pior: as pessoas se apressam ou saem.
### Ordenação
1. Comece com um enquadramento curto: propósito e resultados desejados (2 a 5 min).
2. Decisões e os tópicos mais difíceis na primeira metade, enquanto a energia e a presença estão altas.
3. Discussão e revisão no meio.
4. Informações e updates por último ou fora da reunião inteiramente.
5. Termine com próximos passos, responsáveis e datas (5 min), nunca com AOB.
Agrupe itens que precisam das mesmas pessoas, para que outros possam sair cedo.
### Margens de segurança e pausas
- Margem de segurança: cerca de 5 minutos por hora, 10 por cento para workshops. A margem faz parte do horário, não é tempo extra.
- Pausas: 5 a 10 minutos a cada 60 a 90 minutos; 15 para workshops mais longos. Reuniões remotas precisam de pausas mais cedo.
- Calendários consecutivos: termine 5 minutos antes (reuniões de 25 ou 50 minutos).
### Verificações de ajuste
- Mais de cerca de 8 itens por hora significa que cada um recebe menos de 7 minutos; mescle ou corte.
- Status e anúncios acima de cerca de um terço do tempo: mova-os para uma leitura prévia.
- Um item com mais de 45 minutos: divida-o em etapas com seus próprios resultados (por exemplo, "brainstorm 25" e depois "agrupar e escolher 20").
### O custo de uma reunião
Horas-pessoa = participantes x duração em horas. Uma reunião de uma hora com 9 pessoas custa 9 horas de trabalho. Pergunte se todos precisam estar lá para cada item.
## Movimentos de facilitação que mantêm os blocos de tempo
### Antes da reunião
- Envie a pauta e as leituras prévias 24 a 48 horas antes, com o responsável de cada item.
- Para cada item de decisão, envie uma proposta de uma página: a pergunta, opções, recomendação e quem decide.
- Peça às pessoas para adicionar perguntas à leitura prévia por escrito, para que a reunião comece com perguntas, não com uma apresentação.
### No início
- Declare o propósito e os resultados que você precisa até o final.
- Nomeie um cronometrista e combine o sinal (uma mensagem no chat, uma mão levantada com 2 minutos restantes).
- Diga como as decisões são tomadas hoje: o responsável decide após contribuições, voto majoritário ou consentimento ("alguma objeção forte?").
### Por tipo de item
- Informar: "Dois minutos, depois uma pergunta de esclarecimento cada." Perguntas detalhadas vão para o estacionamento ou para um chat de acompanhamento.
- Atualizar: Apenas bloqueios e pedidos ao vivo; todo o resto está na leitura prévia.
- Discutir: Enquadre a pergunta primeiro ("O que nos preocupa sobre a opção B?"). Use uma rodada rápida para que todos falem uma vez antes de alguém falar duas vezes.
- Brainstorm: 3 a 5 minutos de escrita silenciosa primeiro, depois compartilhe, depois agrupe. Quantidade antes do julgamento.
- Revisar: Combine o tipo de feedback: problemas bloqueadores, perguntas ou polimento. Colete problemas bloqueadores primeiro.
- Decidir: Reafirme a proposta, liste preocupações, verifique objeções, depois decida e diga em voz alta: "Decidimos X; responsável Y; até a data Z."
### Quando um item estoura
Torne a escolha visível em vez de silenciosamente comer o próximo item:
1. "Temos 2 minutos restantes nisso. Estendemos por 5 minutos e cortamos outra coisa, ou estacionamos?"
2. Estacione: escreva no estacionamento com um responsável e uma data.
3. Reduza o próximo item, nunca os itens de decisão.
4. Se o objetivo da reunião estiver em risco, agende um acompanhamento curto com apenas as pessoas necessárias.
### Remoto e híbrido
- Todos entram em seus próprios dispositivos para que os remotos sejam iguais.
- Use o chat para a fila de fala e para enquetes rápidas.
- Compartilhe a pauta na tela com o item atual destacado.
### No final
- Leia de volta decisões, responsáveis e datas (5 minutos).
- Revise o estacionamento: atribua cada item ou descarte-o.
- Envie as notas dentro de 24 horas.
## Entrada da pauta (para scripts/timebox_agenda.py)
```
Reunião: <nome>
Início: <HH:MM>
Duração: <minutos> # ou Término: <HH:MM>
Margem: <minutos ou percentual, ex: 5 ou 10%>
Participantes: <número>
<minutos> | <tópico> | <responsável> | <informar | atualizar | discutir | brainstorm | revisar | decidir | pausa>
? | <tópico com duração desconhecida> | <responsável> | <resultado>
```
Uma tabela Markdown com as colunas Min, Tópico, Responsável, Resultado também funciona, assim como JSON:
`{"meeting": "...", "start": "14:00", "length": 60, "buffer": 5, "attendees": 6, "items": [{"minutes": 10, "topic": "...", "owner": "...", "outcome": "decide"}]}`
---
# Pauta para enviar
**<Nome da reunião>**
<Dia, data>, <início>-<término> (<duração> min), <local ou link de vídeo>
Participantes: <nomes ou equipes> | Facilitador: <nome> | Cronometrista: <nome> | Notas: <nome>
**Propósito:** <uma frase: o que deve ser verdade quando terminarmos>
**Resultados que precisamos**
1. <decisão ou resultado>
2. <decisão ou resultado>
**Leitura prévia (até <dia, hora>)**
- <documento> - <responsável> - <o que olhar, quanto tempo leva para ler>
**Cronograma**
| Hora | Min | Item | Responsável | Resultado |
|---|---|---|---|---|
| <HH:MM-HH:MM> | <n> | <tópico> | <responsável> | <resultado> |
| <HH:MM-HH:MM> | <n> | Margem e encerramento: decisões, responsáveis, datas | <facilitador> | |
**Como decidimos hoje:** <responsável decide após contribuições | consentimento | voto>
**Estacionamento:** Pontos fora do assunto vão para o estacionamento e recebem um responsável no final.
**Movido para fora desta reunião**
- <item> -> <update assíncrono, outra reunião ou um documento>, responsável <nome>
## Exemplo: corrigindo uma reunião de planejamento de uma hora sobrecarregada
### O pedido
"Tenho uma hora com 9 pessoas na quinta às 14:00 para planejar o Q4. Aqui está minha pauta. Vai caber? A divisão do orçamento deve ser aprovada nesta reunião, e as 3 principais iniciativas também."
Rascunho da pauta (`agenda.txt`):
```
Reunião: Planejamento do roadmap Q4
Início: 14:00
Duração: 60
Margem: 5
Participantes: 9
10 | Boas-vindas e objetivos | Dana | informar
15 | Rodada de status da equipe (cada líder) | Líderes | atualizar
10 | Destaques do feedback do cliente | Priya | informar
20 | Prioridades Q4: escolher as 3 principais iniciativas | Lee | discutir
10 | Plano de contratação para Q4 | | discutir
5 | Aprovar divisão do orçamento Q4 | Dana | decidir
? | AOB | |
```
### Primeira execução
```
$ python3 scripts/timebox_agenda.py agenda.txt
Planejamento do roadmap Q4: 14:00-15:00 (60 min, margem 5 min, 55 min para itens)
Planejado: 70 min
14:00-14:10 10 min Boas-vindas e objetivos (Dana) [informar]
14:10-14:25 15 min Rodada de status da equipe (cada líder) (Líderes) [atualizar]
14:25-14:35 10 min Destaques do feedback do cliente (Priya) [informar]
14:35-14:55 20 min Prioridades Q4: escolher as 3 principais iniciativas (Lee) [discutir]
14:55-15:05 10 min Plano de contratação para Q4 [discutir]
15:05-15:10 5 min Aprovar divisão do orçamento Q4 (Dana) [decidir]
15:10-15:10 ? min AOB [?]
14:55-15:00 5 min Margem / encerramento
Achados:
- [ALTO] A pauta precisa de 70 min, mas apenas 55 min estão disponíveis após a margem de 5 min: estouro de 15 min (termina às 15:10 em vez de 14:55). Corte, reduza ou mova itens, ou execute com --fit.
- [AVISO] 1 item(ns) sem duração: AOB. Tempo restante para eles: 0 min.
- [AVISO] "Plano de contratação para Q4" não tem responsável; nomeie quem prepara e lidera.
- [AVISO] "Aprovar divisão do orçamento Q4" é uma decisão com apenas 5 min; planeje pelo menos 10, ou decida por uma proposta escrita com antecedência.
- [AVISO] "Aprovar divisão do orçamento Q4" é uma decisão começando às 15:05, no último quarto da reunião; mova-a para mais cedo enquanto a energia e a presença estão altas.
- [AVISO] "AOB" não tem responsável; nomeie quem prepara e lidera.
- [AVISO] "AOB" não tem resultado; diga se é para informar, discutir, decidir ou brainstorm.
- [AVISO] Updates de status e anúncios ocupam 50% do tempo; envie-os como leitura prévia e mantenha a reunião para discussão e decisões.
- [INFO] Custo da reunião: 9 pessoas x 60 min = 9 horas-pessoa.
```
Código de saída 1: a pauta não cabe.
### O que os números dizem
- 70 minutos de itens (mais AOB) em uma janela de 55 minutos: 15 minutos de estouro antes mesmo do AOB começar.
- Metade do tempo é de updates e anúncios, enquanto as duas coisas que devem ser decididas recebem 5 minutos (orçamento) e um rótulo "discutir" (prioridades), e a decisão do orçamento começaria às 15:05, depois que a reunião deveria ter terminado.
- Executar `--fit` sozinho espremeria tudo em 55 minutos, mas deixaria a decisão do orçamento por último com 5 minutos. Ajustar os números não é suficiente; a ordem e o propósito dos itens têm que mudar.
### Mudanças
1. Rodada de status da equipe (15 min) e destaques do feedback do cliente (10 min) tornam-se uma leitura prévia escrita com vencimento na quarta às 12:00; perguntas vão nos comentários.
2. A divisão do orçamento vai para o início com 10 minutos e uma proposta enviada na segunda, para que a reunião apenas confirme ou ajuste.
3. "Prioridades Q4" torna-se uma decisão com 25 minutos: o resultado é um top 3 classificado.
4. O plano de contratação ganha um responsável (Priya) e uma pergunta mais restrita: quais cargos abrir.
5. AOB é substituído por um encerramento de 5 minutos de "próximos passos, responsáveis e estacionamento".
6. Três pessoas necessárias apenas para a rodada de status podem pular a reunião: 6 participantes em vez de 9.
Pauta revisada:
```
Reunião: Planejamento do roadmap Q4
Início: 14:00
Duração: 60
Margem: 5
Participantes: 6
5 | Boas-vindas e objetivos de hoje | Dana | informar
10 | Aprovar divisão do orçamento Q4 (proposta enviada na segunda) | Dana | decidir
25 | Prioridades Q4: escolher as 3 principais iniciativas | Lee | decidir
10 | Plano de contratação para Q4: concordar quais cargos abrir | Priya | discutir
5 | Próximos passos, responsáveis e estacionamento | Dana | informar
```
### Segunda execução
```
$ python3 scripts/timebox_agenda.py agenda-revisada.txt
Planejamento do roadmap Q4: 14:00-15:00 (60 min, margem 5 min, 55 min para itens)
Planejado: 55 min
14:00-14:05 5 min Boas-vindas e objetivos de hoje (Dana) [informar]
14:05-14:15 10 min Aprovar divisão do orçamento Q4 (proposta enviada na segunda) (Dana) [decidir]
14:15-14:40 25 min Prioridades Q4: escolher as 3 principais iniciativas (Lee) [decidir]
14:40-14:50 10 min Plano de contratação para Q4: concordar quais cargos abrir (Priya) [discutir]
14:50-14:55 5 min Próximos passos, responsáveis e estacionamento (Dana) [informar]
14:55-15:00 5 min Margem / encerramento
Achados:
- [INFO] Custo da reunião: 6 pessoas x 60 min = 6 horas-pessoa.
```
Código de saída 0, sem avisos, e a reunião custa 6 horas-pessoa em vez de 9.
### A pauta para enviar (modelo preenchido, resumido)
**Planejamento do roadmap Q4**
Quinta-feira, 14:00-15:00 (60 min), Sala 3 e link de vídeo
Facilitador: Dana | Cronometrista: Lee | Notas: Priya
**Propósito:** Sair com uma divisão do orçamento Q4 aprovada e um top 3 classificado de iniciativas.
**Leitura prévia (até quarta às 12:00)**
- Resumos de status da equipe - cada líder de equipe - 5 min para ler
- Destaques do feedback do cliente - Priya - 5 min
- Proposta de divisão do orçamento - Dana - 10 min
**Cronograma**
| Hora | Min | Item | Responsável | Resultado |
|---|---|---|---|---|
| 14:00-14:05 | 5 | Boas-vindas e objetivos de hoje | Dana | informar |
| 14:05-14:15 | 10 | Aprovar divisão do orçamento Q4 (proposta enviada na segunda) | Dana | decidir |
| 14:15-14:40 | 25 | Prioridades Q4: escolher as 3 principais iniciativas | Lee | decidir |
| 14:40-14:50 | 10 | Plano de contratação para Q4: concordar quais cargos abrir | Priya | discutir |
| 14:50-14:55 | 5 | Próximos passos, responsáveis e estacionamento | Dana | informar |
| 14:55-15:00 | 5 | Margem | | |
**Como decidimos hoje:** Dana decide o orçamento após contribuições; o top 3 é escolhido por consentimento (alguma objeção forte?).
**Dicas de facilitação**
- Prioridades: 3 minutos de votação silenciosa com pontos na lista de candidatos, depois discuta apenas os itens classificados de 2 a 5.
- Se o item do orçamento atingir 10 minutos, estacione o ponto em aberto com um responsável e um prazo de 24 horas em vez de comer o tempo das prioridades.
**Movido para fora desta reunião:** rodada de status da equipe e feedback do cliente (leitura prévia).
### Por que esta é uma boa resposta
- Corrige o propósito e a ordem, não apenas os minutos.
- Ambas as decisões necessárias agora acontecem nos primeiros 40 minutos, com propostas preparadas.
- O script confirma o ajuste, e as pessoas que estavam lá apenas para updates recuperam sua hora.
## Script Python: timebox_agenda.py
```python
#!/usr/bin/env python3
"""Agenda uma reunião com blocos de tempo: agenda cada item, verifica o ajuste e sinaliza problemas de pauta.
Uso:
python3 timebox_agenda.py agenda.txt
python3 timebox_agenda.py agenda.txt --fit # ajusta itens ao horário (passos de 5 minutos)
python3 timebox_agenda.py agenda.json --json
cat agenda.txt | python3 timebox_agenda.py -
Entrada de texto: linhas de cabeçalho opcionais "Chave: valor", depois um item por linha como
minutos | tópico | responsável | resultado
Linhas de tabela Markdown (| 10 | Tópico | Responsável | decidir |) também funcionam; linhas de cabeçalho e
separador são ignoradas. Use ? para uma duração desconhecida.
Chaves de cabeçalho: Reunião, Início (HH:MM), Duração (minutos) ou Término (HH:MM),
Margem (minutos ou percentual, ex: 5 ou 10%), Participantes (número).
Resultados: informar, atualizar, discutir, brainstorm, revisar, decidir, pausa.
Entrada JSON: {"meeting": "...", "start": "14:00", "length": 60, "buffer": 5,
"attendees": 8, "items": [{"minutes": 10, "topic": "...", "owner": "...", "outcome": "decide"}]}
--fit corta itens de status (e itens sem resultado) primeiro, depois ajusta tudo; o tempo extra vai para
itens de decidir e discutir.
Verificações: estouro (ALTO), durações, responsáveis ou resultados ausentes, decisões atrasadas ou
apressadas, itens grandes demais, longos períodos sem pausa, muitos updates de status,
muitos itens por hora, além do custo da reunião em horas-pessoa.
Código de saída: 0 sem achados ALTO, 1 ALTO encontrado, 2 erro de uso ou entrada.
Apenas biblioteca padrão.
"""
import argparse
import json
import math
import re
import sys
OUTCOMES = {"informar", "atualizar", "discutir", "brainstorm", "revisar", "decidir", "pausa"}
ALIASES = {"decisão": "decidir", "info": "informar", "fyi": "informar", "status": "atualizar", "updates": "atualizar",
"discussão": "discutir", "ideias": "brainstorm", "ideação": "brainstorm", "feedback": "revisar",
"aprovar": "decidir", "aprovação": "decidir", "pausa": "pausa", "café": "pausa"}
class InputError(Exception):
pass
def hhmm(texto):
m = re.fullmatch(r"\s*(\d{1,2})[:.](\d{2})\s*", str(texto))
if not m or int(m.group(1)) > 23 or int(m.group(2)) > 59:
raise InputError(f"o tempo deve ser HH:MM, obtido {texto!r}")
return int(m.group(1)) * 60 + int(m.group(2))
def fmt(minutos):
minutos = int(round(minutos)) % (24 * 60)
return f"{minutos // 60:02d}:{minutos % 60:02d}"
def parse_minutes(texto):
t = str(texto).strip().lower()
if t in ("", "?", "tbd", "-"):
return None
m = re.fullmatch(r"(\d+(?:\.\d+)?)\s*(m|min|mins|minutos?)?", t)
if m:
return float(m.group(1))
m = re.fullmatch(r"(\d+(?:\.\d+)?)\s*h(?:oras?)?(?:\s*(\d+)\s*m(?:in)?)?", t)
if m:
return float(m.group(1)) * 60 + float(m.group(2) or 0)
raise InputError(f"não foi possível ler a duração {texto!r}")
def norm_outcome(texto):
t = (texto or "").strip().lower()
return ALIASES.get(t, t)
def parse_text(texto):
meta, itens, erros = {}, [], []
for no, bruto in enumerate(texto.replace("\r\n", "\n").split("\n"), 1):
linha = bruto.strip()
if not linha or linha.startswith("#"):
continue
hm = re.fullmatch(r"([A-Za-zÀ-ÿ ]{3,20}):\s*(.+)", linha)
if hm and "|" not in linha:
meta[hm.group(1).strip().lower()] = hm.group(2).strip()
continue
if "|" not in linha:
erros.append(f"linha {no}: esperado 'minutos | tópico | responsável | resultado', obtido {linha[:60]!r}")
continue
celulas = [c.strip() for c in linha.strip("|").split("|")]
if all(re.fullmatch(r":?-{2,}:?", c) for c in celulas if c):
continue
if celulas and celulas[0].lower() in ("min", "mins", "minutos", "tempo", "duração"):
continue
celulas += [""] * (4 - len(celulas))
try:
minutos = parse_minutes(celulas[0])
except InputError as e:
erros.append(f"linha {no}: {e}")
continue
if not celulas[1]:
erros.append(f"linha {no}: item não tem tópico")
continue
itens.append({"linha": no, "minutos": minutos, "tópico": celulas[1], "responsável": celulas[2],
"resultado": norm_outcome(celulas[3])})
return meta, itens, erros
def parse_json(texto):
dados = json.loads(texto)
if not isinstance(dados, dict) or not isinstance(dados.get("items"), list):
raise InputError("entrada JSON precisa de um objeto com uma lista 'items'")
meta = {k.lower(): str(v) for k, v in dados.items() if k != "items" and v is not None}
itens, erros = [], []
for i, it in enumerate(dados["items"], 1):
try:
minutos = parse_minutes(it.get("minutes", ""))
except InputError as e:
erros.append(f"item {i}: {e}")
continue
if not str(it.get("topic", "")).strip():
erros.append(f"item {i}: item não tem tópico")
continue
itens.append({"linha": i, "minutos": minutos, "tópico": str(it["topic"]).strip(),
"responsável": str(it.get("owner", "") or "").strip(), "resultado": norm_outcome(it.get("outcome", ""))})
return meta, itens, erros
def settings(meta):
inicio = hhmm(meta.get("início", meta.get("start", "09:00")))
if "duração" in meta:
duracao = parse_minutes(meta["duração"])
if not duracao or duracao <= 0:
raise InputError("Duração deve ser um número positivo de minutos")
elif "término" in meta:
duracao = (hhmm(meta["término"]) - inicio) % (24 * 60)
if duracao == 0:
raise InputError("Término deve ser depois do Início")
else:
raise InputError("cabeçalho precisa de 'Duração: <minutos>' ou 'Término: HH:MM'")
b = meta.get("margem", meta.get("buffer", "0")).strip()
if b.endswith("%"):
margem = 5 * round(duracao * float(b[:-1]) / 100 / 5) # margens percentuais arredondam para 5 minutos
else:
margem = parse_minutes(b) or 0
if margem >= duracao:
raise InputError("Margem deve ser menor que a reunião")
participantes = int(meta["participantes"]) if str(meta.get("participantes", "")).strip().isdigit() else None
return {"reunião": meta.get("reunião", meta.get("título", meta.get("meeting", "Reunião"))), "início": inicio, "duração": duracao,
"margem": margem, "disponível": duracao - margem, "participantes": participantes}
def fit(itens, disponível):
"""Ajusta itens em `disponível` minutos em passos de 5 minutos (durações ausentes contam como 10, pausas mantidas).
Quando a pauta é longa demais, itens de status (informar, atualizar ou sem resultado) são cortados primeiro, até metade
do tempo planejado; depois cada item é ajustado proporcionalmente. Quando é curta demais, o
tempo extra vai para itens de decidir e discutir primeiro.
"""
fixo = sum(it["minutos"] or 0 for it in itens if it["resultado"] == "pausa")
flex = [it for it in itens if it["resultado"] != "pausa"]
espaco = disponível - fixo
if not flex or espaco < 5 * len(flex):
raise InputError(f"não é possível ajustar {len(flex)} itens em {espaco:g} minutos com pelo menos 5 minutos cada")
quer = [max(5, 5 * round((it["minutos"] or 10) / 5)) for it in flex]
atual = list(quer)
status = [i for i, it in enumerate(flex) if it["resultado"] in ("informar", "atualizar", "")]
while sum(atual) > espaco:
cands = [i for i in status if atual[i] - 5 >= max(5, quer[i] / 2)]
if not cands:
break
atual[max(cands, key=lambda k: atual[k])] -= 5
if sum(atual) > espaco:
escala = espaco / sum(atual)
ref = [c * escala for c in atual]
atual = [max(5, 5 * round(r / 5)) for r in ref]
while sum(atual) > espaco:
cands = [k for k in range(len(atual)) if atual[k] > 5]
atual[max(cands, key=lambda k: (atual[k] - ref[k], atual[k]))] -= 5
while sum(atual) + 5 <= espaco:
atual[min(range(len(atual)), key=lambda k: atual[k] - ref[k])] += 5
else:
prio = [i for i, it in enumerate(flex) if it["resultado"] in ("decidir", "discutir")] or list(range(len(flex)))
while sum(atual) + 5 <= espaco:
atual[min(prio, key=lambda k: atual[k] / quer[k])] += 5
saida, it_novo = [], iter(atual)
for it in itens:
copia = dict(it)
copia["original"] = it["minutos"]
if it["resultado"] != "pausa":
copia["minutos"] = float(next(it_novo))
saida.append(copia)
return saida
def analyze(itens, cfg):
achados = []
def add(sev, msg):
achados.append({"severidade": sev, "mensagem": msg})
t = cfg["início"]
for it in itens:
it["início"] = t
t += it["minutos"] or 0
it["fim"] = t
planejado = sum(it["minutos"] or 0 for it in itens)
disp, fim_slot = cfg["disponível"], cfg["início"] + cfg["duração"]
desconhecidos = [it for it in itens if it["minutos"] is None]
if planejado > disp:
add("ALTO", f"A pauta precisa de {planejado:g} min, mas apenas {disp:g} min estão disponíveis"
f"{' após a margem de ' + format(cfg['margem'], 'g') + ' min' if cfg['margem'] else ''}: estouro de {planejado - disp:g} min"
f" (termina às {fmt(cfg['início'] + planejado)} em vez de {fmt(fim_slot - cfg['margem'])}). Corte, reduza ou mova itens, ou execute com --fit.")
elif disp - planejado > 0.15 * disp and not desconhecidos:
add("INFO", f"{disp - planejado:g} min não planejados; termine cedo ou dê mais tempo à decisão principal.")
if desconhecidos:
add("AVISO", f"{len(desconhecidos)} item(ns) sem duração: " + "; ".join(it["tópico"][:40] for it in desconhecidos)
+ f". Tempo restante para eles: {max(disp - planejado, 0):g} min.")
for it in itens:
nome = f"\"{it['tópico'][:50]}\""
if it["resultado"] != "pausa" and not it["responsável"]:
add("AVISO", f"{nome} não tem responsável; nomeie quem prepara e lidera.")
if not it["resultado"]:
add("AVISO", f"{nome} não tem resultado; diga se é para informar, discutir, decidir ou brainstorm.")
elif it["resultado"] not in OUTCOMES:
add("AVISO", f"{nome} tem resultado desconhecido '{it['resultado']}' (use: {', '.join(sorted(OUTCOMES))}).")
m = it["minutos"] or 0
if it["resultado"] == "decidir":
if it["minutos"] is not None and m < 10:
add("AVISO", f"{nome} é uma decisão com apenas {m:g} min; planeje pelo menos 10, ou decida por uma proposta escrita com antecedência.")
if it["início"] - cfg["início"] >= 0.75 * cfg["duração"]:
add("AVISO", f"{nome} é uma decisão começando às {fmt(it['início'])}, no último quarto da reunião; mova-a para mais cedo enquanto a energia e a presença estão altas.")
if it["resultado"] in ("discutir", "brainstorm", "revisar") and it["minutos"] is not None and m < 5:
add("AVISO", f"{nome} é um item de {it['resultado']} com {m:g} min; isso é uma menção, não um {it['resultado']}.")
if m > 45 and it["resultado"] != "pausa":
add("AVISO", f"{nome} tem {m:g} min de duração; divida-o em partes com seus próprios resultados.")
trecho, inicio_trecho = 0, cfg["início"]
for it in itens:
if it["resultado"] == "pausa":
trecho, inicio_trecho = 0, it["fim"]
continue
trecho += it["minutos"] or 0
if trecho > 90:
add("AVISO", f"{trecho:g} min sem pausa desde {fmt(inicio_trecho)}; adicione uma pausa de 5 a 10 min a cada 60 a 90 min.")
trecho = -10**9
status = sum(it["minutos"] or 0 for it in itens if it["resultado"] in ("informar", "atualizar"))
if planejado and status / planejado > 0.35:
add("AVISO", f"Updates de status e anúncios ocupam {round(100 * status / planejado)}% do tempo; envie-os como leitura prévia e mantenha a reunião para discussão e decisões.")
itens_trabalho = [it for it in itens if it["resultado"] != "pausa"]
horas = cfg["duração"] / 60
if horas and len(itens_trabalho) / horas > 8:
add("AVISO", f"{len(itens_trabalho)} itens em {cfg['duração']:g} min é mais de 8 por hora; mescle ou remova itens.")
if not any(it["resultado"] == "decidir" for it in itens):
add("INFO", "Nenhum item de decisão; verifique se esta reunião precisa ser ao vivo.")
custo = None
if cfg["participantes"]:
custo = round(cfg["participantes"] * cfg["duração"] / 60, 1)
add("INFO", f"Custo da reunião: {cfg['participantes']} pessoas x {cfg['duração']:g} min = {custo:g} horas-pessoa.")
ordem = {"ALTO": 0, "AVISO": 1, "INFO": 2}
achados.sort(key=lambda f: ordem[f["severidade"]])
return {"reunião": cfg["reunião"], "início": fmt(cfg["início"]), "fim": fmt(fim_slot), "duração": cfg["duração"],
"margem": cfg["margem"], "disponível": disp, "planejado": planejado, "horas_pessoa": custo,
"itens": [{k: (fmt(v) if k in ("início", "fim") else v) for k, v in it.items()} for it in itens],
"achados": achados}
def main():
ap = argparse.ArgumentParser(description="Agenda uma reunião com blocos de tempo")
ap.add_argument("caminho", help="arquivo de pauta texto/Markdown/JSON, ou - para stdin")
ap.add_argument("--fit", action="store_true", help="ajusta durações dos itens ao tempo disponível")
ap.add_argument("--json", action="store_true")
args = ap.parse_args()
try:
texto = sys.stdin.read() if args.caminho == "-" else open(args.caminho, encoding="utf-8").read()
if not texto.strip():
raise InputError("entrada vazia")
meta, itens, erros = parse_json(texto) if texto.lstrip().startswith("{") else parse_text(texto)
if erros:
raise InputError("não foi possível ler a pauta:\n " + "\n ".join(erros))
if not itens:
raise InputError("nenhum item de pauta encontrado (esperado linhas como '10 | Tópico | Responsável | decidir')")
cfg = settings(meta)
antes = sum(it["minutos"] or 0 for it in itens)
n_desconhecidos = sum(1 for it in itens if it["minutos"] is None)
if args.fit:
itens = fit(itens, cfg["disponível"])
except FileNotFoundError:
print(f"erro: arquivo não encontrado: {args.caminho}", file=sys.stderr)
return 2
except (InputError, json.JSONDecodeError, ValueError) as e:
print(f"erro: {e}", file=sys.stderr)
return 2
rep = analyze(itens, cfg)
rep["ajustado_de"] = antes if args.fit else None
if args.json:
print(json.dumps(rep, indent=2))
else:
print(f"{rep['reunião']}: {rep['início']}-{rep['fim']} ({rep['duração']:g} min, margem {rep['margem']:g} min, {rep['disponível']:g} min para itens)")
if args.fit:
extra = f" mais {n_desconhecidos} sem duração (contados como 10 min cada)" if n_desconhecidos else ""
print(f"Ajustado: {antes:g} min de itens{extra} ajustados em {rep['planejado']:g} min (passos de 5 minutos, pausas mantidas).")
print(f"Planejado: {rep['planejado']:g} min\n")
for it in rep["itens"]:
mins = "?" if it["minutos"] is None else f"{it['minutos']:g}"
era = f" (era {it['original']:g})" if args.fit and it.get("original") not in (None, it["minutos"]) else ""
quem = f" ({it['responsável']})" if it["responsável"] else ""
print(f" {it['início']}-{it['fim']} {mins:>3} min{era:<10} {it['tópico']}{quem} [{it['resultado'] or '?'}]")
if rep["margem"]:
print(f" {fmt(hhmm(rep['fim']) - rep['margem'])}-{rep['fim']} {rep['margem']:>3g} min Margem / encerramento")
print()
if rep["achados"]:
print("Achados:")
for f in rep["achados"]:
print(f"- [{f['severidade']}] {f['mensagem']}")
else:
print("Achados: nenhum")
return 1 if any(f["severidade"] == "ALTO" for f in rep["achados"]) else 0
if __name__ == "__main__":
sys.exit(main())
```
Entre para ver o prompt completo
Continuar com:
Ao entrar, você concorda com nossos Termos de uso e Política de privacidade
Uso
Este prompt foi projetado para uso com productivity. Copie o conteúdo acima e cole na sua ferramenta de IA preferida.
Para melhores resultados, personalize os marcadores (indicados por colchetes ou maiúsculas) com seus requisitos específicos.
Discussão
0 comentários