feat(gestao): adicionar 9 skills /clip-* + migrar 5 para diag tools MCP
Skills clip-* nunca tinham sido committed. Adicionadas todas (9): clip, clip-agent, clip-health, clip-instructions, clip-issue, clip-org, clip-routine, clip-skill, clip-vision. Migração para mcp__paperclip__diag_* (17 substituições em 5 skills): - clip: 5 substituições (agents_by_status, false_blockers, token burn, stuck routines, company_skills_summary) - clip-agent: 2 (agent_full_context consolida 4 passos, false_blockers) - clip-health: 8 (budget_orphans, missing_permissions, missing_heartbeat, routine_triggers_broken, false_blockers, heartbeat_token_usage, prompt_too_long_errors, stuck_routines, zombie_parents) - clip-org: 1 (agent_hierarchy) - clip-routine: 1 (routine_triggers_broken) Sem substituições (CRUD-específico sem diag_* equivalente): clip-instructions, clip-issue, clip-skill — mantêm psql. Refs: Desk #2041, mcp-paperclip feature/diagnostics-db Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,340 @@
|
||||
---
|
||||
name: clip-agent
|
||||
description: Gerir agente Paperclip individual — estado, config, AGENTS.md, histórico runs, issues. Aceita nome como argumento. Usar quando "clip agent", "agente clip", "ver agente", "estado do CTO".
|
||||
context: fork
|
||||
---
|
||||
|
||||
# /clip-agent — Gerir Agente Paperclip
|
||||
|
||||
Aceita argumento: nome do agente (ex: `/clip-agent CTO`).
|
||||
|
||||
## Constantes
|
||||
|
||||
```
|
||||
BD: PGPASSWORD="paperclip" psql -h localhost -p 54329 -U paperclip -d paperclip
|
||||
COMPANY_ID: ebe10308-efd7-453f-86ab-13e6fe84004f
|
||||
AGENTS_PATH: /media/ealmeida/Dados/Hub/04-Stack/02.06-Clip/agents/
|
||||
```
|
||||
|
||||
## Procedimento
|
||||
|
||||
### Passo 1: Contexto completo do agente
|
||||
|
||||
Invocar tool MCP: `mcp__paperclip__diag_agent_full_context(agent_name="{{NOME}}")`
|
||||
|
||||
Esta tool retorna config, últimas runs, membership, permissões e tokens — cobre os Passos 1, 3, 6, 7 e 7b de uma só vez. Se multiplos resultados, mostrar lista e pedir clarificacao.
|
||||
|
||||
### Passo 2: Hierarquia
|
||||
|
||||
Quem lhe reporta:
|
||||
```sql
|
||||
SELECT name, role, status FROM agents
|
||||
WHERE reports_to = '{{AGENT_ID}}'
|
||||
AND company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
ORDER BY role, name;
|
||||
```
|
||||
|
||||
A quem reporta:
|
||||
```sql
|
||||
SELECT name, role FROM agents WHERE id = '{{REPORTS_TO_ID}}';
|
||||
```
|
||||
|
||||
### Passo 3: Ultimas 5 runs
|
||||
|
||||
```sql
|
||||
SELECT hr.status, hr.started_at, hr.finished_at, LEFT(hr.error, 80) as erro
|
||||
FROM heartbeat_runs hr
|
||||
WHERE hr.agent_id = '{{AGENT_ID}}'
|
||||
ORDER BY hr.started_at DESC LIMIT 5;
|
||||
```
|
||||
|
||||
### Passo 4: Issues atribuidas
|
||||
|
||||
```sql
|
||||
SELECT title, status, priority FROM issues
|
||||
WHERE assignee_agent_id = '{{AGENT_ID}}'
|
||||
AND status NOT IN ('done','cancelled')
|
||||
ORDER BY priority, status;
|
||||
```
|
||||
|
||||
### Passo 4b: Verificar falsos blockers (INC-07)
|
||||
|
||||
Se o agente tem issues `blocked`, invocar tool MCP: `mcp__paperclip__diag_false_blockers` e filtrar pelo agente. TODO: criar diag_* tool per-agent se uso recorrente.
|
||||
|
||||
Se `sub_activas > 0` e o agente está operacional → falso blocker. Alertar: "Issue {{ID}} marcada como blocked mas tem sub-tasks activas — deveria ser in_progress."
|
||||
|
||||
### Passo 5: AGENTS.md
|
||||
|
||||
Procurar em `AGENTS_PATH`:
|
||||
```bash
|
||||
find /media/ealmeida/Dados/Hub/04-Stack/02.06-Clip/agents/ -name "AGENTS.md" -exec grep -l "{{NOME}}" {} \;
|
||||
```
|
||||
|
||||
Se encontrado, ler e apresentar resumo (primeiras 30 linhas).
|
||||
|
||||
## Formato de output
|
||||
|
||||
```
|
||||
## Agente: {{NOME}}
|
||||
|
||||
**Role:** {{role}} | **Status:** {{status}} | **Ultimo heartbeat:** {{last_heartbeat_at}}
|
||||
**Reporta a:** {{reports_to_name}} | **Budget:** {{spent}}/{{budget}} ({{pct}}%)
|
||||
**Tokens cached:** {{tokens_M}}M | **CWD:** {{cwd}} | **Model:** {{model}}
|
||||
|
||||
### Equipa (reportam a este agente)
|
||||
| Nome | Role | Status |
|
||||
...
|
||||
|
||||
### Ultimas 5 runs
|
||||
| Status | Início | Fim | Erro |
|
||||
...
|
||||
|
||||
### Issues atribuidas
|
||||
| Titulo | Status | Prioridade |
|
||||
...
|
||||
|
||||
### Skills atribuidas
|
||||
[lista de desiredSkills ou "Sem skills (apenas built-in paperclip)"]
|
||||
|
||||
### AGENTS.md
|
||||
[resumo ou path]
|
||||
```
|
||||
|
||||
### Passo 6: Skills do agente
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
adapter_config->'paperclipSkillSync'->'desiredSkills' as desired_skills
|
||||
FROM agents
|
||||
WHERE id = '{{AGENT_ID}}';
|
||||
```
|
||||
|
||||
Se nao NULL, listar as skills. Se NULL, indicar "Sem skills atribuidas (apenas built-in paperclip)".
|
||||
|
||||
Para ver detalhes das skills disponiveis na empresa:
|
||||
```sql
|
||||
SELECT name, slug, key, source_type FROM company_skills
|
||||
WHERE company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
ORDER BY name;
|
||||
```
|
||||
|
||||
### Skills atribuídas ao agente
|
||||
|
||||
```sql
|
||||
-- Ver skills desejadas (configuradas via API)
|
||||
SELECT
|
||||
a.name as agente,
|
||||
a.adapter_config->'paperclipSkillSync'->'desiredSkills' as desired_skills
|
||||
FROM agents a
|
||||
WHERE a.id = '{{AGENT_ID}}';
|
||||
```
|
||||
|
||||
**Acções disponíveis:**
|
||||
- Ver skills da empresa: `SELECT name, slug FROM company_skills WHERE company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'`
|
||||
- Atribuir skills via API (fetch no browser): `POST /api/agents/{{AGENT_ID}}/skills/sync` com `{ "desiredSkills": ["slug1", "slug2"] }`
|
||||
|
||||
### Membership (OBRIGATÓRIO — sem isto, permissões não funcionam)
|
||||
|
||||
A função `hasPermission()` verifica **primeiro** se o agente tem membership activa em `company_memberships`. Sem membership → permissão negada mesmo com grants correctos.
|
||||
|
||||
```sql
|
||||
-- Verificar membership
|
||||
SELECT status, membership_role FROM company_memberships
|
||||
WHERE company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
AND principal_id = '{{AGENT_ID}}';
|
||||
```
|
||||
|
||||
Se **0 rows** → agente não tem membership. Criar:
|
||||
```sql
|
||||
INSERT INTO company_memberships (id, company_id, principal_type, principal_id, status, membership_role, created_at, updated_at)
|
||||
VALUES (gen_random_uuid(), 'ebe10308-efd7-453f-86ab-13e6fe84004f', 'agent', '{{AGENT_ID}}', 'active', 'member', NOW(), NOW());
|
||||
```
|
||||
|
||||
**Nota:** Agentes criados via SQL directo NÃO recebem membership automaticamente — apenas os onboarded via fluxo OpenClaw/hiring. Sempre criar membership ao adicionar agentes manualmente.
|
||||
|
||||
### Permissões do agente
|
||||
|
||||
```sql
|
||||
SELECT permission_key FROM principal_permission_grants
|
||||
WHERE company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
AND principal_id = '{{AGENT_ID}}';
|
||||
```
|
||||
|
||||
Para adicionar `tasks:assign` (necessário para delegação):
|
||||
```sql
|
||||
INSERT INTO principal_permission_grants (company_id, principal_type, principal_id, permission_key, granted_by_user_id)
|
||||
VALUES ('ebe10308-efd7-453f-86ab-13e6fe84004f', 'agent', '{{AGENT_ID}}', 'tasks:assign', 'local-board');
|
||||
```
|
||||
|
||||
**ATENÇÃO:** Este grant só funciona se o agente tiver membership activa (ver secção acima).
|
||||
|
||||
### Passo 7: Verificar adapter_config (CRITICO)
|
||||
|
||||
Agentes sem `dangerouslySkipPermissions: true` ficam bloqueados — todos os comandos bash sao rejeitados.
|
||||
|
||||
```sql
|
||||
SELECT name,
|
||||
adapter_config->>'dangerouslySkipPermissions' as skip_perms,
|
||||
adapter_config->>'cwd' as cwd,
|
||||
adapter_config->>'model' as model,
|
||||
adapter_config->>'timeoutSec' as timeout,
|
||||
adapter_config->>'maxTurnsPerRun' as max_turns
|
||||
FROM agents WHERE id = '{{AGENT_ID}}';
|
||||
```
|
||||
|
||||
**Alertar se:**
|
||||
- `skip_perms` != `true` → agente vai ficar bloqueado em todos os comandos bash
|
||||
- `cwd` = NULL → agente corre em directório temporário sem acesso ao Hub
|
||||
- `cwd` = `/media/ealmeida/Dados/Hub` → **CRITICO: CWD aponta para Hub raiz (6.4GB), Claude Code indexa tudo, causa token burn massivo** — usar `/media/ealmeida/Dados/Hub/04-Stack/02.06-Clip`
|
||||
- `model` = NULL → usa modelo default (pode não ser o desejado)
|
||||
|
||||
**Corrigir agente (CWD correcto para Clip):**
|
||||
```sql
|
||||
UPDATE agents SET adapter_config = adapter_config || '{"dangerouslySkipPermissions": true, "cwd": "/media/ealmeida/Dados/Hub/04-Stack/02.06-Clip", "model": "gemini-2.5-flash", "graceSec": 20, "timeoutSec": 900}'::jsonb
|
||||
WHERE id = '{{AGENT_ID}}';
|
||||
```
|
||||
|
||||
**Nota sobre modelos e adapters:** O adapter `claude_local` já não é usado para agentes heartbeat. Distribuição actual:
|
||||
- 1 agente (CEO) usa `gemini_local` com `gemini-2.5-pro`
|
||||
- 50 agentes usam `gemini_local` com `gemini-2.5-flash`
|
||||
- 13 agentes usam `opencode_local` com `openrouter/x-ai/grok-4.1-fast`
|
||||
|
||||
**Agentes analyst/read-only (ex: Reality Checker):** usar `adapter_type: process` com `adapter_config.model: "claude-sonnet-4-6"` e `instructionsBundleMode: "external"`. Estes agentes são invocados manualmente (heartbeat desactivado), não consomem budget em modo autónomo.
|
||||
|
||||
### Passo 7b: Sessão e tokens (INC-12)
|
||||
|
||||
`agent_task_sessions` não tem campo de tokens — o consumo está em `heartbeat_runs.usage_json`. Verificar erros "Prompt is too long" e consumo nas últimas runs.
|
||||
|
||||
```sql
|
||||
-- Erros "Prompt is too long" recentes
|
||||
SELECT hr.status, LEFT(hr.error, 80) as erro, hr.started_at::timestamp(0)
|
||||
FROM heartbeat_runs hr
|
||||
WHERE hr.agent_id = '{{AGENT_ID}}'
|
||||
AND hr.status IN ('failed','error')
|
||||
AND hr.error ILIKE '%too long%'
|
||||
AND hr.started_at > NOW() - INTERVAL '48 hours'
|
||||
ORDER BY hr.started_at DESC LIMIT 5;
|
||||
|
||||
-- Consumo token nas últimas runs bem-sucedidas
|
||||
SELECT ROUND(COALESCE((hr.usage_json->>'cache_read_input_tokens')::numeric,0)/1000,0) as cache_read_k,
|
||||
ROUND(COALESCE((hr.usage_json->>'input_tokens')::numeric,0)/1000,0) as input_k,
|
||||
ROUND(COALESCE((hr.usage_json->>'output_tokens')::numeric,0)/1000,0) as output_k,
|
||||
hr.started_at::timestamp(0)
|
||||
FROM heartbeat_runs hr
|
||||
WHERE hr.agent_id = '{{AGENT_ID}}'
|
||||
AND hr.status = 'succeeded'
|
||||
AND hr.usage_json IS NOT NULL
|
||||
ORDER BY hr.started_at DESC LIMIT 3;
|
||||
```
|
||||
|
||||
Se existirem erros "too long" → forçar rotação:
|
||||
```sql
|
||||
DELETE FROM agent_task_sessions
|
||||
WHERE agent_id = '{{AGENT_ID}}'
|
||||
AND company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f';
|
||||
```
|
||||
|
||||
### Passo 7c: Validar instructionsFilePath (INC-07)
|
||||
|
||||
O Paperclip **não usa `cwd` para resolver `instructionsFilePath`** — o path é sempre relativo ao processo do servidor, não ao CWD do agente. Deve ser **sempre absoluto**.
|
||||
|
||||
```sql
|
||||
SELECT adapter_config->>'instructionsFilePath' as instructions_path
|
||||
FROM agents WHERE id = '{{AGENT_ID}}';
|
||||
```
|
||||
|
||||
**Alertar se:**
|
||||
- `instructionsFilePath` não começa com `/` → **CRITICO: path relativo, AGENTS.md não carrega**
|
||||
- Path absoluto mas ficheiro não existe → CRITICO
|
||||
|
||||
**Corrigir path relativo:**
|
||||
```sql
|
||||
UPDATE agents
|
||||
SET adapter_config = jsonb_set(
|
||||
adapter_config,
|
||||
'{instructionsFilePath}',
|
||||
to_jsonb('/media/ealmeida/Dados/Hub/04-Stack/02.06-Clip/' || (adapter_config->>'instructionsFilePath'))
|
||||
)
|
||||
WHERE id = '{{AGENT_ID}}'
|
||||
AND adapter_config->>'instructionsFilePath' NOT LIKE '/%';
|
||||
```
|
||||
|
||||
## Wakeup manual de agente
|
||||
|
||||
Para forcar um agente a acordar imediatamente (ex: testar, desbloquear):
|
||||
|
||||
```sql
|
||||
DO $$
|
||||
DECLARE wakeup_id uuid;
|
||||
BEGIN
|
||||
INSERT INTO agent_wakeup_requests (company_id, agent_id, source, trigger_detail, reason, payload, status, requested_at, created_at, updated_at)
|
||||
VALUES ('ebe10308-efd7-453f-86ab-13e6fe84004f', '{{AGENT_ID}}', 'on_demand', 'manual', '{{RAZAO}}', '{}'::jsonb, 'queued', NOW(), NOW(), NOW())
|
||||
RETURNING id INTO wakeup_id;
|
||||
|
||||
INSERT INTO heartbeat_runs (company_id, agent_id, invocation_source, trigger_detail, status, wakeup_request_id, context_snapshot, created_at, updated_at)
|
||||
VALUES ('ebe10308-efd7-453f-86ab-13e6fe84004f', '{{AGENT_ID}}', 'on_demand', 'manual', 'queued', wakeup_id, '{"wakeReason": "manual_wakeup"}'::jsonb, NOW(), NOW());
|
||||
END $$;
|
||||
```
|
||||
|
||||
**Nota:** UPDATE directo em issues nao dispara wakeOnDemand — e preciso o par wakeup_request + heartbeat_run.
|
||||
|
||||
## Criar agente novo via SQL (checklist OBRIGATÓRIA)
|
||||
|
||||
Ao criar agente directamente na BD (fora do fluxo OpenClaw), executar TODOS os passos:
|
||||
|
||||
1. `INSERT INTO agents (...)` — dados do agente, incluindo:
|
||||
- `adapter_type: 'process'`
|
||||
- `adapter_config`: campos obrigatórios: `model`, `instructionsFilePath` (absoluto!), `instructionsRootPath`, `instructionsEntryFile: "AGENTS.md"`, `instructionsBundleMode: "external"`
|
||||
- Para agentes autónomos: adicionar `dangerouslySkipPermissions: true`, `cwd`, `timeoutSec`
|
||||
2. `INSERT INTO company_memberships (...)` — **sem isto, permissões não funcionam** (agentes criados via SQL não recebem membership automática)
|
||||
3. `INSERT INTO principal_permission_grants (...)` — se precisa de `tasks:assign` (C-Level, Directores)
|
||||
4. Criar `AGENTS.md` no path absoluto definido em `instructionsFilePath`
|
||||
5. Verificar: `instructionsFilePath` não começa com `/` → AGENTS.md não carrega (ver Passo 7c)
|
||||
|
||||
## Acções disponíveis
|
||||
|
||||
Se o utilizador pedir:
|
||||
- **Editar AGENTS.md:** Abrir ficheiro com Read/Edit
|
||||
- **Alterar config:** `UPDATE agents SET runtime_config = '...' WHERE id = '{{AGENT_ID}}';`
|
||||
- **Pausar:** `UPDATE agents SET status = 'paused', pause_reason = '...', paused_at = NOW() WHERE id = '{{AGENT_ID}}';`
|
||||
- **Despausar:** `UPDATE agents SET status = 'idle', pause_reason = NULL, paused_at = NULL WHERE id = '{{AGENT_ID}}';`
|
||||
- **Wakeup:** Usar bloco SQL acima (wakeup_request + heartbeat_run)
|
||||
- **Corrigir permissoes:** Usar UPDATE adapter_config acima
|
||||
- **Atribuir skill:** `curl -s -X POST http://localhost:3100/api/agents/{{AGENT_ID}}/skills/sync -H "Content-Type: application/json" -H "Authorization: Bearer $PAPERCLIP_API_KEY" -d '{"desiredSkills": ["key1", "key2"]}'`
|
||||
- **Ver skills empresa:** query company_skills acima
|
||||
|
||||
### Safety gate: verificacao de dependencias (OBRIGATORIO antes de DELETE/remocao)
|
||||
|
||||
Antes de apagar ou remover qualquer agente, executar SEMPRE:
|
||||
```sql
|
||||
SELECT 'budget_policies' as tabela, COUNT(*) as refs FROM budget_policies WHERE scope_type='agent' AND scope_id='{{AGENT_ID}}'
|
||||
UNION ALL
|
||||
SELECT 'budget_incidents', COUNT(*) FROM budget_incidents WHERE scope_type='agent' AND scope_id='{{AGENT_ID}}'
|
||||
UNION ALL
|
||||
SELECT 'heartbeat_runs', COUNT(*) FROM heartbeat_runs WHERE agent_id='{{AGENT_ID}}'
|
||||
UNION ALL
|
||||
SELECT 'issues', COUNT(*) FROM issues WHERE assignee_agent_id='{{AGENT_ID}}'
|
||||
UNION ALL
|
||||
SELECT 'issue_comments', COUNT(*) FROM issue_comments WHERE author_agent_id='{{AGENT_ID}}';
|
||||
```
|
||||
|
||||
- Se refs > 0 em budget_policies ou budget_incidents: apagar essas refs PRIMEIRO, senao o dashboard fica com "Agent not found"
|
||||
- Se refs > 0 em issues: reatribuir ou fechar as issues antes
|
||||
- Mostrar resultado ao utilizador e confirmar antes de prosseguir
|
||||
- NUNCA apagar agente sem verificar e limpar dependencias
|
||||
|
||||
Confirmar sempre antes de executar accoes destrutivas.
|
||||
|
||||
---
|
||||
|
||||
## Healing Log
|
||||
|
||||
Registo de erros conhecidos e como evitá-los. Lido automaticamente antes de executar.
|
||||
|
||||
```jsonl
|
||||
{"date":"2026-04-07","issue":"API skill attribution sem Authorization header — chamada rejeitada com 401","fix":"Adicionar -H 'Authorization: Bearer $PAPERCLIP_API_KEY' ao curl POST /api/agents/:id/skills/sync","source":"auto"}
|
||||
{"date":"2026-04-07","issue":"Agente criado via SQL sem membership ficou com Board access required em todos os endpoints","fix":"Sempre inserir em company_memberships após INSERT em agents. Agentes via SQL não recebem membership automática — só via fluxo OpenClaw/hiring","source":"auto"}
|
||||
{"date":"2026-04-07","issue":"instructionsBundleMode em falta na adapter_config — AGENTS.md não carregava","fix":"Incluir instructionsBundleMode: 'external' + instructionsRootPath + instructionsEntryFile: 'AGENTS.md' na adapter_config","source":"auto"}
|
||||
```
|
||||
|
||||
*Adicionar nova linha após cada erro corrigido.*
|
||||
@@ -0,0 +1,398 @@
|
||||
---
|
||||
name: clip-health
|
||||
description: Diagnóstico rápido Paperclip — serviço, BD, heartbeats falhados, budget, disco. Usar quando "clip health", "saúde clip", "diagnóstico paperclip", "clip problemas".
|
||||
context: fork
|
||||
---
|
||||
|
||||
# /clip-health — Diagnostico Paperclip
|
||||
|
||||
Verificacao rapida da saude do sistema Clip.
|
||||
|
||||
## Constantes
|
||||
|
||||
```
|
||||
BD: PGPASSWORD="paperclip" psql -h localhost -p 54329 -U paperclip -d paperclip
|
||||
PAPERCLIP_DIR: /home/ealmeida/paperclip
|
||||
INSTANCE_DIR: /home/ealmeida/.paperclip/instances/default
|
||||
```
|
||||
|
||||
## Procedimento
|
||||
|
||||
Executar todas as verificacoes em paralelo, depois apresentar relatorio.
|
||||
|
||||
### Check 1: Serviço
|
||||
|
||||
```bash
|
||||
ps aux | grep -E "paperclip.*src/index|pnpm.*paperclipai" | grep -v grep | head -5
|
||||
```
|
||||
|
||||
- Processos encontrados = OK
|
||||
- Nenhum processo = CRITICO (iniciar com: `cd /home/ealmeida/paperclip && pnpm --filter @paperclipai/server dev`)
|
||||
|
||||
Verificar também memória partilhada PostgreSQL (causa do bug POSIX shared memory):
|
||||
```bash
|
||||
ls /dev/shm/PostgreSQL.* 2>/dev/null && echo "POSIX OK" || echo "POSIX em falta — BD pode falhar ao ligar"
|
||||
```
|
||||
|
||||
- POSIX OK = OK
|
||||
- POSIX em falta + processos activos = AVISO (PostgreSQL perdeu shared memory — reiniciar Paperclip)
|
||||
- POSIX em falta + sem processos = CRITICO
|
||||
|
||||
### Check 2: Base de dados
|
||||
|
||||
Conexao:
|
||||
```sql
|
||||
SELECT 1 as connected;
|
||||
```
|
||||
|
||||
Tamanho:
|
||||
```sql
|
||||
SELECT pg_size_pretty(pg_database_size('paperclip')) as db_size;
|
||||
```
|
||||
|
||||
Contagens:
|
||||
```sql
|
||||
SELECT
|
||||
(SELECT COUNT(*) FROM agents WHERE company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f') as agentes,
|
||||
(SELECT COUNT(*) FROM issues WHERE company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f') as issues,
|
||||
(SELECT COUNT(*) FROM heartbeat_runs hr JOIN agents a ON hr.agent_id = a.id WHERE a.company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f') as heartbeats;
|
||||
```
|
||||
|
||||
- Conexao OK = OK
|
||||
- Conexao falha = CRITICO
|
||||
|
||||
### Check 3: Heartbeats falhados (24h)
|
||||
|
||||
```sql
|
||||
SELECT a.name, hr.status, LEFT(hr.error, 70) as erro, hr.started_at::timestamp(0)
|
||||
FROM heartbeat_runs hr JOIN agents a ON hr.agent_id = a.id
|
||||
WHERE a.company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
AND hr.status IN ('failed','error')
|
||||
AND hr.started_at > NOW() - INTERVAL '24 hours'
|
||||
ORDER BY hr.started_at DESC
|
||||
LIMIT 20;
|
||||
```
|
||||
|
||||
- 0 falhas = OK
|
||||
- 1-2 falhas = AVISO
|
||||
- 3+ falhas = CRITICO
|
||||
|
||||
### Check 4: Budget
|
||||
|
||||
```sql
|
||||
SELECT name, budget_monthly_cents, spent_monthly_cents,
|
||||
CASE WHEN budget_monthly_cents > 0
|
||||
THEN ROUND(spent_monthly_cents::numeric / budget_monthly_cents * 100, 1)
|
||||
ELSE 0 END as pct
|
||||
FROM agents
|
||||
WHERE company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
AND budget_monthly_cents > 0
|
||||
AND spent_monthly_cents > 0
|
||||
ORDER BY pct DESC;
|
||||
```
|
||||
|
||||
- <80% = OK
|
||||
- 80-95% = AVISO
|
||||
- >95% = CRITICO
|
||||
|
||||
### Check 5: Disco
|
||||
|
||||
```bash
|
||||
df -h /home/ealmeida/.paperclip/ | tail -1
|
||||
```
|
||||
|
||||
```bash
|
||||
du -sh /home/ealmeida/.paperclip/instances/default/db/ 2>/dev/null
|
||||
du -sh /home/ealmeida/.paperclip/instances/default/logs/ 2>/dev/null
|
||||
du -sh /home/ealmeida/.paperclip/instances/default/data/ 2>/dev/null
|
||||
```
|
||||
|
||||
- >30% livre = OK
|
||||
- 15-30% livre = AVISO
|
||||
- <15% livre = CRITICO
|
||||
|
||||
### Check 6: API Health
|
||||
|
||||
```bash
|
||||
curl -s --max-time 5 http://localhost:3100/health 2>/dev/null || echo "FALHA"
|
||||
```
|
||||
|
||||
Esperado: `{"status":"ok","version":"...","deploymentMode":"authenticated","bootstrapStatus":"ready"}`
|
||||
|
||||
- `status: ok` = OK
|
||||
- `{"error":"Board access required"}` = AVISO (API responde mas sem auth — BD operacional)
|
||||
- FALHA/timeout = CRITICO (servidor não responde)
|
||||
|
||||
### Check 7: Gateway MCPs
|
||||
|
||||
```bash
|
||||
curl -s --max-time 5 https://gateway.descomplicar.pt/health 2>/dev/null || echo "FALHA"
|
||||
```
|
||||
|
||||
- Responde = OK
|
||||
- Timeout/falha = AVISO
|
||||
|
||||
### Check 8: Referencias orfas na BD
|
||||
|
||||
Budget policies e incidents a referenciar entidades inexistentes:
|
||||
|
||||
Invocar tool MCP: `mcp__paperclip__diag_budget_orphans`
|
||||
|
||||
- 0 orfaos = OK
|
||||
- 1+ orfaos = CRITICO (causa "Agent not found" no dashboard, apagar com DELETE)
|
||||
|
||||
### Check 9: Instancias duplicadas
|
||||
|
||||
```bash
|
||||
ss -tlnp | grep -E "310[0-9]" | wc -l
|
||||
```
|
||||
|
||||
- 1 instancia = OK
|
||||
- 2+ instancias = CRITICO (processos orfaos do pnpm, matar com `kill -9` os PIDs com PPID=1)
|
||||
|
||||
Detalhe dos processos:
|
||||
```bash
|
||||
ss -tlnp | grep -E "310[0-9]"
|
||||
```
|
||||
|
||||
### Check 10: Porta vs Cloudflare Tunnel
|
||||
|
||||
```bash
|
||||
TUNNEL_PORT=$(grep -A1 "clip.descomplicar.pt" ~/.cloudflared/config.yml | grep service | grep -oP ':\K[0-9]+')
|
||||
ACTUAL_PORT=$(ss -tlnp | grep -E "310[0-9]" | head -1 | grep -oP ':310[0-9]' | tr -d ':')
|
||||
echo "Tunnel: $TUNNEL_PORT | Servidor: $ACTUAL_PORT"
|
||||
```
|
||||
|
||||
- Iguais = OK
|
||||
- Diferentes = CRITICO (tunnel a apontar para porta errada, dashboard inacessivel)
|
||||
|
||||
### Check 11: Agentes sem permissoes bash
|
||||
|
||||
Invocar tool MCP: `mcp__paperclip__diag_agents_missing_permissions`
|
||||
|
||||
- 0 = OK
|
||||
- 1+ = CRITICO (agentes vao ficar bloqueados ao executar bash — corrigir com `/clip-agent`)
|
||||
|
||||
### Check 12: Agentes sem heartbeat
|
||||
|
||||
Invocar tool MCP: `mcp__paperclip__diag_agents_missing_heartbeat`
|
||||
|
||||
- 0 = OK
|
||||
- 1+ = AVISO (agentes nao acordam — podem nao processar issues)
|
||||
|
||||
### Check 13: Routine triggers com kind errado ou next_run_at NULL
|
||||
|
||||
Invocar tool MCP: `mcp__paperclip__diag_routine_triggers_broken`
|
||||
|
||||
- 0 = OK
|
||||
- 1+ = CRITICO (routines nao vao disparar — kind deve ser 'schedule' e next_run_at populado)
|
||||
|
||||
### Check 14: Issues PUBLICAR NOTICIA sem assignee
|
||||
|
||||
```sql
|
||||
SELECT COUNT(*) FROM issues
|
||||
WHERE company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
AND title LIKE 'PUBLICAR NOTICIA%'
|
||||
AND status = 'todo'
|
||||
AND assignee_agent_id IS NULL;
|
||||
```
|
||||
|
||||
- 0 = OK
|
||||
- 1+ = AVISO (cron assign-copywriter.sh devia atribuir a cada 5 min — verificar crontab)
|
||||
|
||||
### Check 15: Qualidade artigos publicados (ultimas 24h)
|
||||
|
||||
Verificar artigos recentes no WordPress via SSH (server):
|
||||
|
||||
```bash
|
||||
cd /home/ealmeida/public_html && wp --allow-root post list --post_type=post --post_status=publish --category=noticias --date_query='{"after":"1 day ago"}' --fields=ID,post_title --format=csv 2>/dev/null
|
||||
```
|
||||
|
||||
Para CADA artigo recente, verificar:
|
||||
|
||||
**15a. Acentuacao** — procurar palavras sem acento:
|
||||
```bash
|
||||
cd /home/ealmeida/public_html && wp --allow-root post get POST_ID --field=post_content 2>/dev/null | sed 's/<[^>]*>//g' | grep -oP '\b\w+cao\b|\b\w+sao\b|\bnao\b|\b\w+vel\b' | head -20
|
||||
```
|
||||
Palavras terminadas em "cao", "sao" (sem til) ou "nao" indicam acentuacao em falta.
|
||||
|
||||
**15b. Links HTML sem aspas:**
|
||||
```bash
|
||||
cd /home/ealmeida/public_html && wp --allow-root post get POST_ID --field=post_content 2>/dev/null | grep -oP 'href=[^"'\''"][^ >]+' | head -10
|
||||
```
|
||||
Se output nao vazio = links sem aspas.
|
||||
|
||||
**15c. Titulo com maiusculas indevidas:**
|
||||
```bash
|
||||
cd /home/ealmeida/public_html && wp --allow-root post get POST_ID --field=post_title 2>/dev/null
|
||||
```
|
||||
Verificar: so primeira palavra e nomes proprios devem ter maiuscula.
|
||||
|
||||
- 0 problemas = OK
|
||||
- 1-3 = AVISO (artigos com defeitos cosmeticos)
|
||||
- 4+ = CRITICO (Copywriter nao esta a cumprir quality gates — actualizar AGENTS.md)
|
||||
|
||||
### Check 16: Cron assign-copywriter activo
|
||||
|
||||
```bash
|
||||
crontab -l | grep assign-copywriter
|
||||
```
|
||||
|
||||
- Presente = OK
|
||||
- Ausente = CRITICO (issues PUBLICAR NOTICIA nunca serao atribuidas ao Copywriter)
|
||||
|
||||
### Check 17: Pipeline noticias end-to-end (ultimas 24h)
|
||||
|
||||
```sql
|
||||
-- Routines disparadas
|
||||
SELECT COUNT(*) as routines_fired FROM routine_triggers rt
|
||||
JOIN routines r ON rt.routine_id = r.id
|
||||
WHERE r.title LIKE 'Pesquisa diaria%noticias%'
|
||||
AND rt.last_fired_at > NOW() - INTERVAL '24 hours';
|
||||
|
||||
-- Issues de pesquisa concluidas
|
||||
SELECT COUNT(*) as pesquisas_done FROM issues
|
||||
WHERE company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
AND title LIKE 'Pesquisa diaria%'
|
||||
AND status = 'done'
|
||||
AND created_at > NOW() - INTERVAL '24 hours';
|
||||
|
||||
-- Issues PUBLICAR NOTICIA criadas e concluidas
|
||||
SELECT
|
||||
COUNT(*) as total,
|
||||
COUNT(*) FILTER (WHERE status = 'done') as done,
|
||||
COUNT(*) FILTER (WHERE status IN ('todo','in_progress')) as pendentes
|
||||
FROM issues
|
||||
WHERE company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
AND title LIKE 'PUBLICAR NOTICIA%'
|
||||
AND created_at > NOW() - INTERVAL '24 hours';
|
||||
```
|
||||
|
||||
- routines_fired >= 3 E pesquisas_done >= 1 E done >= 5 = OK
|
||||
- Qualquer zero = AVISO (pipeline com falhas)
|
||||
- routines_fired = 0 = CRITICO (routines nao disparam)
|
||||
|
||||
### Check 18: Issues blocked sem impedimento real (INC-07)
|
||||
|
||||
Invocar tool MCP: `mcp__paperclip__diag_false_blockers`
|
||||
|
||||
Para cada issue blocked, verificar se o assignee está em erro:
|
||||
```sql
|
||||
SELECT a.name, a.status FROM agents a
|
||||
WHERE a.id = (SELECT assignee_agent_id FROM issues WHERE identifier = '{{ID}}');
|
||||
```
|
||||
|
||||
- Issue `blocked` + assignee `active/idle/running` + sub-tasks activas > 0 = **FALSO BLOCKER** (deveria ser `in_progress`)
|
||||
- Issue `blocked` + assignee `error/paused` = blocker legítimo
|
||||
- Issue `blocked` + sem sub-tasks + sem comentário de impedimento = suspeito, alertar
|
||||
|
||||
Resultado:
|
||||
- 0 falsos blockers = OK
|
||||
- 1+ falsos blockers = AVISO (listar e recomendar correcção para `in_progress`)
|
||||
|
||||
---
|
||||
|
||||
### Check 19: Sessões com tokens excessivos (INC-12)
|
||||
|
||||
Previne "Prompt is too long" e token burn massivo. Monitoriza via usage_json dos heartbeats recentes.
|
||||
|
||||
Top agentes com maior consumo de tokens nas últimas 24h:
|
||||
|
||||
Invocar tool MCP: `mcp__paperclip__diag_heartbeat_token_usage(hours=24)`
|
||||
|
||||
Contagem de erros "Prompt is too long" activos (sinal imediato):
|
||||
|
||||
Invocar tool MCP: `mcp__paperclip__diag_prompt_too_long_errors(hours=24)`
|
||||
|
||||
- 0 erros = OK
|
||||
- 1+ erros = CRITICO (forçar rotação de sessão)
|
||||
|
||||
**Forçar rotação de sessão (apaga histórico, fresh start):**
|
||||
```sql
|
||||
DELETE FROM agent_task_sessions
|
||||
WHERE agent_id = '{{AGENT_ID}}'
|
||||
AND company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Check 20: Routines presas in_progress >4h (INC-08)
|
||||
|
||||
Issues de routine que ficam `in_progress` sem actividade bloqueiam todos os futuros disparos da mesma routine (constraint `issues_open_routine_execution_uq`). A ligação issue→routine está em `routine_runs.linked_issue_id` (não existe `issues.routine_id`).
|
||||
|
||||
Invocar tool MCP: `mcp__paperclip__diag_stuck_routines(hours=4)`
|
||||
|
||||
- 0 = OK
|
||||
- 1+ = CRITICO (routine bloqueada — cancelar a issue presa para desbloquear futuros disparos)
|
||||
|
||||
**Desbloquear routine (cancelar issue presa):**
|
||||
```sql
|
||||
UPDATE issues SET status = 'cancelled', updated_at = NOW()
|
||||
WHERE identifier = '{{IDENTIFIER}}'
|
||||
AND company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Check 21: Zombie parents — issues pai com sub-tasks todas concluídas (AP-09)
|
||||
|
||||
Issues pai que ficam abertas indefinidamente quando todas as sub-tasks estão `done` ou `cancelled`. Poluem o dashboard e impedem distinguir trabalho parado de trabalho já feito.
|
||||
|
||||
Invocar tool MCP: `mcp__paperclip__diag_zombie_parents`
|
||||
|
||||
- 0 = OK
|
||||
- 1+ = AVISO (fechar manualmente ou alertar CEO para verificar e fechar)
|
||||
|
||||
---
|
||||
|
||||
## Formato de output
|
||||
|
||||
```
|
||||
## Clip Health — [data/hora]
|
||||
|
||||
| Check | Estado | Detalhe |
|
||||
|-------|--------|---------|
|
||||
| Servico | OK/CRITICO | N processos activos / stopped |
|
||||
| POSIX shared memory | OK/AVISO/CRITICO | /dev/shm/PostgreSQL.* presente / em falta |
|
||||
| Base de dados | OK/CRITICO | Xmb, N agentes, N issues |
|
||||
| Heartbeats 24h | OK/AVISO/CRITICO | N falhas |
|
||||
| Budget | OK/AVISO/CRITICO | [agente] a X% |
|
||||
| Disco | OK/AVISO/CRITICO | X% livre (Xgb) |
|
||||
| API Health | OK/AVISO/CRITICO | status:ok / board access / timeout |
|
||||
| Gateway | OK/AVISO | responde / timeout |
|
||||
| Refs orfas | OK/CRITICO | N budget_policies orfas |
|
||||
| Instancias | OK/CRITICO | N processos na porta 310x |
|
||||
| Porta/Tunnel | OK/CRITICO | tunnel:X servidor:Y |
|
||||
| Permissoes bash | OK/CRITICO | N agentes sem dangerouslySkipPermissions |
|
||||
| Heartbeats config | OK/AVISO | N agentes sem heartbeat enabled |
|
||||
| Routine triggers | OK/CRITICO | N triggers com kind errado ou next_run_at NULL |
|
||||
| Auto-assign noticias | OK/AVISO | N issues PUBLICAR NOTICIA sem assignee |
|
||||
| Qualidade artigos | OK/AVISO/CRITICO | N artigos com acentos/links/titulos errados |
|
||||
| Cron assign-copywriter | OK/CRITICO | activo / ausente |
|
||||
| Pipeline noticias 24h | OK/AVISO/CRITICO | N routines, N pesquisas, N publicadas |
|
||||
| Falsos blockers | OK/AVISO | N issues blocked sem impedimento real |
|
||||
| Tokens excessivos | OK/AVISO/CRITICO | N agentes >500K tokens cached |
|
||||
| Routines presas | OK/CRITICO | N issues rotina paradas >4h |
|
||||
| Zombie parents | OK/AVISO | N issues pai com todas as subs concluídas |
|
||||
|
||||
**Score:** N/22 OK
|
||||
|
||||
### Detalhes (se existirem alertas)
|
||||
[listar heartbeats falhados, budget alto, artigos com defeitos, pipeline parado]
|
||||
|
||||
### Accoes recomendadas
|
||||
[listar accoes concretas para resolver alertas]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Healing Log
|
||||
|
||||
Registo de erros conhecidos e como evitá-los. Lido automaticamente antes de executar.
|
||||
|
||||
```jsonl
|
||||
{"date":"2026-04-07","issue":"Check 1 usava systemctl que nunca existe (Paperclip corre via pnpm dev)","fix":"Substituir por ps aux | grep paperclip + check POSIX shared memory /dev/shm/PostgreSQL.*","source":"auto"}
|
||||
{"date":"2026-04-07","issue":"Check 6 usava npx paperclipai doctor que não existe no projecto local","fix":"Substituir por curl localhost:3100/health — distingue: ok / board access (BD operacional) / timeout (servidor morto)","source":"auto"}
|
||||
```
|
||||
|
||||
*Adicionar nova linha após cada erro corrigido.*
|
||||
@@ -0,0 +1,184 @@
|
||||
---
|
||||
name: clip-instructions
|
||||
description: Editar e gerir AGENTS.md de agentes Paperclip — ver, editar, rever histórico de versões. O AGENTS.md é o "cérebro" do agente. Usar quando "clip instructions", "editar agente", "atualizar AGENTS.md", "mudar comportamento agente", "instruções agente".
|
||||
context: fork
|
||||
version: "1.0.0"
|
||||
created: 2026-04-07
|
||||
---
|
||||
|
||||
# /clip-instructions — Gerir AGENTS.md dos Agentes
|
||||
|
||||
O `AGENTS.md` é o ficheiro de instruções que define identidade, missão, comportamento e regras de cada agente. É injectado a cada heartbeat — editar o ficheiro tem efeito imediato no próximo run.
|
||||
|
||||
Aceita argumento: nome do agente (ex: `/clip-instructions CTO`).
|
||||
|
||||
## Constantes
|
||||
|
||||
```
|
||||
BD: PGPASSWORD="paperclip" psql -h localhost -p 54329 -U paperclip -d paperclip
|
||||
COMPANY_ID: ebe10308-efd7-453f-86ab-13e6fe84004f
|
||||
```
|
||||
|
||||
## Passo 1: Encontrar agente e localizar AGENTS.md
|
||||
|
||||
```sql
|
||||
SELECT id, name, role, title,
|
||||
adapter_config->>'instructionsFilePath' as instructions_path,
|
||||
adapter_config->>'instructionsRootPath' as instructions_root
|
||||
FROM agents
|
||||
WHERE company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
AND LOWER(name) LIKE LOWER('%{{NOME}}%');
|
||||
```
|
||||
|
||||
Se `instructions_path` é NULL ou não começa com `/` → CRITICO (AGENTS.md não está a ser carregado).
|
||||
|
||||
## Passo 2: Ler ficheiro actual
|
||||
|
||||
```bash
|
||||
cat "{{instructions_path}}"
|
||||
```
|
||||
|
||||
Apresentar conteúdo completo. Identificar secções:
|
||||
- `## Identidade` — nome, papel, tipo, modelo, budget
|
||||
- `## Missão` — objectivo principal
|
||||
- `## Comportamento` — regras de actuação
|
||||
- `## Skills` / `## MCPs` — ferramentas
|
||||
- `## Heartbeat` — intervalo, checklist
|
||||
- `## Equipa` — quem reporta a quem
|
||||
|
||||
## Passo 3: Modo de actuação
|
||||
|
||||
### Ver (sem edições pedidas)
|
||||
Apresentar resumo estruturado das secções principais.
|
||||
|
||||
### Editar (utilizador pede alteração específica)
|
||||
|
||||
1. Ler ficheiro completo com Read
|
||||
2. Identificar a secção a alterar
|
||||
3. Propor a alteração ao utilizador ("Vou mudar X para Y — confirmas?")
|
||||
4. Executar com Edit após confirmação
|
||||
5. Verificar que o ficheiro ficou correcto
|
||||
|
||||
**Regras de edição segura:**
|
||||
- Nunca reescrever o ficheiro completo — usar Edit para alterações cirúrgicas
|
||||
- Preservar frontmatter YAML se existir
|
||||
- Manter estrutura de secções existente
|
||||
- Após editar, mostrar diff resumido das alterações
|
||||
|
||||
### Criar novo AGENTS.md (agente sem instruções)
|
||||
|
||||
Se `instructions_path` está definido mas o ficheiro não existe:
|
||||
|
||||
```bash
|
||||
ls "{{instructions_path}}" 2>/dev/null || echo "NAO_EXISTE"
|
||||
```
|
||||
|
||||
Criar directório se necessário:
|
||||
```bash
|
||||
mkdir -p "{{instructions_root}}"
|
||||
```
|
||||
|
||||
Template mínimo para novo AGENTS.md:
|
||||
```markdown
|
||||
# {{NOME}}
|
||||
|
||||
## Identidade
|
||||
|
||||
- **Nome:** {{NOME}}
|
||||
- **Papel:** {{ROLE}} — reporta ao {{SUPERVISOR}}
|
||||
- **Tipo:** {{TIPO}} (executor/analyst/manager)
|
||||
- **Modelo:** {{MODELO}}
|
||||
- **Budget:** {{BUDGET}} cents/mês
|
||||
|
||||
## Missão
|
||||
|
||||
{{DESCRICAO_MISSAO}}
|
||||
|
||||
## Comportamento
|
||||
|
||||
### Regras
|
||||
|
||||
- **Foco** — executar apenas tarefas dentro do scope definido
|
||||
- **Escalação** — problemas fora de scope → reportar ao supervisor
|
||||
- **PT-PT** — sempre com acentuação correcta
|
||||
|
||||
## Heartbeat
|
||||
|
||||
- **Intervalo:** {{INTERVALO}}s
|
||||
- **Checklist:** ver issues atribuídas, executar, reportar
|
||||
|
||||
## Equipa
|
||||
|
||||
- Reporta ao: {{SUPERVISOR}}
|
||||
```
|
||||
|
||||
## Passo 4: Verificar após edição
|
||||
|
||||
Confirmar que o Paperclip reconhece o ficheiro actualizado:
|
||||
```bash
|
||||
curl -s "http://localhost:3100/api/agents/{{AGENT_ID}}/instructions-bundle" \
|
||||
-H "Authorization: Bearer $PAPERCLIP_API_KEY" | python3 -c "import sys,json; d=json.load(sys.stdin); print('OK' if d.get('content') else 'VAZIO')"
|
||||
```
|
||||
|
||||
- OK = AGENTS.md carregado pelo servidor
|
||||
- VAZIO / erro = path errado ou ficheiro não encontrado
|
||||
|
||||
## Casos especiais
|
||||
|
||||
### Actualizar model no AGENTS.md
|
||||
|
||||
Se o agente mudou de modelo (ex: gemini → claude), actualizar tanto o AGENTS.md como o `adapter_config`:
|
||||
```sql
|
||||
UPDATE agents
|
||||
SET adapter_config = jsonb_set(adapter_config, '{model}', '"{{NOVO_MODELO}}"'::jsonb)
|
||||
WHERE id = '{{AGENT_ID}}'
|
||||
AND company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f';
|
||||
```
|
||||
|
||||
### Rever historial de versões (config_revisions)
|
||||
|
||||
```sql
|
||||
SELECT cr.id, cr.created_at::timestamp(0), a.name as criado_por
|
||||
FROM agent_config_revisions cr
|
||||
LEFT JOIN agents a ON cr.created_by_agent_id = a.id
|
||||
WHERE cr.agent_id = '{{AGENT_ID}}'
|
||||
ORDER BY cr.created_at DESC
|
||||
LIMIT 10;
|
||||
```
|
||||
|
||||
### Rollback via API
|
||||
|
||||
```bash
|
||||
curl -s -X POST "http://localhost:3100/api/agents/{{AGENT_ID}}/config-revisions/{{REVISION_ID}}/rollback" \
|
||||
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Formato de output
|
||||
|
||||
```
|
||||
## Instruções — {{NOME}} ({{role}})
|
||||
|
||||
**Ficheiro:** {{instructions_path}}
|
||||
**Estado:** carregado / não encontrado / path inválido
|
||||
|
||||
### Resumo actual
|
||||
**Missão:** [1 linha]
|
||||
**Modelo:** {{model}} | **Budget:** {{budget}} cents | **Heartbeat:** {{intervalo}}s
|
||||
**Regras principais:** [lista]
|
||||
**Skills:** [lista ou "nenhuma"]
|
||||
|
||||
### Alterações efectuadas (se editou)
|
||||
[diff resumido]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Healing Log
|
||||
|
||||
```jsonl
|
||||
{"date":"2026-04-07","issue":"instructionsFilePath relativo — AGENTS.md não carregava após criação via SQL","fix":"Path deve ser sempre absoluto. Verificar com query adapter_config->>'instructionsFilePath' NOT LIKE '/%'","source":"auto"}
|
||||
```
|
||||
@@ -0,0 +1,200 @@
|
||||
---
|
||||
name: clip-issue
|
||||
description: Criar e gerir issues Paperclip — lançar objectivos ao CEO, ver progresso, comentar. Usar quando "clip issue", "criar issue", "lançar objectivo", "ver issues clip". Issues seguem cadeia de delegação hierárquica.
|
||||
context: fork
|
||||
---
|
||||
|
||||
# /clip-issue — Gerir Issues Paperclip
|
||||
|
||||
Modos: lista (sem args), criar (com titulo), ver (com ID).
|
||||
|
||||
## Constantes
|
||||
|
||||
```
|
||||
BD: PGPASSWORD="paperclip" psql -h localhost -p 54329 -U paperclip -d paperclip
|
||||
COMPANY_ID: ebe10308-efd7-453f-86ab-13e6fe84004f
|
||||
API: http://localhost:3100/api
|
||||
```
|
||||
|
||||
## Modo lista (sem argumentos)
|
||||
|
||||
```sql
|
||||
SELECT i.id, i.title, i.status, i.priority, a.name as assignee, i.created_at
|
||||
FROM issues i LEFT JOIN agents a ON i.assignee_agent_id = a.id
|
||||
WHERE i.company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
AND i.status NOT IN ('done','cancelled')
|
||||
ORDER BY
|
||||
CASE i.priority WHEN 'critical' THEN 1 WHEN 'high' THEN 2 WHEN 'medium' THEN 3 ELSE 4 END,
|
||||
i.status, i.created_at DESC;
|
||||
```
|
||||
|
||||
Para ver concluidas tambem:
|
||||
```sql
|
||||
-- Adicionar: AND i.status IN ('done') AND i.updated_at > NOW() - INTERVAL '7 days'
|
||||
```
|
||||
|
||||
## Modo criar (com titulo)
|
||||
|
||||
### Passo 1: Obter CEO ID
|
||||
|
||||
```sql
|
||||
SELECT id FROM agents
|
||||
WHERE company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
AND name = 'CEO';
|
||||
```
|
||||
|
||||
### Passo 2: Criar issue
|
||||
|
||||
Preferir API (quando JWT funciona):
|
||||
```bash
|
||||
curl -s -X POST "http://localhost:3100/api/companies/ebe10308-efd7-453f-86ab-13e6fe84004f/issues" \
|
||||
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"title": "{{TITULO}}",
|
||||
"description": "{{DESCRICAO}}",
|
||||
"priority": "{{PRIORIDADE}}",
|
||||
"assigneeAgentId": "{{CEO_ID}}"
|
||||
}'
|
||||
```
|
||||
|
||||
Fallback via BD (OBRIGATORIO incluir identifier e issue_number):
|
||||
```sql
|
||||
-- Passo 2a: Obter proximo numero
|
||||
SELECT issue_counter FROM companies WHERE id = 'ebe10308-efd7-453f-86ab-13e6fe84004f';
|
||||
-- Guardar o valor como NEXT_NUM
|
||||
|
||||
-- Passo 2b: Criar issue COM identifier
|
||||
INSERT INTO issues (id, company_id, title, description, priority, assignee_agent_id, status, identifier, issue_number, created_at, updated_at)
|
||||
VALUES (
|
||||
gen_random_uuid(),
|
||||
'ebe10308-efd7-453f-86ab-13e6fe84004f',
|
||||
'{{TITULO}}',
|
||||
'{{DESCRICAO}}',
|
||||
'{{PRIORIDADE}}',
|
||||
'{{CEO_ID}}',
|
||||
'todo',
|
||||
'DES-{{NEXT_NUM}}',
|
||||
{{NEXT_NUM}},
|
||||
NOW(), NOW()
|
||||
)
|
||||
RETURNING id, identifier, title, status;
|
||||
|
||||
-- Passo 2c: Incrementar counter (CRITICO — nunca esquecer)
|
||||
UPDATE companies SET issue_counter = {{NEXT_NUM}} + 1 WHERE id = 'ebe10308-efd7-453f-86ab-13e6fe84004f';
|
||||
```
|
||||
|
||||
**NUNCA criar issues via SQL sem identifier e issue_number.** Causa bug de duplicate key que bloqueia toda a criacao de issues no Paperclip.
|
||||
|
||||
Confirmar titulo e prioridade com o utilizador antes de criar. Prioridades: critical, high, medium, low.
|
||||
|
||||
### Nota sobre delegação hierárquica
|
||||
|
||||
Issues criadas pelo Board (Emanuel) são sempre atribuídas ao CEO. O CEO delega pela cadeia:
|
||||
- CEO cria sub-issue ao C-Level adequado
|
||||
- C-Level cria sub-issue ao Director
|
||||
- Director atribui ao especialista
|
||||
|
||||
Quando routines disparam, geram issues ao CEO que segue o mesmo fluxo. A cadeia está na descrição da routine (campo `description` começa com `CADEIA: CEO → ...`).
|
||||
|
||||
## Semântica de estados (referência rápida)
|
||||
|
||||
Ao criar, alterar ou interpretar estados de issues:
|
||||
|
||||
- **`todo`** — não iniciada, aguarda pickup
|
||||
- **`in_progress`** — trabalho em curso, **incluindo aguardar sub-tasks delegadas**
|
||||
- **`blocked`** — APENAS impedimento real (agente em erro, falta de permissão, dependência externa, aguarda decisão humana)
|
||||
- **`done`** — concluída com resultado verificado
|
||||
- **`cancelled`** — abandonada por decisão superior
|
||||
|
||||
**Regra INC-07:** `blocked` ≠ "delegué e estou à espera". Aguardar sub-task activa = `in_progress`. Se ao listar issues vires `blocked` sem impedimento real, alertar o utilizador.
|
||||
|
||||
## Modo ver (com ID ou titulo parcial)
|
||||
|
||||
```sql
|
||||
SELECT i.*, a.name as assignee
|
||||
FROM issues i LEFT JOIN agents a ON i.assignee_agent_id = a.id
|
||||
WHERE i.company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
AND (i.id::text LIKE '%{{ARG}}%' OR LOWER(i.title) LIKE LOWER('%{{ARG}}%'));
|
||||
```
|
||||
|
||||
Comentarios:
|
||||
```sql
|
||||
SELECT ic.body, ic.created_at, a.name as author
|
||||
FROM issue_comments ic
|
||||
LEFT JOIN agents a ON ic.author_agent_id = a.id
|
||||
WHERE ic.issue_id = '{{ISSUE_ID}}'
|
||||
ORDER BY ic.created_at ASC;
|
||||
```
|
||||
|
||||
## Modo comentar
|
||||
|
||||
```sql
|
||||
INSERT INTO issue_comments (id, company_id, issue_id, author_user_id, body, created_at, updated_at)
|
||||
VALUES (gen_random_uuid(), 'ebe10308-efd7-453f-86ab-13e6fe84004f', '{{ISSUE_ID}}', 'v1N5OccPn9DGq6iog7qW9nEvnXYFT3iO', '{{COMENTARIO}}', NOW(), NOW())
|
||||
RETURNING id;
|
||||
```
|
||||
|
||||
Nota: `author_user_id = 'v1N5OccPn9DGq6iog7qW9nEvnXYFT3iO'` (Emanuel) → comentário aparece como Board/humano no dashboard. Nunca usar `'board'` — não é um user_id válido.
|
||||
|
||||
## Modo checkout / release
|
||||
|
||||
Checkout reserva a issue para trabalho activo (sinaliza ao Paperclip que está em curso).
|
||||
Release liberta a issue de volta a `todo`.
|
||||
|
||||
**Checkout via API:**
|
||||
```bash
|
||||
curl -s -X POST "http://localhost:3100/api/issues/{{ISSUE_ID}}/checkout" \
|
||||
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"agentId": "{{AGENT_ID}}"}'
|
||||
```
|
||||
|
||||
**Release via API:**
|
||||
```bash
|
||||
curl -s -X POST "http://localhost:3100/api/issues/{{ISSUE_ID}}/release" \
|
||||
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{}'
|
||||
```
|
||||
|
||||
**Fallback via BD (se API falhar):**
|
||||
```sql
|
||||
-- Checkout manual
|
||||
UPDATE issues SET status = 'in_progress', updated_at = NOW()
|
||||
WHERE id = '{{ISSUE_ID}}'
|
||||
AND company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
RETURNING identifier, title, status;
|
||||
|
||||
-- Release manual
|
||||
UPDATE issues SET status = 'todo', updated_at = NOW()
|
||||
WHERE id = '{{ISSUE_ID}}'
|
||||
AND company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
RETURNING identifier, title, status;
|
||||
```
|
||||
|
||||
**Nota:** O par checkout/release é importante para o pipeline do Paperclip — evita que dois agentes peguem na mesma issue em simultâneo.
|
||||
|
||||
## Formato de output
|
||||
|
||||
Adaptar ao modo. Para lista:
|
||||
```
|
||||
## Issues Clip — [data]
|
||||
|
||||
| # | Titulo | Status | Prioridade | Assignee |
|
||||
...
|
||||
|
||||
Total: N abertas (N critical, N high, N medium, N low)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Healing Log
|
||||
|
||||
Registo de erros conhecidos e como evitá-los. Lido automaticamente antes de executar.
|
||||
|
||||
```jsonl
|
||||
{"date":"2026-04-07","issue":"author_user_id = 'board' em comentários — não é user_id válido, comentário não aparecia no dashboard","fix":"Usar 'v1N5OccPn9DGq6iog7qW9nEvnXYFT3iO' (ID real de Emanuel no Paperclip)","source":"auto"}
|
||||
```
|
||||
|
||||
*Adicionar nova linha após cada erro corrigido.*
|
||||
@@ -0,0 +1,148 @@
|
||||
---
|
||||
name: clip-org
|
||||
description: Org chart Paperclip — hierarquia completa, reports, gaps por preencher. Usar quando "clip org", "organigrama", "hierarquia clip", "quem reporta a quem". Inclui modelo de governance e cadeias de delegação.
|
||||
context: fork
|
||||
---
|
||||
|
||||
# /clip-org — Org Chart Paperclip
|
||||
|
||||
Hierarquia completa da empresa Descomplicar no Paperclip.
|
||||
|
||||
## Constantes
|
||||
|
||||
```
|
||||
BD: PGPASSWORD="paperclip" psql -h localhost -p 54329 -U paperclip -d paperclip
|
||||
COMPANY_ID: ebe10308-efd7-453f-86ab-13e6fe84004f
|
||||
```
|
||||
|
||||
## Procedimento
|
||||
|
||||
### Passo 1: Obter hierarquia completa
|
||||
|
||||
Invocar tool MCP: `mcp__paperclip__diag_agent_hierarchy`
|
||||
|
||||
### Passo 2: Construir arvore visual
|
||||
|
||||
Apresentar como arvore identada:
|
||||
|
||||
```
|
||||
Emanuel (Board)
|
||||
└── CEO (running)
|
||||
├── COO (idle)
|
||||
│ ├── [Dir. Suporte] — nao existe
|
||||
│ └── Ticket Triage (idle)
|
||||
├── CFO (idle)
|
||||
│ ├── [Dir. Financeiro] — nao existe
|
||||
│ ├── Finance Manager (idle)
|
||||
│ └── Compliance Auditor (idle)
|
||||
├── CTO (idle)
|
||||
│ ├── [Dir. Infraestrutura] — nao existe
|
||||
│ │ ├── CWP Server Manager (idle)
|
||||
│ │ ├── EasyPanel Specialist (idle)
|
||||
│ │ ├── Backup Specialist (idle)
|
||||
│ │ └── Security Specialist (idle)
|
||||
│ ├── [Dir. Desenvolvimento] — nao existe
|
||||
│ │ └── ...
|
||||
│ └── ...
|
||||
└── ...
|
||||
```
|
||||
|
||||
Nota: Directores de seccao (~16) podem ainda nao existir. Mostrar como `[Nome] — nao existe` para evidenciar gaps.
|
||||
|
||||
### Passo 3: Identificar gaps
|
||||
|
||||
```sql
|
||||
-- Agentes orfaos (sem reports_to, excepto CEO)
|
||||
SELECT name, role, status FROM agents
|
||||
WHERE company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
AND reports_to IS NULL
|
||||
AND role != 'ceo';
|
||||
```
|
||||
|
||||
```sql
|
||||
-- C-Level sem subordinados directos
|
||||
SELECT c.name, c.role,
|
||||
(SELECT COUNT(*) FROM agents sub WHERE sub.reports_to = c.id) as subordinados
|
||||
FROM agents c
|
||||
WHERE c.company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
AND c.role IN ('coo','cfo','cto','cmo','cro','cgo','cdo')
|
||||
ORDER BY subordinados ASC;
|
||||
```
|
||||
|
||||
### Passo 4: Estatisticas
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
role,
|
||||
COUNT(*) as total,
|
||||
COUNT(CASE WHEN status = 'running' THEN 1 END) as running,
|
||||
COUNT(CASE WHEN status = 'idle' THEN 1 END) as idle,
|
||||
COUNT(CASE WHEN status = 'paused' THEN 1 END) as paused
|
||||
FROM agents
|
||||
WHERE company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
GROUP BY role
|
||||
ORDER BY CASE role
|
||||
WHEN 'ceo' THEN 1 WHEN 'coo' THEN 2 WHEN 'cfo' THEN 3
|
||||
WHEN 'manager' THEN 4 WHEN 'engineer' THEN 5 ELSE 6 END;
|
||||
```
|
||||
|
||||
## Formato de output
|
||||
|
||||
```
|
||||
## Org Chart Clip — [data]
|
||||
|
||||
[arvore visual]
|
||||
|
||||
### Estatisticas
|
||||
| Camada | Total | Running | Idle | Paused |
|
||||
...
|
||||
|
||||
### Gaps
|
||||
- Directores em falta: [lista das 16 TFs sem Director]
|
||||
- Agentes orfaos: [lista]
|
||||
- C-Level sem subordinados: [lista]
|
||||
|
||||
### Cobertura
|
||||
Directores: N/16 (N%)
|
||||
TaskForces cobertas: [lista]
|
||||
```
|
||||
|
||||
## Referência de TaskForces esperadas
|
||||
|
||||
| TF | Director esperado | Reporta a |
|
||||
|----|-------------------|-----------|
|
||||
| TF-01 Estratégia | Dir. Estratégia | CGO |
|
||||
| TF-02 Operações | Dir. Operações | COO |
|
||||
| TF-03 Financeiro | Dir. Financeiro | CFO |
|
||||
| TF-04 Infraestrutura | Dir. Infraestrutura | CTO |
|
||||
| TF-05 Desenvolvimento | Dir. Desenvolvimento | CTO |
|
||||
| TF-06 Automação | Dir. Automação | CTO |
|
||||
| TF-07 IA | Dir. IA | CGO |
|
||||
| TF-08 Design | Dir. Design | CMO |
|
||||
| TF-09 Web | Dir. Web | CMO |
|
||||
| TF-10 Vídeo | Dir. Vídeo | CMO |
|
||||
| TF-11 SEO | Dir. SEO | CMO |
|
||||
| TF-12 Conteúdo | Dir. Conteúdo | CMO |
|
||||
| TF-13 Social | Dir. Social | CMO |
|
||||
| TF-14 Publicidade | Dir. Publicidade | CMO |
|
||||
| TF-15 Comercial | Dir. Comercial | CRO |
|
||||
| TF-16 Suporte | Dir. Suporte | COO |
|
||||
|
||||
## Modelo de governance
|
||||
|
||||
Todas as routines são atribuídas ao CEO que delega pela cadeia hierárquica:
|
||||
`Routine → CEO → C-Level → Director → Especialista`
|
||||
|
||||
Cada nível adiciona contexto antes de delegar e sintetiza resultados antes de reportar acima. Ver `/clip-routine` para detalhes.
|
||||
|
||||
---
|
||||
|
||||
## Healing Log
|
||||
|
||||
Registo de erros conhecidos e como evitá-los. Lido automaticamente antes de executar.
|
||||
|
||||
```jsonl
|
||||
{"date":"","issue":"","fix":"","source":"user|auto"}
|
||||
```
|
||||
|
||||
*Adicionar nova linha após cada erro corrigido.*
|
||||
@@ -0,0 +1,349 @@
|
||||
---
|
||||
name: clip-routine
|
||||
description: Gerir routines Paperclip — listar crons activos, ver execuções, criar/editar routines. Usar quando "clip routine", "routines clip", "crons paperclip", "automações clip".
|
||||
context: fork
|
||||
---
|
||||
|
||||
# /clip-routine — Gerir Routines Paperclip
|
||||
|
||||
## Modelo de governance (desde 29-03-2026)
|
||||
|
||||
**Todas as routines são atribuídas ao CEO.** O CEO delega pela cadeia hierárquica:
|
||||
|
||||
```
|
||||
Routine (cron trigger) → CEO avalia e delega
|
||||
→ C-Level adiciona contexto departamental
|
||||
→ Director coordena e atribui
|
||||
→ Especialista executa
|
||||
→ Resultado sobe a cadeia com síntese progressiva
|
||||
```
|
||||
|
||||
Cada routine tem no campo `description` a cadeia de delegação (ex: `CADEIA: CEO → CTO → Dir. Infraestrutura → Backup Specialist`).
|
||||
|
||||
**Regras:**
|
||||
- Novas routines devem ser SEMPRE atribuídas ao CEO
|
||||
- A cadeia de delegação deve estar explícita na descrição
|
||||
- Nunca atribuir routines directamente a especialistas — quebra a visibilidade hierárquica
|
||||
|
||||
## Dois tipos de periodicidade
|
||||
|
||||
1. **Heartbeats** — intervalos configurados via `runtime_config` dos agentes (quando acordam)
|
||||
2. **Routines** — tarefas periódicas via tabela `routines` + `routine_triggers` com cron (o que fazem ao acordar)
|
||||
|
||||
## Constantes
|
||||
|
||||
```
|
||||
BD: PGPASSWORD="paperclip" psql -h localhost -p 54329 -U paperclip -d paperclip
|
||||
COMPANY_ID: ebe10308-efd7-453f-86ab-13e6fe84004f
|
||||
```
|
||||
|
||||
## Tiers de heartbeat
|
||||
|
||||
| Tier | Intervalo | Uso |
|
||||
|------|-----------|-----|
|
||||
| 1 | 1h (3600s) | CEO, agentes criticos |
|
||||
| 2 | 2h (7200s) | C-Level activos |
|
||||
| 3 | 4h (14400s) | Directores |
|
||||
| 4 | 6h (21600s) | Especialistas com rotina |
|
||||
| 5 | on-demand | Especialistas reactivos (sem timer) |
|
||||
|
||||
## Modo lista (sem argumentos)
|
||||
|
||||
Listar agentes com heartbeat configurado:
|
||||
|
||||
```sql
|
||||
SELECT name, role, status,
|
||||
runtime_config->'heartbeat'->>'enabled' as hb_enabled,
|
||||
runtime_config->'heartbeat'->>'intervalSec' as hb_interval,
|
||||
last_heartbeat_at
|
||||
FROM agents
|
||||
WHERE company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
AND runtime_config::text != '{}'
|
||||
AND runtime_config->'heartbeat' IS NOT NULL
|
||||
ORDER BY (runtime_config->'heartbeat'->>'intervalSec')::int ASC NULLS LAST;
|
||||
```
|
||||
|
||||
Complementar com contagem de execucoes recentes:
|
||||
|
||||
```sql
|
||||
SELECT a.name,
|
||||
COUNT(CASE WHEN hr.status = 'succeeded' THEN 1 END) as ok_24h,
|
||||
COUNT(CASE WHEN hr.status = 'failed' THEN 1 END) as fail_24h
|
||||
FROM agents a
|
||||
LEFT JOIN heartbeat_runs hr ON hr.agent_id = a.id
|
||||
AND hr.started_at > NOW() - INTERVAL '24 hours'
|
||||
WHERE a.company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
AND a.runtime_config->'heartbeat' IS NOT NULL
|
||||
GROUP BY a.name
|
||||
ORDER BY a.name;
|
||||
```
|
||||
|
||||
## Modo ver (com nome de agente)
|
||||
|
||||
Ultimas 10 execucoes de um agente:
|
||||
|
||||
```sql
|
||||
SELECT hr.status, hr.started_at, hr.finished_at, LEFT(hr.error, 80) as erro
|
||||
FROM heartbeat_runs hr
|
||||
JOIN agents a ON hr.agent_id = a.id
|
||||
WHERE a.company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
AND LOWER(a.name) LIKE LOWER('%{{NOME}}%')
|
||||
ORDER BY hr.started_at DESC LIMIT 10;
|
||||
```
|
||||
|
||||
## Modo criar/editar (configurar heartbeat)
|
||||
|
||||
### Activar heartbeat
|
||||
|
||||
```sql
|
||||
UPDATE agents SET runtime_config = jsonb_set(
|
||||
COALESCE(runtime_config, '{}'::jsonb),
|
||||
'{heartbeat}',
|
||||
'{"enabled": true, "intervalSec": {{INTERVALO}}, "cooldownSec": 10, "wakeOnDemand": true, "maxConcurrentRuns": 1}'::jsonb
|
||||
)
|
||||
WHERE name = '{{NOME}}'
|
||||
AND company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
RETURNING name, runtime_config;
|
||||
```
|
||||
|
||||
Confirmar sempre com o utilizador:
|
||||
- Nome do agente
|
||||
- Intervalo (sugerir tier adequado ao role)
|
||||
- wakeOnDemand (true para a maioria)
|
||||
|
||||
### Desactivar heartbeat
|
||||
|
||||
```sql
|
||||
UPDATE agents SET runtime_config = jsonb_set(
|
||||
runtime_config,
|
||||
'{heartbeat,enabled}',
|
||||
'false'::jsonb
|
||||
)
|
||||
WHERE name = '{{NOME}}'
|
||||
AND company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
RETURNING name, runtime_config;
|
||||
```
|
||||
|
||||
### Alterar intervalo
|
||||
|
||||
```sql
|
||||
UPDATE agents SET runtime_config = jsonb_set(
|
||||
runtime_config,
|
||||
'{heartbeat,intervalSec}',
|
||||
'{{INTERVALO}}'::jsonb
|
||||
)
|
||||
WHERE name = '{{NOME}}'
|
||||
AND company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
RETURNING name, runtime_config;
|
||||
```
|
||||
|
||||
## Routines do projecto (tabela routines)
|
||||
|
||||
Alem dos heartbeats por agente, existem routines organizadas por projecto com cron triggers.
|
||||
|
||||
**Estado actual:** 5 routines activas no Paperclip. 9 routines anteriores foram migradas para workflows n8n em https://automator.descomplicar.pt.
|
||||
|
||||
**5 routines Paperclip:**
|
||||
- Auditoria processos e compliance (0 10 * * *)
|
||||
- Execução tarefas AikTop (*/30 * * * *)
|
||||
- Reconciliação financeira diária (0 8 * * *)
|
||||
- Varredura inteligência competitiva (0 11 * * *)
|
||||
- Monitorização workflows n8n (0 10,18 * * *) — atribuída ao COO
|
||||
|
||||
### Listar routines activas
|
||||
|
||||
```sql
|
||||
SELECT r.title, r.status, r.priority, a.name as assignee,
|
||||
rt.cron_expression, rt.enabled, rt.next_run_at
|
||||
FROM routines r
|
||||
LEFT JOIN agents a ON r.assignee_agent_id = a.id
|
||||
LEFT JOIN routine_triggers rt ON rt.routine_id = r.id
|
||||
WHERE r.company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
ORDER BY r.title;
|
||||
```
|
||||
|
||||
### Ver execucoes de uma routine
|
||||
|
||||
```sql
|
||||
SELECT rr.status, rr.triggered_at, rr.completed_at, LEFT(rr.error, 80) as erro
|
||||
FROM routine_runs rr
|
||||
JOIN routines r ON rr.routine_id = r.id
|
||||
WHERE r.company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
AND LOWER(r.title) LIKE LOWER('%{{TITULO}}%')
|
||||
ORDER BY rr.triggered_at DESC LIMIT 10;
|
||||
```
|
||||
|
||||
## Modo criar routine (nova)
|
||||
|
||||
### Passo 1: Obter CEO ID
|
||||
|
||||
```sql
|
||||
SELECT id FROM agents
|
||||
WHERE name = 'CEO' AND company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f';
|
||||
```
|
||||
|
||||
### Passo 2: Obter projecto
|
||||
|
||||
```sql
|
||||
SELECT id, name FROM projects
|
||||
WHERE company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f';
|
||||
```
|
||||
|
||||
### Passo 3: Criar routine (SEMPRE atribuída ao CEO)
|
||||
|
||||
```sql
|
||||
INSERT INTO routines (id, company_id, project_id, title, description, assignee_agent_id, priority, status, created_at, updated_at)
|
||||
VALUES (
|
||||
gen_random_uuid(),
|
||||
'ebe10308-efd7-453f-86ab-13e6fe84004f',
|
||||
'{{PROJECT_ID}}',
|
||||
'{{TITULO}}',
|
||||
'CADEIA: CEO → {{C_LEVEL}} → {{DIRECTOR}} → {{ESPECIALISTA}}. {{DESCRICAO_TAREFA}}',
|
||||
'{{CEO_ID}}',
|
||||
'{{PRIORIDADE}}',
|
||||
'active',
|
||||
NOW(), NOW()
|
||||
)
|
||||
RETURNING id, title;
|
||||
```
|
||||
|
||||
### Passo 4: Criar cron trigger
|
||||
|
||||
**CRITICO:** O kind DEVE ser `'schedule'` (nao `'cron'`). O scheduler do Paperclip so processa triggers com `kind = 'schedule'`. Tambem e OBRIGATORIO popular `next_run_at` — sem ele o scheduler ignora o trigger.
|
||||
|
||||
```sql
|
||||
-- Calcular next_run_at antes de inserir
|
||||
-- Para crons diarios (ex: 0 8 * * *), usar:
|
||||
-- (CURRENT_DATE + 1) AT TIME ZONE 'Europe/Lisbon' + INTERVAL '{{HORA}} hours'
|
||||
-- Para crons recorrentes (ex: 0 */4 * * *), calcular proximo slot
|
||||
|
||||
INSERT INTO routine_triggers (id, company_id, routine_id, kind, label, enabled, cron_expression, timezone, next_run_at, created_at, updated_at)
|
||||
VALUES (
|
||||
gen_random_uuid(),
|
||||
'ebe10308-efd7-453f-86ab-13e6fe84004f',
|
||||
'{{ROUTINE_ID}}',
|
||||
'schedule',
|
||||
'{{LABEL}}',
|
||||
true,
|
||||
'{{CRON_EXPRESSION}}',
|
||||
'Europe/Lisbon',
|
||||
{{NEXT_RUN_AT}},
|
||||
NOW(), NOW()
|
||||
)
|
||||
RETURNING id, cron_expression, next_run_at;
|
||||
```
|
||||
|
||||
**Exemplos de next_run_at:**
|
||||
- `0 8 * * *` → `(CURRENT_DATE + 1) AT TIME ZONE 'Europe/Lisbon' + INTERVAL '8 hours'`
|
||||
- `0 */6 * * *` → `date_trunc('hour', NOW()) + INTERVAL '6 hours'`
|
||||
- `0 9 * * 1` → proxima segunda-feira as 09h
|
||||
|
||||
Confirmar sempre com o utilizador: título, cadeia, cron, projecto.
|
||||
|
||||
### Diagnostico: routines que nao disparam
|
||||
|
||||
Se routines nao disparam, verificar:
|
||||
|
||||
Invocar tool MCP: `mcp__paperclip__diag_routine_triggers_broken`
|
||||
|
||||
Corrigir com:
|
||||
```sql
|
||||
UPDATE routine_triggers SET kind = 'schedule', next_run_at = {{NEXT_RUN}}, updated_at = NOW()
|
||||
WHERE id = '{{TRIGGER_ID}}';
|
||||
```
|
||||
|
||||
### Diagnostico: pipeline noticias
|
||||
|
||||
Se noticias nao estao a ser publicadas, verificar esta cadeia:
|
||||
|
||||
```
|
||||
1. Routine triggers → kind='schedule'? next_run_at populado? last_fired_at recente?
|
||||
2. CEO heartbeat → apanha a issue da routine? delega ao CGO?
|
||||
3. CGO → delega ao Intelligence Researcher?
|
||||
4. Intelligence Researcher → cria issues PUBLICAR NOTICIA? (assignee fica NULL — normal)
|
||||
5. Cron assign-copywriter.sh → atribui ao Copywriter a cada 5 min?
|
||||
6. Copywriter → acorda com wakeOnDemand? publica no WordPress?
|
||||
7. Artigo publicado → acentuacao OK? links com aspas? titulo normalizado?
|
||||
```
|
||||
|
||||
Verificar ponto a ponto com:
|
||||
```sql
|
||||
-- Ponto 1: triggers
|
||||
SELECT r.title, rt.kind, rt.next_run_at, rt.last_fired_at
|
||||
FROM routine_triggers rt JOIN routines r ON rt.routine_id = r.id
|
||||
WHERE r.title LIKE 'Pesquisa diaria%noticias%' ORDER BY rt.cron_expression;
|
||||
|
||||
-- Ponto 4-5: issues PUBLICAR NOTICIA
|
||||
SELECT i.title, i.status, a.name as assignee, i.created_at
|
||||
FROM issues i LEFT JOIN agents a ON i.assignee_agent_id = a.id
|
||||
WHERE i.title LIKE 'PUBLICAR NOTICIA%' AND i.created_at > NOW() - INTERVAL '24 hours'
|
||||
ORDER BY i.created_at DESC;
|
||||
|
||||
-- Ponto 6: Copywriter runs
|
||||
SELECT hr.status, hr.started_at FROM heartbeat_runs hr
|
||||
JOIN agents a ON hr.agent_id = a.id WHERE a.name = 'Copywriter'
|
||||
AND hr.started_at > NOW() - INTERVAL '24 hours' ORDER BY hr.started_at DESC;
|
||||
|
||||
-- Ponto 7: artigos publicados (via SSH server)
|
||||
-- wp --allow-root post list --category=noticias --date_query='{"after":"1 day ago"}' --fields=ID,post_title
|
||||
```
|
||||
|
||||
## Cadeias de delegação por área
|
||||
|
||||
| Área | Cadeia |
|
||||
|------|--------|
|
||||
| Infraestrutura/WP/Backups/SSL | CEO → CTO → Dir. Infraestrutura → Especialista |
|
||||
| Desenvolvimento/MCPs/N8N | CEO → CTO → Dir. Desenvolvimento/Automação → Especialista |
|
||||
| Email/Tickets/Processos | CEO → COO → Dir. Suporte/Operações → Especialista |
|
||||
| Financeiro/Facturação | CEO → CFO → Dir. Financeiro → Finance Manager |
|
||||
| Marketing/SEO/Conteúdo/Ads | CEO → CMO → Dir. relevante → Especialista |
|
||||
| Vendas/Leads/Propostas | CEO → CRO → Dir. Comercial → Especialista |
|
||||
| Inteligência/Pesquisa | CEO → CGO → Dir. IA/Estratégia → Especialista |
|
||||
| Analytics/Dados | CEO → CDO → Analytics Agent |
|
||||
|
||||
## Formato de output
|
||||
|
||||
Para modo lista (heartbeats):
|
||||
```
|
||||
## Heartbeats Clip — [data]
|
||||
|
||||
| Agente | Tier | Intervalo | Enabled | Último HB | OK 24h | Fail 24h |
|
||||
...
|
||||
```
|
||||
|
||||
Para modo lista (routines):
|
||||
```
|
||||
## Routines Clip — [data]
|
||||
|
||||
| Título | Cron | Assignee | Cadeia | Próximo run | Enabled |
|
||||
...
|
||||
|
||||
Total: 5 routines activas no Paperclip (4 atribuídas ao CEO, 1 ao COO) + 9 migradas para n8n
|
||||
```
|
||||
|
||||
Para modo ver:
|
||||
```
|
||||
## Routine: {{NOME}}
|
||||
|
||||
**Cadeia:** {{cadeia_delegação}}
|
||||
**Cron:** {{cron}} | **Enabled:** {{enabled}}
|
||||
**Último trigger:** {{last_triggered_at}}
|
||||
|
||||
### Últimas 10 execuções
|
||||
| Status | Triggered | Completed | Erro |
|
||||
...
|
||||
|
||||
Taxa sucesso 24h: N/N (N%)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Healing Log
|
||||
|
||||
Registo de erros conhecidos e como evitá-los. Lido automaticamente antes de executar.
|
||||
|
||||
```jsonl
|
||||
{"date":"","issue":"","fix":"","source":"user|auto"}
|
||||
```
|
||||
|
||||
*Adicionar nova linha após cada erro corrigido.*
|
||||
@@ -0,0 +1,292 @@
|
||||
---
|
||||
name: clip-skill
|
||||
description: Gerir company skills no Paperclip — listar, instalar, atribuir a agentes, auditar cobertura. Usar quando "clip skill", "skills clip", "instalar skill", "atribuir skill", "skills paperclip".
|
||||
context: fork
|
||||
---
|
||||
|
||||
# /clip-skill — Gerir Company Skills Paperclip
|
||||
|
||||
Gerir skills instaladas na empresa Descomplicar no Paperclip. Instalar, atribuir, remover e auditar.
|
||||
|
||||
## Constantes
|
||||
|
||||
```
|
||||
BD: PGPASSWORD="paperclip" psql -h localhost -p 54329 -U paperclip -d paperclip
|
||||
COMPANY_ID: ebe10308-efd7-453f-86ab-13e6fe84004f
|
||||
API: http://localhost:3100/api
|
||||
SKILLS_CC: ~/.claude/plugins/marketplaces/descomplicar-plugins/
|
||||
```
|
||||
|
||||
## Contexto técnico
|
||||
|
||||
Skills no Paperclip funcionam como **injecção de contexto em runtime**:
|
||||
- O conteúdo do SKILL.md é injectado como contexto adicional ao agente a cada heartbeat
|
||||
- Não há instalação permanente — a skill é lida do ficheiro a cada execução
|
||||
- Atribuição é por agente via `adapter_config.paperclipSkillSync.desiredSkills` (array de slugs)
|
||||
- Skills instaladas na empresa ficam em `company_skills` — só as atribuídas ao agente são injectadas
|
||||
|
||||
**Distribuição actual de adapters:**
|
||||
- 1 agente (CEO): `gemini_local` com `gemini-2.5-pro`
|
||||
- 50 agentes: `gemini_local` com `gemini-2.5-flash`
|
||||
- 13 agentes: `opencode_local` com `openrouter/x-ai/grok-4.1-fast`
|
||||
- Agentes analyst/passive (ex: Reality Checker): `process` com `claude-sonnet-4-6` (sem heartbeat, sem skills)
|
||||
|
||||
O adapter `claude_local` já não é usado para agentes heartbeat.
|
||||
|
||||
## Modo lista (sem argumentos)
|
||||
|
||||
### Skills instaladas na empresa
|
||||
|
||||
```sql
|
||||
SELECT name, slug, key, source_type, trust_level, compatibility,
|
||||
created_at::date as instalada
|
||||
FROM company_skills
|
||||
WHERE company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
ORDER BY name;
|
||||
```
|
||||
|
||||
### Agentes com skills atribuidas
|
||||
|
||||
```sql
|
||||
SELECT name, role, status,
|
||||
adapter_config->'paperclipSkillSync'->'desiredSkills' as skills
|
||||
FROM agents
|
||||
WHERE company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
AND adapter_config::text LIKE '%paperclipSkillSync%'
|
||||
ORDER BY name;
|
||||
```
|
||||
|
||||
### Resumo
|
||||
|
||||
Apresentar:
|
||||
```
|
||||
## Skills Clip — [data]
|
||||
|
||||
**Empresa:** N skills instaladas (N locais, N built-in)
|
||||
**Agentes:** N com skills atribuidas / 62 total
|
||||
|
||||
### Skills instaladas
|
||||
| Nome | Key | Fonte | Trust | Compativel |
|
||||
...
|
||||
|
||||
### Agentes com skills
|
||||
| Agente | Role | Skills |
|
||||
...
|
||||
|
||||
### Agentes sem skills (top 10 por relevancia)
|
||||
[listar agentes com routines activas mas sem skills]
|
||||
```
|
||||
|
||||
## Modo instalar (com path ou key)
|
||||
|
||||
### Instalar skill de path local
|
||||
|
||||
Argumento: path absoluto para pasta com SKILL.md.
|
||||
|
||||
Verificar primeiro que existe SKILL.md:
|
||||
```bash
|
||||
ls {{PATH}}/SKILL.md 2>/dev/null && head -5 {{PATH}}/SKILL.md
|
||||
```
|
||||
|
||||
Instalar via API:
|
||||
```bash
|
||||
curl -s -X POST "http://localhost:3100/api/companies/ebe10308-efd7-453f-86ab-13e6fe84004f/skills/import" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
|
||||
-d '{"source": "{{PATH}}"}'
|
||||
```
|
||||
|
||||
Se API falha (auth), inserir directamente na BD:
|
||||
```sql
|
||||
-- Ler frontmatter do SKILL.md para obter name e description
|
||||
-- Depois inserir:
|
||||
INSERT INTO company_skills (id, company_id, key, slug, name, description, markdown, source_type, source_locator, trust_level, compatibility, file_inventory, created_at, updated_at)
|
||||
VALUES (
|
||||
gen_random_uuid(),
|
||||
'ebe10308-efd7-453f-86ab-13e6fe84004f',
|
||||
'descomplicar/{{PLUGIN}}/{{SKILL_NAME}}',
|
||||
'{{SKILL_NAME}}',
|
||||
'{{NAME_FROM_FRONTMATTER}}',
|
||||
'{{DESCRIPTION_FROM_FRONTMATTER}}',
|
||||
'{{FULL_SKILL_MD_CONTENT}}',
|
||||
'local_path',
|
||||
'{{PATH}}',
|
||||
'markdown_only',
|
||||
'compatible',
|
||||
'[]'::jsonb,
|
||||
NOW(), NOW()
|
||||
)
|
||||
RETURNING id, name, slug;
|
||||
```
|
||||
|
||||
Confirmar com o utilizador antes de instalar. Mostrar name e description do SKILL.md.
|
||||
|
||||
### Instalar skill do marketplace CC
|
||||
|
||||
Argumento: nome da skill no formato `plugin/skill` (ex: `crm-ops/crm`).
|
||||
|
||||
Resolver path:
|
||||
```bash
|
||||
SKILL_PATH="$HOME/.claude/plugins/marketplaces/descomplicar-plugins/{{PLUGIN}}/skills/{{SKILL}}"
|
||||
ls "$SKILL_PATH/SKILL.md" 2>/dev/null && head -10 "$SKILL_PATH/SKILL.md"
|
||||
```
|
||||
|
||||
Depois seguir o fluxo de instalacao por path local.
|
||||
|
||||
### Instalar em massa (com filtro de plugin)
|
||||
|
||||
Argumento: nome do plugin (ex: `crm-ops`).
|
||||
|
||||
```bash
|
||||
find "$HOME/.claude/plugins/marketplaces/descomplicar-plugins/{{PLUGIN}}/skills/" -name "SKILL.md" -exec dirname {} \;
|
||||
```
|
||||
|
||||
Listar todas as skills encontradas com name e description. Pedir confirmacao antes de instalar cada uma.
|
||||
|
||||
## Modo atribuir (skill a agente)
|
||||
|
||||
### Atribuir via API
|
||||
|
||||
```bash
|
||||
curl -s -X POST "http://localhost:3100/api/agents/{{AGENT_ID}}/skills/sync" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
|
||||
-d '{"desiredSkills": [{{SKILLS_ARRAY}}]}'
|
||||
```
|
||||
|
||||
### Atribuir via BD (fallback)
|
||||
|
||||
```sql
|
||||
UPDATE agents SET adapter_config = jsonb_set(
|
||||
COALESCE(adapter_config, '{}'::jsonb),
|
||||
'{paperclipSkillSync}',
|
||||
jsonb_build_object('desiredSkills', '{{SKILLS_JSON_ARRAY}}'::jsonb)
|
||||
)
|
||||
WHERE id = '{{AGENT_ID}}'
|
||||
AND company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
RETURNING name, adapter_config->'paperclipSkillSync'->'desiredSkills';
|
||||
```
|
||||
|
||||
Confirmar sempre:
|
||||
- Nome do agente
|
||||
- Skills a atribuir (mostrar name de cada)
|
||||
- Se vai substituir ou adicionar a skills existentes
|
||||
|
||||
### Atribuir por departamento (batch)
|
||||
|
||||
Argumento: nome do C-Level ou Director.
|
||||
|
||||
1. Obter agentes subordinados:
|
||||
```sql
|
||||
SELECT id, name, role FROM agents
|
||||
WHERE reports_to = '{{MANAGER_ID}}'
|
||||
AND company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f';
|
||||
```
|
||||
|
||||
2. Listar skills recomendadas para o departamento
|
||||
3. Confirmar com utilizador
|
||||
4. Aplicar a cada agente
|
||||
|
||||
## Modo remover
|
||||
|
||||
### Remover skill de agente
|
||||
|
||||
Ler skills actuais, filtrar a removida, escrever de volta:
|
||||
|
||||
```sql
|
||||
-- Ler
|
||||
SELECT adapter_config->'paperclipSkillSync'->'desiredSkills' as skills
|
||||
FROM agents WHERE id = '{{AGENT_ID}}';
|
||||
|
||||
-- Actualizar (remover skill especifica)
|
||||
-- Construir novo array sem a skill removida e usar o UPDATE do modo atribuir
|
||||
```
|
||||
|
||||
### Desinstalar skill da empresa
|
||||
|
||||
```sql
|
||||
DELETE FROM company_skills
|
||||
WHERE company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
AND slug = '{{SLUG}}'
|
||||
RETURNING name, slug;
|
||||
```
|
||||
|
||||
Avisar: isto remove a skill de todos os agentes que a referenciam. Confirmar sempre.
|
||||
|
||||
## Modo auditar
|
||||
|
||||
### Cobertura de skills
|
||||
|
||||
```sql
|
||||
-- Agentes com routines activas mas sem skills
|
||||
SELECT a.name, a.role, r.title as routine
|
||||
FROM agents a
|
||||
JOIN routines r ON r.assignee_agent_id = a.id
|
||||
WHERE a.company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
AND r.status = 'active'
|
||||
AND (a.adapter_config->'paperclipSkillSync' IS NULL
|
||||
OR a.adapter_config::text NOT LIKE '%paperclipSkillSync%')
|
||||
ORDER BY a.name;
|
||||
```
|
||||
|
||||
### Mapeamento recomendado (plugin CC → departamento Clip)
|
||||
|
||||
| Plugin CC | Agentes-alvo | Skills prioritarias |
|
||||
|-----------|-------------|-------------------|
|
||||
| core-tools | Todos | _core, quality-validator |
|
||||
| crm-ops | CRO, Dir. Comercial, Sales Manager, Lead Qualifier | crm, desk, lead-approach, orcamento |
|
||||
| gestao | COO, Dir. Operacoes, Project Manager | today, worklog, knowledge, tasks-overview |
|
||||
| infraestrutura | CTO, Dir. Infraestrutura, Infra Check, Backup Specialist | gateway-check, backup, easypanel, cwp-server |
|
||||
| marketing | CMO, Dir. SEO, Dir. Publicidade | seo-audit, seo-technical, ppc |
|
||||
| wordpress | Dir. Web, WP Update | wp-dev, wp-performance, wp-cli |
|
||||
| dev-tools | Dir. Desenvolvimento, Development Lead | dev-helper, pdf, docx |
|
||||
| automacao | Dir. Automacao | n8n, automation-lead |
|
||||
| negocio | CFO, CGO, Finance Manager | finance, research, saas |
|
||||
| perfex-dev | Dir. Desenvolvimento | perfex-module |
|
||||
|
||||
### Comparacao CC vs Clip
|
||||
|
||||
```sql
|
||||
-- Skills CC disponiveis (contar no filesystem)
|
||||
-- vs skills instaladas no Clip
|
||||
SELECT
|
||||
(SELECT COUNT(*) FROM company_skills WHERE company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f') as instaladas_clip;
|
||||
```
|
||||
|
||||
```bash
|
||||
find ~/.claude/plugins/marketplaces/descomplicar-plugins/ -name "SKILL.md" | wc -l
|
||||
```
|
||||
|
||||
Apresentar:
|
||||
```
|
||||
### Auditoria Skills — [data]
|
||||
|
||||
**CC:** N skills disponiveis em 15 plugins
|
||||
**Clip:** N instaladas (N%)
|
||||
**Agentes com skills:** N/62 (N%)
|
||||
**Agentes com routines sem skills:** N (ATENCAO)
|
||||
|
||||
### Gaps por departamento
|
||||
| Departamento | Agentes | Com skills | Sem skills | Skills recomendadas |
|
||||
...
|
||||
```
|
||||
|
||||
## Referencias
|
||||
|
||||
- Mecanismo runtime injection: conteúdo SKILL.md injectado como contexto adicional a cada heartbeat
|
||||
- API skills: `skills/paperclip/references/company-skills.md`
|
||||
- Schema BD: tabela `company_skills` (16 colunas)
|
||||
- Auditoria compatibilidade: `04-Stack/02.06-Clip/auditoria-skills-compatibilidade.md`
|
||||
- Manual: `06-Operacoes/Documentacao/Manuais/Paperclip/06-skills-e-plugins.md`
|
||||
|
||||
---
|
||||
|
||||
## Healing Log
|
||||
|
||||
Registo de erros conhecidos e como evitá-los. Lido automaticamente antes de executar.
|
||||
|
||||
```jsonl
|
||||
{"date":"2026-04-07","issue":"API /skills/import e /skills/sync sem Authorization header — rejeitadas com 401","fix":"Adicionar -H 'Authorization: Bearer $PAPERCLIP_API_KEY' a todos os curl da skill","source":"auto"}
|
||||
```
|
||||
|
||||
*Adicionar nova linha após cada erro corrigido.*
|
||||
@@ -0,0 +1,174 @@
|
||||
---
|
||||
name: clip-vision
|
||||
category: gestao
|
||||
description: "Gera documento de visao estrategica para o CEO Paperclip e bootstraps por C-Level. Resolve o vision gap — agentes param porque lhes falta a visao do fundador. Usar quando 'clip vision', 'visao paperclip', 'vision gap', 'bootstrap ceo', 'direcao agentes'."
|
||||
version: "1.0.0"
|
||||
created: 2026-04-07
|
||||
tools: [Read, Write, Bash, AskUserQuestion]
|
||||
---
|
||||
|
||||
# Skill: /clip-vision
|
||||
|
||||
Gera documento de visao estrategica para o CEO Paperclip e bootstrap documents para cada C-Level. Baseado no padrao Paperclip Vision Skill (#368 Aron Prins).
|
||||
|
||||
---
|
||||
|
||||
## Problema que resolve
|
||||
|
||||
Agentes Paperclip param de produzir apos setup porque so recebem tarefas operacionais, nao visao estrategica. O CEO nao sabe para onde ir. Os C-Level nao sabem o que priorizar. O "vision gap" faz com que a organizacao funcione mas sem direcao.
|
||||
|
||||
---
|
||||
|
||||
## Processo de execucao
|
||||
|
||||
### Fase 1 — Recolha de contexto (automatica)
|
||||
|
||||
Recolher dados do estado actual do Paperclip e do stack:
|
||||
|
||||
1. **Ler estado Paperclip:**
|
||||
- Ficheiro `/home/ealmeida/paperclip/` — listar agents activos
|
||||
- Desk CRM task #2041 (projecto Stack) — estado
|
||||
- `Hub/04-Stack/STK-Estado-Actual.md` — metricas actuais
|
||||
- `Hub/04-Stack/plano-consolidado-stack-q2-2026.md` — plano e metas
|
||||
|
||||
2. **Ler issues e routines:**
|
||||
- Via MCP Paperclip ou ficheiros locais em `/home/ealmeida/paperclip/`
|
||||
- Issues abertas, routines activas, ultimos heartbeats
|
||||
|
||||
3. **Compilar contexto:** resumo de 10-15 linhas com estado actual
|
||||
|
||||
### Fase 2 — Entrevista ao fundador (interactiva)
|
||||
|
||||
Fazer 5-7 perguntas ao Emanuel usando AskUserQuestion. Cada pergunta com 3-4 opcoes + "outro":
|
||||
|
||||
**Pergunta 1:** Qual e a prioridade principal para os proximos 30 dias?
|
||||
- a) Aumentar receita (novos clientes, propostas)
|
||||
- b) Melhorar operacoes internas (eficiencia, automacao)
|
||||
- c) Desenvolver produto/servico novo
|
||||
- d) Consolidar o que ja existe (qualidade, documentacao)
|
||||
- e) Outro: ___
|
||||
|
||||
**Pergunta 2:** Que departamento precisa de mais atencao neste momento?
|
||||
- a) D1 Comercial (vendas, leads, propostas)
|
||||
- b) D6 Marketing (SEO, conteudo, redes sociais)
|
||||
- c) D7 Tecnologia (infra, dev, automacao)
|
||||
- d) D3 Contabilidade (facturas, despesas, cash flow)
|
||||
- e) Outro: ___
|
||||
|
||||
**Pergunta 3:** Que nivel de autonomia queres dar aos agentes?
|
||||
- a) Passive — so actuam quando pedido, sempre com aprovacao
|
||||
- b) Balanced — actuam em rotinas, pedem aprovacao para novidades
|
||||
- c) Active — actuam proactivamente, reportam resultados
|
||||
- d) Manter o actual
|
||||
|
||||
**Pergunta 4:** Qual e o budget mensal aceitavel para agentes IA (tokens + APIs)?
|
||||
- a) <50 EUR/mes (minimo, so essenciais)
|
||||
- b) 50-100 EUR/mes (moderado)
|
||||
- c) 100-200 EUR/mes (investimento activo)
|
||||
- d) >200 EUR/mes (sem restricao significativa)
|
||||
|
||||
**Pergunta 5:** Qual e o objectivo principal do Q2 2026?
|
||||
- a) Facturacao: atingir X EUR/mes
|
||||
- b) Clientes: fechar N novos contratos
|
||||
- c) Produto: lancar servico/SaaS especifico
|
||||
- d) Stack: maximizar capacidade operacional
|
||||
- e) Outro: ___
|
||||
|
||||
**Pergunta 6:** O que deve ser explicitamente proibido para os agentes?
|
||||
- a) Contactar clientes directamente
|
||||
- b) Fazer deploy sem aprovacao
|
||||
- c) Gastar budget acima de X
|
||||
- d) Todas as anteriores
|
||||
- e) Outro: ___
|
||||
|
||||
**Pergunta 7:** Como medes sucesso dos agentes Paperclip?
|
||||
- a) Output tangivel (artigos, propostas, deploys)
|
||||
- b) Reducao de tempo em tarefas manuais
|
||||
- c) ROI mensuravel (custo vs valor gerado)
|
||||
- d) Consistencia (fazem sempre o basico bem)
|
||||
|
||||
### Fase 3 — Geracao de documentos
|
||||
|
||||
Com base nas respostas, gerar 5 documentos:
|
||||
|
||||
#### 1. vision.md (destino: /home/ealmeida/paperclip/vision.md)
|
||||
|
||||
```markdown
|
||||
# Visao Descomplicar — {data}
|
||||
|
||||
## Missao
|
||||
{extraido das respostas + contexto}
|
||||
|
||||
## Objectivos Q2 2026
|
||||
1. {objectivo principal}
|
||||
2. {objectivo secundario}
|
||||
3. {objectivo terciario}
|
||||
|
||||
## Prioridades (30 dias)
|
||||
1. {prioridade 1 com accao concreta}
|
||||
2. {prioridade 2}
|
||||
3. {prioridade 3}
|
||||
|
||||
## Restricoes
|
||||
- {proibicoes definidas na P6}
|
||||
- Budget maximo: {P4}
|
||||
- Governance: {P3}
|
||||
|
||||
## Metricas de sucesso
|
||||
- {P7 — como medir}
|
||||
|
||||
## Revisao
|
||||
- Gerado: {data}
|
||||
- Proxima revisao: {data + 90 dias}
|
||||
```
|
||||
|
||||
#### 2-5. Bootstrap documents (destino: /home/ealmeida/paperclip/)
|
||||
|
||||
Para cada C-Level (CEO, CTO, CMO, COO), gerar `{role}-bootstrap.md`:
|
||||
|
||||
```markdown
|
||||
# Bootstrap {Role} — {data}
|
||||
|
||||
## Contexto
|
||||
{estado actual do departamento relevante}
|
||||
|
||||
## Top 3 prioridades
|
||||
1. {prioridade com accao e deadline}
|
||||
2. {prioridade}
|
||||
3. {prioridade}
|
||||
|
||||
## Recursos disponiveis
|
||||
- Skills: {lista relevante}
|
||||
- MCPs: {lista relevante}
|
||||
- Routines: {activas no departamento}
|
||||
|
||||
## Restricoes
|
||||
- {do vision.md, filtradas para este papel}
|
||||
|
||||
## Proxima accao
|
||||
{1 accao concreta que pode fazer no proximo heartbeat}
|
||||
```
|
||||
|
||||
### Fase 4 — Resumo e confirmacao
|
||||
|
||||
Apresentar resumo ao utilizador:
|
||||
- 5 documentos gerados com paths
|
||||
- Sugerir proximos passos (injectar vision.md no CEO heartbeat, etc.)
|
||||
- Perguntar se quer ajustar algo
|
||||
|
||||
---
|
||||
|
||||
## Notas importantes
|
||||
|
||||
- Os documentos devem ser **accionaveis**, nao genericos
|
||||
- Cada bootstrap deve referenciar **dados reais** do estado actual
|
||||
- O vision.md deve ser **injectado no CEO** como contexto do heartbeat
|
||||
- Sugerir /schedule trimestral para refrescar a visao
|
||||
|
||||
---
|
||||
|
||||
## Healing Log
|
||||
|
||||
```jsonl
|
||||
{"date":"","issue":"","fix":"","source":"user|auto"}
|
||||
```
|
||||
@@ -0,0 +1,162 @@
|
||||
---
|
||||
name: clip
|
||||
description: Dashboard rápido Paperclip — estado agentes, issues abertas, heartbeats recentes, alertas. Usar quando "clip", "paperclip", "estado clip", "agentes clip".
|
||||
context: fork
|
||||
---
|
||||
|
||||
# /clip — Dashboard Paperclip
|
||||
|
||||
Dashboard rapido do estado do Clip (Paperclip Orquestrador Descomplicar).
|
||||
|
||||
## Constantes
|
||||
|
||||
```
|
||||
BD: PGPASSWORD="paperclip" psql -h localhost -p 54329 -U paperclip -d paperclip
|
||||
COMPANY_ID: ebe10308-efd7-453f-86ab-13e6fe84004f
|
||||
```
|
||||
|
||||
## Procedimento
|
||||
|
||||
Executar os 5 passos em paralelo (silenciosamente), depois apresentar dashboard compacto.
|
||||
|
||||
### Passo 1: Estado do servico
|
||||
|
||||
```bash
|
||||
systemctl --user status paperclip 2>&1 | head -5
|
||||
```
|
||||
|
||||
### Passo 2: Agentes por status
|
||||
|
||||
Invocar tool MCP: `mcp__paperclip__diag_agents_by_status`
|
||||
|
||||
### Passo 3: Issues abertas
|
||||
|
||||
```sql
|
||||
SELECT i.title, i.status, i.priority, a.name as assignee
|
||||
FROM issues i LEFT JOIN agents a ON i.assignee_agent_id = a.id
|
||||
WHERE i.company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
AND i.status NOT IN ('done','cancelled')
|
||||
ORDER BY
|
||||
CASE i.priority WHEN 'critical' THEN 1 WHEN 'high' THEN 2 WHEN 'medium' THEN 3 ELSE 4 END,
|
||||
i.status;
|
||||
```
|
||||
|
||||
### Passo 4: Ultimos 10 heartbeats
|
||||
|
||||
```sql
|
||||
SELECT a.name, hr.status, hr.started_at, hr.finished_at
|
||||
FROM heartbeat_runs hr JOIN agents a ON hr.agent_id = a.id
|
||||
WHERE a.company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
ORDER BY hr.started_at DESC LIMIT 10;
|
||||
```
|
||||
|
||||
### Passo 5: Alertas
|
||||
|
||||
Heartbeats falhados nas ultimas 24h:
|
||||
```sql
|
||||
SELECT a.name, LEFT(hr.error, 80) as erro, hr.started_at
|
||||
FROM heartbeat_runs hr JOIN agents a ON hr.agent_id = a.id
|
||||
WHERE a.company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
AND hr.status = 'failed'
|
||||
AND hr.started_at > NOW() - INTERVAL '24 hours'
|
||||
ORDER BY hr.started_at DESC;
|
||||
```
|
||||
|
||||
Falsos blockers (INC-07):
|
||||
|
||||
Invocar tool MCP: `mcp__paperclip__diag_false_blockers`
|
||||
|
||||
Se resultado > 0 → listar como alerta: "N issues blocked com sub-tasks activas — provavelmente deveriam ser in_progress".
|
||||
|
||||
Token burn — agentes com consumo excessivo de tokens nas últimas 24h (INC-12):
|
||||
|
||||
Invocar tool MCP: `mcp__paperclip__diag_heartbeat_token_usage(hours=24)`
|
||||
|
||||
Se `agentes_risco > 0` → alertar: "TOKEN BURN: N agentes com runs >500K cache tokens — usar /clip-health check 19 para detalhes".
|
||||
|
||||
Routines presas (INC-08) — a ligação issue→routine está em `routine_runs.linked_issue_id`:
|
||||
|
||||
Invocar tool MCP: `mcp__paperclip__diag_stuck_routines(hours=4)`
|
||||
|
||||
Se `routines_presas > 0` → alertar: "ROUTINE BLOQUEADA: N issues de routine paradas >4h — usar /clip-health check 20".
|
||||
|
||||
Budget (agentes com >0 configurado):
|
||||
```sql
|
||||
SELECT name, budget_monthly_cents, spent_monthly_cents,
|
||||
CASE WHEN budget_monthly_cents > 0
|
||||
THEN ROUND(spent_monthly_cents::numeric / budget_monthly_cents * 100, 1)
|
||||
ELSE 0 END as pct
|
||||
FROM agents
|
||||
WHERE company_id = 'ebe10308-efd7-453f-86ab-13e6fe84004f'
|
||||
AND budget_monthly_cents > 0
|
||||
ORDER BY pct DESC;
|
||||
```
|
||||
|
||||
### Passo 6: Saude API (endpoint dashboard)
|
||||
|
||||
Verificar se os endpoints criticos respondem:
|
||||
```bash
|
||||
HEALTH=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3100/api/health)
|
||||
DASH=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3100/api/companies/ebe10308-efd7-453f-86ab-13e6fe84004f/dashboard)
|
||||
BADGES=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3100/api/companies/ebe10308-efd7-453f-86ab-13e6fe84004f/sidebar-badges)
|
||||
echo "health=$HEALTH dashboard=$DASH badges=$BADGES"
|
||||
```
|
||||
|
||||
- health=200 = OK (sem auth)
|
||||
- dashboard/badges=401 = OK (auth funciona, endpoint existe)
|
||||
- dashboard/badges=404 ou 500 = CRITICO (endpoint em falha, provavelmente refs orfas na BD)
|
||||
|
||||
Verificar instancias duplicadas:
|
||||
```bash
|
||||
ss -tlnp | grep -E "310[0-9]" | wc -l
|
||||
```
|
||||
- 1 = OK
|
||||
- 2+ = AVISO (processos orfaos, recomendar limpeza)
|
||||
|
||||
### Passo 7: Company skills
|
||||
|
||||
Invocar tool MCP: `mcp__paperclip__diag_company_skills_summary`
|
||||
|
||||
## Formato de output
|
||||
|
||||
Apresentar como dashboard compacto:
|
||||
|
||||
```
|
||||
## Clip Dashboard — [data/hora]
|
||||
|
||||
**Servico:** [running/stopped] ha [tempo]
|
||||
**Agentes:** [N] total — [n] running, [n] idle, [n] paused
|
||||
**API:** health=[code] dashboard=[code] badges=[code] | Instancias: [N]
|
||||
**Skills:** [N] instaladas ([n] locais, [n] skills.sh, [n] github)
|
||||
|
||||
### Issues abertas
|
||||
| Titulo | Status | Prioridade | Assignee |
|
||||
...
|
||||
|
||||
### Heartbeats recentes
|
||||
| Agente | Status | Inicio | Fim |
|
||||
...
|
||||
|
||||
### Alertas
|
||||
- [CRITICO] descricao
|
||||
- [TOKEN BURN] N agentes >500K tokens — /clip-health check 19
|
||||
- [ROUTINE BLOQUEADA] N issues paradas >4h — /clip-health check 20
|
||||
```
|
||||
|
||||
## Referencias
|
||||
|
||||
- Manual: Hub `06-Operacoes/Documentacao/Manuais/Paperclip/`
|
||||
- API: `04-Stack/02.06-Clip/skills.md`
|
||||
- Spec: `04-Stack/02.06-Clip/docs/superpowers/specs/2026-03-28-clip-grande-visao-design.md`
|
||||
|
||||
---
|
||||
|
||||
## Healing Log
|
||||
|
||||
Registo de erros conhecidos e como evitá-los. Lido automaticamente antes de executar.
|
||||
|
||||
```jsonl
|
||||
{"date":"","issue":"","fix":"","source":"user|auto"}
|
||||
```
|
||||
|
||||
*Adicionar nova linha após cada erro corrigido.*
|
||||
Reference in New Issue
Block a user