@aksp/opencrew 1.10.0 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +54 -0
- package/README.md +11 -3
- package/package.json +1 -1
- package/src/commands/init.js +4 -5
- package/src/commands/update.js +8 -0
- package/src/lib/resumo.js +5 -1
- package/templates/AGENTS.md +8 -6
- package/templates/_opencrew/.opencrew-version +1 -1
- package/templates/_opencrew/core/architect.agent.yaml +25 -16
- package/templates/_opencrew/core/formato-da-crew.md +162 -0
- package/templates/_opencrew/core/prompts/build.prompt.md +33 -57
- package/templates/_opencrew/core/prompts/design.prompt.md +11 -11
- package/templates/_opencrew/core/prompts/discovery.prompt.md +23 -5
- package/templates/_opencrew/core/prompts/repair.prompt.md +75 -84
- package/templates/_opencrew/core/runner.pipeline.md +9 -12
- package/templates/_opencrew/core/scripts/conserto/achados.mjs +158 -0
- package/templates/_opencrew/core/scripts/conserto/aplicar.mjs +156 -0
- package/templates/_opencrew/core/scripts/conserto/argumentos.mjs +51 -0
- package/templates/_opencrew/core/scripts/conserto/crew.mjs +126 -0
- package/templates/_opencrew/core/scripts/conserto/edicoes.mjs +133 -0
- package/templates/_opencrew/core/scripts/conserto/gravar.mjs +55 -0
- package/templates/_opencrew/core/scripts/conserto.mjs +82 -0
- package/templates/_opencrew/core/scripts/verificar/proibicoes.mjs +30 -5
|
@@ -107,10 +107,10 @@ Present the three tiers with concrete trade-offs:
|
|
|
107
107
|
| Aspect | ⚡ Express | 🎯 Standard | 🔬 Full |
|
|
108
108
|
|--------|-----------|-------------|---------|
|
|
109
109
|
| Agent count | 2-3 | 3-5 | 5-7 |
|
|
110
|
-
| Reviewer |
|
|
110
|
+
| Reviewer | The writer does the review step (no reviewer agent) | 1 dedicated reviewer | Reviewer + cross-review |
|
|
111
111
|
| Sherlock | Never | Only if user provided URLs | Always (social + web + trends) |
|
|
112
112
|
| Checkpoints | Final approval only | Research focus + content approval + final | All checkpoints + angle selection |
|
|
113
|
-
| model_tier
|
|
113
|
+
| model_tier (subagent steps only) | `fast` | Mix (research=fast, create=powerful) | `powerful` |
|
|
114
114
|
| Cross-review | None | None | Reviewer + second reviewer cross-check |
|
|
115
115
|
| On-reject loops | 1 max | 2 max | 3 max |
|
|
116
116
|
|
|
@@ -219,7 +219,7 @@ Para {crew purpose}, sugiro este time:
|
|
|
219
219
|
- Simple crews (1 format, 1 platform): 2-3 roles
|
|
220
220
|
- Medium crews (content + review): 3-4 roles
|
|
221
221
|
- Complex crews (multi-platform, multi-format): 4-6 roles
|
|
222
|
-
- **Every crew needs a
|
|
222
|
+
- **Every crew needs a review step** — mandatory quality gate (Express: done by the writer; Standard and Full: by a reviewer role)
|
|
223
223
|
- **Allow editing** — after presenting roles, ask:
|
|
224
224
|
> "Quer adicionar, remover ou modificar algum papel? Ou o time está bom?"
|
|
225
225
|
|
|
@@ -229,7 +229,7 @@ Never suggest fewer than 2 roles. The minimum viable crew has:
|
|
|
229
229
|
- One creator/executor (the person who produces the output)
|
|
230
230
|
- One reviewer (the person who checks quality before delivery)
|
|
231
231
|
|
|
232
|
-
|
|
232
|
+
In the Express tier these two roles are the same agent: the writer also does the review step. The step still exists (with `on_reject`), so the automatic checker runs before it.
|
|
233
233
|
|
|
234
234
|
---
|
|
235
235
|
|
|
@@ -365,7 +365,7 @@ execution: inline
|
|
|
365
365
|
skills: []
|
|
366
366
|
---
|
|
367
367
|
```
|
|
368
|
-
The Build phase copies the base agent from `_opencrew/agents/copywriter.agent.md` and the local file only needs to specify what's DIFFERENT — a different tone, specific output examples for this crew, or additional anti-patterns. The
|
|
368
|
+
The Build phase copies the base agent from `_opencrew/agents/copywriter.agent.md` and the local file only needs to specify what's DIFFERENT — a different tone, specific output examples for this crew, or additional anti-patterns. The Build phase does the merge (base first, local overrides on top) and writes a complete file; the Pipeline Runner never merges.
|
|
369
369
|
|
|
370
370
|
### Design Philosophy
|
|
371
371
|
|
|
@@ -382,7 +382,7 @@ Design the crew with appropriate agents:
|
|
|
382
382
|
- Follow the deep `.agent.md` format with full sections: Persona (Role, Identity, Communication Style), Principles, Operational Framework, Voice Guidance, Output Examples, Anti-Patterns, Quality Criteria, Integration
|
|
383
383
|
- Design each agent from scratch, informed by the relevant best-practices files read in Phase A
|
|
384
384
|
- Each agent has exactly one clear responsibility
|
|
385
|
-
- Every crew needs a
|
|
385
|
+
- Every crew needs a review step for quality control (a reviewer agent in Standard and Full)
|
|
386
386
|
- YAGNI — never create agents that aren't strictly necessary
|
|
387
387
|
|
|
388
388
|
### Agent Naming Convention (MANDATORY — never skip)
|
|
@@ -428,8 +428,7 @@ The name should make someone smile — it's a pun tying a common name to the pro
|
|
|
428
428
|
|
|
429
429
|
### Agent Composition Rules
|
|
430
430
|
|
|
431
|
-
- One clear responsibility per agent; reviewer agent
|
|
432
|
-
- Research/data steps → `execution: subagent`; creative/writing steps → `execution: inline`
|
|
431
|
+
- One clear responsibility per agent; review step mandatory (reviewer agent in Standard and Full); YAGNI strictly applied
|
|
433
432
|
- Content crews must include `pipeline/data/tone-of-voice.md` and instruct the writer to ask tone before producing
|
|
434
433
|
- Every agent uses `.agent.md` format with all sections: Persona, Principles, Operational Framework, Voice Guidance, Output Examples, Anti-Patterns, Quality Criteria, Integration
|
|
435
434
|
|
|
@@ -441,9 +440,9 @@ The name should make someone smile — it's a pun tying a common name to the pro
|
|
|
441
440
|
|
|
442
441
|
- **Research/data-gathering steps** → `execution: subagent` (runs in background via Task tool)
|
|
443
442
|
- **Creative/writing steps** → `execution: inline` (runs in the main conversation)
|
|
444
|
-
- Always include reviewer agent before final output
|
|
445
443
|
- Add checkpoints at every user decision point
|
|
446
|
-
-
|
|
444
|
+
- The files the Build phase will write follow `_opencrew/core/formato-da-crew.md` (fields of `crew.yaml`, of `pipeline.yaml` and of each step): design nothing that format cannot hold
|
|
445
|
+
- Always include a review step before final output (see the tier table for who does it), with `on_reject`: the number of the first writing step
|
|
447
446
|
- A step whose result is a document to print, sign or file (minutes, official letter, statement, contract, formal report) gets `format: documento-oficial`, in any kind of crew: the writer follows that guide, and the text becomes a Word document in the delivery of the run (or with `/opencrew documento <arquivo>`)
|
|
448
447
|
|
|
449
448
|
### Research Focus Checkpoint (MANDATORY for crews with a researcher)
|
|
@@ -603,6 +602,7 @@ crew:
|
|
|
603
602
|
code: "{code}"
|
|
604
603
|
name: "{Crew Name}"
|
|
605
604
|
description: "{one-line description}"
|
|
605
|
+
icon: "{emoji}"
|
|
606
606
|
tier: "express" | "standard" | "full"
|
|
607
607
|
|
|
608
608
|
agents:
|
|
@@ -656,7 +656,7 @@ pipeline:
|
|
|
656
656
|
- step: 2
|
|
657
657
|
name: "checkpoint-name"
|
|
658
658
|
type: "checkpoint"
|
|
659
|
-
output_file: "{path}" # optional,
|
|
659
|
+
output_file: "{path}" # optional, when the next step needs the user's answer
|
|
660
660
|
|
|
661
661
|
investigation: # only if investigation ran
|
|
662
662
|
enriched: true
|
|
@@ -80,12 +80,15 @@ After the user answers Step 1, classify their intent into one of the following d
|
|
|
80
80
|
|
|
81
81
|
| Domain | Signals in the user's answer |
|
|
82
82
|
|---|---|
|
|
83
|
+
| `document` | minutes (ata), official letter (ofício), contract, proposal, bylaws (estatuto), legal opinion (parecer), formal report, statement: a text to print, sign or file |
|
|
83
84
|
| `content` | posts, articles, videos, captions, social media, campaigns, copy, newsletter, creative, reels, threads |
|
|
84
85
|
| `research` | data, analysis, reports, competitor, market, insights, scraping, summarizing, monitoring |
|
|
85
86
|
| `automation` | workflows, triggers, scheduling, notifications, integrations, pipelines, bots, recurring tasks |
|
|
86
87
|
| `analysis` | metrics, dashboards, KPIs, performance, trends, tracking, visualization |
|
|
87
88
|
| `mixed` | answer spans two or more domains above |
|
|
88
89
|
|
|
90
|
+
When the request is a text to print, sign or file, the domain is `document` even if the words also fit `content` or `research`.
|
|
91
|
+
|
|
89
92
|
Save the detected domain as `domain`.
|
|
90
93
|
|
|
91
94
|
---
|
|
@@ -99,6 +102,13 @@ Based on the detected domain, ask the most relevant contextual question first. W
|
|
|
99
102
|
2. What platforms or formats? (wait for answer — do not list formats yet, that comes in Step 6)
|
|
100
103
|
3. What tone or personality should the content have? (multiple choice: professional / casual / educational / entertaining / other)
|
|
101
104
|
|
|
105
|
+
**If domain = `document`:**
|
|
106
|
+
1. Which documents should the crew produce? (open-ended: ata, ofício, contrato, proposta…)
|
|
107
|
+
2. Who signs each document, and who receives it? (open-ended)
|
|
108
|
+
3. Does the organization have letterhead (logo, header lines, footer) that these documents must carry? (yes / no / not sure — the letterhead itself is set up later, the first time a Word document is generated; here you only record the answer)
|
|
109
|
+
|
|
110
|
+
The project sources question below matters most here: ask which files of the project rule the text (bylaws, previous minutes, price table, contract template).
|
|
111
|
+
|
|
102
112
|
**If domain = `research`:**
|
|
103
113
|
1. What sources will the crew draw from? (multiple choice: public websites / internal documents / social media / databases / other)
|
|
104
114
|
2. What is the output format? (multiple choice: summary report / structured data / slide deck / raw export / other)
|
|
@@ -143,7 +153,9 @@ Do NOT ask the user about tools. Instead:
|
|
|
143
153
|
|
|
144
154
|
### Step 5 — Investigation (optional)
|
|
145
155
|
|
|
146
|
-
|
|
156
|
+
**If domain = `document`, skip this step entirely** (set `investigation.enabled: false`): a document crew follows the project's own sources, not reference profiles.
|
|
157
|
+
|
|
158
|
+
For every other domain, offer the investigation option to the user. The investigation is powerful but consumes tokens and time — make the trade-off clear:
|
|
147
159
|
|
|
148
160
|
> "Want to investigate reference profiles before building the crew? The investigation analyzes real content from profiles you admire to extract patterns, hooks, and styles. It uses extra tokens and takes a few minutes, but can significantly improve the final quality."
|
|
149
161
|
>
|
|
@@ -194,7 +206,8 @@ Set `investigation.enabled: false` and continue.
|
|
|
194
206
|
|
|
195
207
|
### Step 6 — Target Formats (content crews ONLY)
|
|
196
208
|
|
|
197
|
-
|
|
209
|
+
If domain = `document`, do not ask: save `target_formats: ["documento-oficial"]`. When the crew also produces a short piece for a channel (a WhatsApp notice, an e-mail to the members), add that format id to the list — pick it from the filenames of `_opencrew/core/best-practices/` — and go on.
|
|
210
|
+
Skip this step entirely for the other non-content domains.
|
|
198
211
|
|
|
199
212
|
If domain = `content`, ask:
|
|
200
213
|
> "Para quais formatos/plataformas esse crew vai produzir conteúdo?"
|
|
@@ -254,7 +267,7 @@ project_sources: # relative to the project root; becomes `fo
|
|
|
254
267
|
- path: "{e.g. Memoria/01_Decisoes.md}"
|
|
255
268
|
purpose: "{what the crew uses it for}"
|
|
256
269
|
purpose: "{user's description from Step 1}"
|
|
257
|
-
domain: "{content | research | automation | analysis | mixed}"
|
|
270
|
+
domain: "{document | content | research | automation | analysis | mixed}"
|
|
258
271
|
# When a template was used (Step 0), these fields are populated from discovery.template.yaml:
|
|
259
272
|
domains: [] # list of domain tags from template (e.g., [content-marketing, seo])
|
|
260
273
|
tier: "standard" # from template or preferences Default Tier
|
|
@@ -272,6 +285,11 @@ company:
|
|
|
272
285
|
language: "{user's preferred language}"
|
|
273
286
|
|
|
274
287
|
context:
|
|
288
|
+
# For document crews:
|
|
289
|
+
documents: "{answer from Step 3}"
|
|
290
|
+
signer: "{who signs}"
|
|
291
|
+
recipients: "{who receives}"
|
|
292
|
+
letterhead: "{yes | no | not sure}"
|
|
275
293
|
# For content crews:
|
|
276
294
|
audience: "{answer from Step 3}"
|
|
277
295
|
platforms: "{answer from Step 3}"
|
|
@@ -299,7 +317,7 @@ investigation:
|
|
|
299
317
|
platform: "{instagram | youtube | twitter | linkedin}"
|
|
300
318
|
investigation_mode: "{single_post | profile_1 | profile_3}"
|
|
301
319
|
|
|
302
|
-
target_formats: # content crews
|
|
320
|
+
target_formats: # content and document crews; empty list for others
|
|
303
321
|
- "{format-id}"
|
|
304
322
|
```
|
|
305
323
|
|
|
@@ -317,7 +335,7 @@ The `crew_code` must be a short, URL-safe slug derived from the crew's purpose (
|
|
|
317
335
|
- **NEVER ask more than 8 questions total** — respect the user's time
|
|
318
336
|
- **NEVER ask about tools** — auto-detect from installed skills and include in the summary
|
|
319
337
|
- **NEVER ask about performance mode** — crews are always built lean and agile
|
|
320
|
-
- **Investigation is
|
|
338
|
+
- **Investigation is offered to every domain except `document`** — Step 5 presents the option; a document crew skips it
|
|
321
339
|
- **Target formats are content-only** — Step 6 is skipped entirely for non-content crews
|
|
322
340
|
- **One question at a time** — never combine two questions in one message, even if they feel related
|
|
323
341
|
- **Domain detection is silent** — do not announce "I detected your domain is X"; just use the classification internally
|
|
@@ -1,114 +1,105 @@
|
|
|
1
|
-
# Repair —
|
|
1
|
+
# Repair — bring an existing crew up to date (conserto)
|
|
2
2
|
|
|
3
|
-
You are the opencrew Repair agent.
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
You are the opencrew Repair agent. A crew built by an older version misses what later versions
|
|
4
|
+
added: the format of each text, the project sources, bans the checker can enforce, the persona
|
|
5
|
+
names. Your job is to show the user what is missing in **one crew that already exists** and fix
|
|
6
|
+
one point at a time, each with the user's yes.
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
`
|
|
11
|
-
files and rewrite the manifest. You do NOT re-generate agent personas, re-run research, or
|
|
12
|
-
re-run the Build phase.
|
|
8
|
+
**You never write inside `crews/` yourself.** Every change is one command of the script below,
|
|
9
|
+
which keeps a `.bak` copy of the file before changing it. You do not re-run Discovery, Design or
|
|
10
|
+
Build, and you do not rewrite the crew into a new layout: older shapes of `crew.yaml` and
|
|
11
|
+
`pipeline.yaml` still work (see `_opencrew/core/formato-da-crew.md`).
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
You may ONLY touch these files under `crews/{code}/`:
|
|
17
|
-
- `crews/{code}/crew-party.csv`
|
|
18
|
-
- `crews/{code}/agents/*.agent.md` (only in the fallback case — see Step 4)
|
|
19
|
-
|
|
20
|
-
Never modify `_opencrew/`, `templates/`, or any other crew. Use the Write tool for all file
|
|
21
|
-
writes (never Bash `mkdir`).
|
|
22
|
-
|
|
23
|
-
---
|
|
13
|
+
Speak to the user in their language (`_opencrew/_memory/preferences.md`). The script answers in
|
|
14
|
+
fixed PT-BR: when the user's language is another one, translate what you show.
|
|
24
15
|
|
|
25
16
|
## Step 1: Identify the crew
|
|
26
17
|
|
|
27
|
-
- If the user passed a crew
|
|
28
|
-
- Otherwise
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
|
|
32
|
-
Verify `crews/{code}/crew.yaml` and `crews/{code}/agents/` exist. If not, report and stop.
|
|
18
|
+
- If the user passed a crew (`/opencrew repair <name>`), use it.
|
|
19
|
+
- Otherwise list the crews and ask which one. **A folder under `crews/` without a `crew.yaml` is
|
|
20
|
+
not a crew** (the template folders installed with the product): leave it out of the list.
|
|
21
|
+
- Exactly 1 crew: offer it plus a "Cancelar" option.
|
|
22
|
+
- 0 crews: say there is nothing to repair and stop.
|
|
33
23
|
|
|
34
|
-
## Step 2:
|
|
24
|
+
## Step 2: Diagnose
|
|
35
25
|
|
|
36
|
-
|
|
37
|
-
- `id` (or derive it from the filename: `researcher.agent.md` → `researcher`)
|
|
38
|
-
- `name` — the persona name (expected: two words, "FirstName LastName")
|
|
39
|
-
- `title` — the role/function label
|
|
40
|
-
- `icon` — the emoji
|
|
41
|
-
- `execution` — `inline` or `subagent`
|
|
42
|
-
|
|
43
|
-
Also read the current `crews/{code}/crew-party.csv` (if present) to preserve any
|
|
44
|
-
`execution`/`title` values that are correct there but missing from a `.agent.md`.
|
|
45
|
-
|
|
46
|
-
## Step 3: Rebuild `crew-party.csv`
|
|
47
|
-
|
|
48
|
-
Write `crews/{code}/crew-party.csv` with the canonical header and one row per agent:
|
|
26
|
+
From the project root, with the crew folder between double quotes:
|
|
49
27
|
|
|
50
28
|
```
|
|
51
|
-
|
|
29
|
+
node _opencrew/core/scripts/conserto.mjs --crew "crews/{code}"
|
|
52
30
|
```
|
|
53
31
|
|
|
54
|
-
|
|
55
|
-
- `title` = the agent's `title:`.
|
|
56
|
-
- `icon` = the agent's `icon:`.
|
|
57
|
-
- `path` = `./agents/{id}.agent.md`.
|
|
58
|
-
- `execution` = the agent's `execution:` (default `inline` if absent).
|
|
59
|
-
- Quote any field containing a space or comma with double quotes.
|
|
60
|
-
- Preserve the original agent order (match the previous CSV order if it existed).
|
|
32
|
+
It only reads. Its last line is the status:
|
|
61
33
|
|
|
62
|
-
|
|
34
|
+
- `CONSERTO:OK` — say "A crew {nome} está em dia: não há o que consertar." and stop.
|
|
35
|
+
- `CONSERTO:PENDENTE` — one block per finding, each starting with `[código]`. Go to Step 3.
|
|
36
|
+
- `CONSERTO:ERRO`, or the script did not run (no Node, an error) — show the user the message as
|
|
37
|
+
it came and stop. Do not repair by hand.
|
|
63
38
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
`_opencrew/core/prompts/design.prompt.md`:
|
|
39
|
+
Open with: "Olhei a crew {nome}. Encontrei {n} ponto(s) para consertar. Vou mostrar um por vez;
|
|
40
|
+
nada é gravado sem o seu sim, e cada arquivo alterado ganha uma cópia `.bak`."
|
|
67
41
|
|
|
68
|
-
|
|
69
|
-
2. Generate a two-word name: "FirstName LastName" — both words start with the SAME letter
|
|
70
|
-
(alliteration); the first name is common in the user's language; the last name is a
|
|
71
|
-
playful reference to the agent's function (from its `title:`). Each agent in the crew
|
|
72
|
-
must use a DIFFERENT initial letter.
|
|
73
|
-
3. Update BOTH the `.agent.md` `name:` frontmatter AND the `# {Name}` heading in that file.
|
|
74
|
-
4. Use the new name as the `displayName` in the rebuilt CSV.
|
|
42
|
+
## Step 3: One finding at a time
|
|
75
43
|
|
|
76
|
-
|
|
77
|
-
|
|
44
|
+
Take the findings in the order the script printed them. For each: say what it is, ask the
|
|
45
|
+
question, wait for the answer, and only then run the command. Never group two findings in one
|
|
46
|
+
question. A "não" leaves the point as it is: go on to the next one.
|
|
78
47
|
|
|
79
|
-
|
|
48
|
+
The script's output is for you. To the user, say each point in plain words: do not show the
|
|
49
|
+
codes between brackets, the `--aplicar` lines or the `CONSERTO:` status line.
|
|
80
50
|
|
|
81
|
-
|
|
51
|
+
| Finding | What you say and ask | Command after the yes |
|
|
52
|
+
|---|---|---|
|
|
53
|
+
| `nome-de-agente` | The agent has no two-word persona name. Propose one by the Agent Naming Convention of `_opencrew/core/prompts/design.prompt.md` (two words with the same initial, a different initial for each agent of the crew), keeping the first name the agent already has, and ask: "O agente {id} está sem nome de pessoa. Proponho {Nome Sobrenome}. Posso gravar?" | `--aplicar "nome:{id}={Nome Sobrenome}"`; the names reach the list of the crew with `manifesto`, below — when `manifesto` is not among the findings, run it right after this one |
|
|
54
|
+
| `manifesto` | "O arquivo de nomes da crew está incompleto; por isso aparece a função no lugar do nome. Posso refazer a partir dos arquivos dos agentes?" | `--aplicar "manifesto"` |
|
|
55
|
+
| `formato` | Read each listed step and propose one format per step, among the files of `_opencrew/core/best-practices/` (and `_opencrew/best-practices.local/`). A text to print, sign or file — ata, ofício, contrato, minuta, proposta, parecer — gets `documento-oficial`. Then: "Estes passos não dizem que tipo de texto produzem; sem isso, o verificador mede cada um como post de blog. Minha proposta: {passo → formato}. Posso gravar assim?" | one `--aplicar "formato:{passo}={formato}"` per step |
|
|
56
|
+
| `fontes` | "Esta crew não registra os arquivos do projeto que ela deve ler antes de escrever. Quais arquivos ou pastas ela precisa conhecer? (Pode responder 'nenhum'.)" Confirm that each one exists (search the project when only a name was given) and ask what the crew uses it for | one `--aplicar "fonte:{caminho}={para que}"` per file or folder, the path relative to the project root |
|
|
57
|
+
| `proibicao` | For each listed item: "Esta proibição não tem um trecho entre aspas, então o verificador não consegue barrar: «{item}». Qual trecho exato devo barrar? Se for uma regra de conteúdo, e não uma palavra ou expressão, responda 'revisão humana': ela fica para o revisor." The excerpt must be words of the item itself | `--aplicar "proibicao:{n}={trecho}"` or `--aplicar "proibicao:{n}=revisao-humana"` |
|
|
58
|
+
| `irreversivel` | For each listed step: "O passo {n} é feito por um agente que tem uma ferramenta de publicar ou enviar ({skill}). Este passo publica ou envia alguma coisa para fora do projeto? Se sim, marco o passo para que ele nunca seja repetido sozinho." | `--aplicar "irreversivel:{n}"` only for a yes |
|
|
59
|
+
| `sem-revisao` | "Esta crew não tem passo de revisão: nada é conferido antes de chegar a você. Isso se resolve editando a crew: /opencrew edit {nome}." | none |
|
|
60
|
+
| `sem-aprovacao-final` | "Depois da revisão não há um ponto de aprovação seu. Isso se resolve editando a crew: /opencrew edit {nome}." | none |
|
|
61
|
+
| `publica-antes` | "O passo {n} publica ou envia antes da revisão e da sua aprovação final. Enquanto estiver assim, o que sai não passou pela revisão. Isso se resolve editando a crew: /opencrew edit {nome}." | none |
|
|
62
|
+
| `passo-faltando` | Show the lines the script printed and say that it is solved by editing the crew: `/opencrew edit {nome}` | none |
|
|
82
63
|
|
|
64
|
+
The command is always the same line, with the item between double quotes:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
node _opencrew/core/scripts/conserto.mjs --crew "crews/{code}" --aplicar "{item}"
|
|
83
68
|
```
|
|
84
|
-
Crew "{name}" repaired.
|
|
85
69
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
| copywriter | Guilherme | ✍️ Guilherme Gancho | generated |
|
|
70
|
+
Several items of the same finding may go in one call (`--aplicar "…" --aplicar "…"`). The last
|
|
71
|
+
line must be `CONSERTO:APLICADO`. With `CONSERTO:ERRO` nothing was written: read the reason to the
|
|
72
|
+
user, correct the item and ask again — do not write the file yourself.
|
|
90
73
|
|
|
91
|
-
|
|
74
|
+
## Step 4: Project paths
|
|
92
75
|
|
|
93
|
-
|
|
76
|
+
After the findings, run the sources check:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
node _opencrew/core/scripts/conferir-fontes.mjs --crew "crews/{code}"
|
|
94
80
|
```
|
|
95
81
|
|
|
96
|
-
|
|
97
|
-
|
|
82
|
+
When it lists a path with a suggestion (`Sugestão: …` — an absolute path left in a step, or a
|
|
83
|
+
file that moved), show the user each path and its suggestion and ask: "Posso corrigir estes
|
|
84
|
+
caminhos nos arquivos da crew?" After a yes, run the same command ending with `--corrigir`: the
|
|
85
|
+
script rewrites only those paths and keeps a copy of each file it changes. A missing file with
|
|
86
|
+
no suggestion is the user's to solve: say which one.
|
|
87
|
+
|
|
88
|
+
## Step 5: Report
|
|
89
|
+
|
|
90
|
+
Run the diagnosis of Step 2 once more and close with what really happened:
|
|
98
91
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
needed."
|
|
92
|
+
"Pronto: {k} conserto(s) gravado(s). Cópias do que mudou: {lista de .bak}. Ficou pendente:
|
|
93
|
+
{lista ou 'nada'}." — `{k}` is the number of points the user said yes to and the script wrote.
|
|
102
94
|
|
|
103
|
-
|
|
95
|
+
Then: `Run it: /opencrew run {code}`.
|
|
104
96
|
|
|
105
97
|
## Rules
|
|
106
98
|
|
|
107
|
-
- **DO**
|
|
108
|
-
- **DO**
|
|
109
|
-
- **DO**
|
|
110
|
-
|
|
111
|
-
- **DO NOT**
|
|
112
|
-
|
|
113
|
-
- **DO NOT**
|
|
114
|
-
- **DO NOT** fabricate a summary — report only what you actually changed.
|
|
99
|
+
- **DO** run the diagnosis before and after; report only what the script printed.
|
|
100
|
+
- **DO** ask before every `--aplicar`, one finding at a time.
|
|
101
|
+
- **DO NOT** create, edit or delete any file under `crews/` with your own tools — not even to
|
|
102
|
+
"finish" a repair the script refused.
|
|
103
|
+
- **DO NOT** reorder, renumber, add or remove steps here: that is `/opencrew edit`.
|
|
104
|
+
- **DO NOT** touch `_opencrew/` or any other crew.
|
|
105
|
+
- **DO NOT** delete the `.bak` copies: they belong to the user.
|
|
@@ -114,7 +114,7 @@ Before starting execution:
|
|
|
114
114
|
briefing, the research or your own assumptions, the sources take precedence over them
|
|
115
115
|
(as fontes valem sobre o briefing e a pesquisa) — and say so when it matters.
|
|
116
116
|
|
|
117
|
-
2. Read `crews/{name}/pipeline/pipeline.yaml` for the pipeline definition
|
|
117
|
+
2. Read `crews/{name}/pipeline/pipeline.yaml` for the pipeline definition. The format of the crew files — where each field lives and the older shapes that still count — is in `_opencrew/core/formato-da-crew.md`; read it when a field is not where you expect.
|
|
118
118
|
3. **Resolve skills**: Read `crew.yaml` → `skills` section. For each non-native skill (anything other than web_search, web_fetch):
|
|
119
119
|
a. Verify `skills/{skill}/SKILL.md` exists
|
|
120
120
|
- If missing → ask user: "Skill '{skill}' is not installed. Install now? (y/n)"
|
|
@@ -124,13 +124,9 @@ Before starting execution:
|
|
|
124
124
|
c. If type: mcp, verify MCP is configured in `.claude/settings.local.json`
|
|
125
125
|
- If missing → **ERROR**: "Skill '{skill}' MCP not configured. Reinstall the skill."
|
|
126
126
|
All skills must resolve successfully before the pipeline starts (fail fast).
|
|
127
|
-
4. **Model tiers**:
|
|
128
|
-
- Read `crew.
|
|
129
|
-
|
|
130
|
-
- `standard`: mixed — research/data steps use `fast`, creative/review steps use `powerful`
|
|
131
|
-
- `full`: all steps use `model_tier: powerful` by default
|
|
132
|
-
- If a step has its own `model_tier` in frontmatter → step-level override takes priority over crew-level default.
|
|
133
|
-
- If neither crew tier nor step model_tier is set → default to `powerful` at dispatch.
|
|
127
|
+
4. **Model tiers**: a `subagent` step declares its own `model_tier` (`fast` or `powerful`), set at crew creation by the crew's tier; inline steps carry none.
|
|
128
|
+
- Read the crew's tier for the run header: `crew.tier` in `crew.yaml` (older crews: `tier` loose at the top level).
|
|
129
|
+
- A subagent step with no `model_tier` → `powerful` at dispatch.
|
|
134
130
|
|
|
135
131
|
4b. **Pre-Execution Agent Selection** — Decide which agents actually run for this task.
|
|
136
132
|
Run this step ONLY if `crew.yaml` declares an `agent_dependencies:` field (even an
|
|
@@ -563,7 +559,7 @@ root the one-line command of each moment and read the last line (`CAMINHO:OK {pa
|
|
|
563
559
|
Atualizo o perfil da empresa?" — change `company.md` only after a yes.
|
|
564
560
|
- **If the step frontmatter contains `outputFile`**: after collecting the user's full response,
|
|
565
561
|
insert only the run_id in the `outputFile` path (item 1 of the rule in Output Path Transformation — no version folder, no `saida` command), then write the response to that path using the Write tool (it creates the folder) before moving to the next step. Checkpoint files are user input captures, not versioned output: they live in the group itself, where `entrada` finds them.
|
|
566
|
-
|
|
562
|
+
For the checkpoint that precedes the researcher, use this format:
|
|
567
563
|
```
|
|
568
564
|
# Research Focus
|
|
569
565
|
|
|
@@ -571,7 +567,8 @@ root the one-line command of each moment and read the last line (`CAMINHO:OK {pa
|
|
|
571
567
|
**Time Range:** {selected time range label, e.g., "Últimos 7 dias"}
|
|
572
568
|
**Date:** {today's date in YYYY-MM-DD format}
|
|
573
569
|
```
|
|
574
|
-
|
|
570
|
+
For any other checkpoint: `# {the checkpoint's title}`, the user's answer as given (the option chosen and every comment), and `**Date:** {today, YYYY-MM-DD}`.
|
|
571
|
+
This file is the `inputFile` of the step that follows.
|
|
575
572
|
|
|
576
573
|
### Post-Step Output Validation
|
|
577
574
|
|
|
@@ -681,8 +678,8 @@ When a step has `on_reject: {step-id}` (a review step):
|
|
|
681
678
|
(real data only the user has): do NOT reject for them — the reviewer judges the rest, and the
|
|
682
679
|
final approval below collects the missing data from the user.
|
|
683
680
|
3. Track the review cycle count: a **cycle** is one pass of the reviewer. The maximum is
|
|
684
|
-
`max_review_cycles`, an integer from 1 declared where the step declares `on_reject` (the
|
|
685
|
-
frontmatter or its `pipeline.yaml` entry); absent or invalid: 3. On every rejection, with or
|
|
681
|
+
`max_review_cycles`, an integer from 1: the one declared where the step declares `on_reject` (the
|
|
682
|
+
step frontmatter or its `pipeline.yaml` entry); without it, the one in `crew.yaml`; absent or invalid in both: 3. On every rejection, with or
|
|
686
683
|
without a block, send the reviewer's feedback to the writer and go back to the referenced step.
|
|
687
684
|
4. If the last allowed pass also rejects, stop; the status of the last report picks the message, as
|
|
688
685
|
in item 2 — `VERIFICACAO:BLOQUEADA`: the blocks; any other status: the reviewer's feedback, also
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
// O diagnóstico do conserto: o que falta numa crew para as melhorias do runtime valerem nela.
|
|
2
|
+
// Cada achado tem um código e as linhas, em PT-BR fixo, que o usuário lê. Só leitura.
|
|
3
|
+
// Spec: fase-u4a-conserto-de-crews.md, §4 e regras 5, 6 e 9 (repositório do OpenCrew).
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { lerFrontmatter, semBom } from '../verificar/leitura.mjs';
|
|
6
|
+
import { itensDeProibicao } from '../verificar/proibicoes.mjs';
|
|
7
|
+
import { idDoAgente, lerBruto, listaDe } from './crew.mjs';
|
|
8
|
+
import { lerCsv } from './edicoes.mjs';
|
|
9
|
+
|
|
10
|
+
const EXPORTACAO = new Set(['pdf', 'csv', 'formatted-post']);
|
|
11
|
+
const plural = (n, um, varios) => (n === 1 ? um : varios);
|
|
12
|
+
const editar = (crew) => `Resolve-se editando a crew: /opencrew edit ${crew.nome}`;
|
|
13
|
+
const irreversivel = (passo) => passo.dados.side_effects === 'irreversible';
|
|
14
|
+
const revisoes = (crew) => crew.passos.filter((p) => p.revisao);
|
|
15
|
+
|
|
16
|
+
function manifesto(crew) {
|
|
17
|
+
if (!crew.agentes.length) return null;
|
|
18
|
+
const { colunas, linhas } = lerCsv(crew.csv);
|
|
19
|
+
const semNome = (l) => !l.displayName || l.displayName.toLowerCase() === (l.title ?? '').toLowerCase();
|
|
20
|
+
if (crew.csv !== null && colunas.includes('displayName') && !linhas.some(semNome)) return null;
|
|
21
|
+
return ['O arquivo de nomes da crew (crew-party.csv) está incompleto: aparece a função no lugar do nome.', 'Para consertar: --aplicar "manifesto"'];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function nomeDeAgente(crew) {
|
|
25
|
+
const semNome = crew.agentes.filter((a) => String(a.dados.name ?? '').trim().split(/\s+/).filter(Boolean).length < 2);
|
|
26
|
+
if (!semNome.length) return null;
|
|
27
|
+
const n = semNome.length;
|
|
28
|
+
return [
|
|
29
|
+
`${n} ${plural(n, 'agente', 'agentes')} sem nome de duas palavras.`,
|
|
30
|
+
...semNome.map((a) => `${a.id} (name: "${a.dados.name ?? ''}")`),
|
|
31
|
+
'Para consertar: --aplicar "nome:<agente>=<Nome Sobrenome>" e depois --aplicar "manifesto"',
|
|
32
|
+
];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Os passos que o verificador mede: do passo de `on_reject` até o anterior à revisão (regra 6). */
|
|
36
|
+
function medidos(crew) {
|
|
37
|
+
const dentro = new Set();
|
|
38
|
+
for (const revisao of revisoes(crew)) {
|
|
39
|
+
const de = crew.passos.findIndex((p) => p.numero === revisao.volta);
|
|
40
|
+
const ate = crew.passos.indexOf(revisao);
|
|
41
|
+
if (de >= 0) crew.passos.slice(de, ate).forEach((p) => dentro.add(p));
|
|
42
|
+
}
|
|
43
|
+
return crew.passos.filter((p) => dentro.has(p) && p.arquivo && !p.checkpoint && !p.revisao);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const semFormato = (passo) => !passo.dados.format || EXPORTACAO.has(String(passo.dados.format));
|
|
47
|
+
const saidaDe = (passo) => path.posix.basename(String(passo.dados.outputFile ?? passo.citado).replace(/\\/g, '/'));
|
|
48
|
+
|
|
49
|
+
function formato(crew) {
|
|
50
|
+
const passos = medidos(crew).filter(semFormato);
|
|
51
|
+
if (!passos.length) return null;
|
|
52
|
+
const n = passos.length;
|
|
53
|
+
return [
|
|
54
|
+
`${n} ${plural(n, 'passo que a revisão confere não diz', 'passos que a revisão confere não dizem')} o formato do texto.`,
|
|
55
|
+
`Sem o formato, o verificador mede ${plural(n, 'esse texto', 'cada um')} como post de blog.`,
|
|
56
|
+
`Passos: ${passos.map((p) => `${p.numero} (${saidaDe(p)})`).join(', ')}`,
|
|
57
|
+
'Para consertar: --aplicar "formato:<passo>=<formato>"',
|
|
58
|
+
];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function fontes(crew) {
|
|
62
|
+
const linhas = semBom(crew.yaml ?? '').split(/\r?\n/);
|
|
63
|
+
const inicio = linhas.findIndex((l) => /^fontes\s*:/.test(l));
|
|
64
|
+
const fim = linhas.findIndex((l, i) => i > inicio && /^[^\s#-]/.test(l));
|
|
65
|
+
const daLista = inicio < 0 ? [] : linhas.slice(inicio + 1, fim < 0 ? linhas.length : fim);
|
|
66
|
+
if (daLista.some((l) => /^\s*(?:-\s*)?caminho\s*:\s*\S/.test(l))) return null;
|
|
67
|
+
return [
|
|
68
|
+
'A crew não registra os arquivos do projeto que ela precisa ler.',
|
|
69
|
+
'Sem isso, ela escreve sem conhecer o que o projeto já decidiu.',
|
|
70
|
+
'Para consertar: --aplicar "fonte:<caminho>=<para que>" (um por arquivo ou pasta)',
|
|
71
|
+
];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function proibicao(crew) {
|
|
75
|
+
const pendentes = itensDeProibicao(semBom(crew.memoria ?? '')).filter((i) => i.pendente);
|
|
76
|
+
if (!pendentes.length) return null;
|
|
77
|
+
const n = pendentes.length;
|
|
78
|
+
return [
|
|
79
|
+
`${n} ${plural(n, 'proibição', 'proibições')} sem trecho entre aspas: o verificador não consegue barrar.`,
|
|
80
|
+
...pendentes.map((i) => `${i.n}. ${i.texto}`),
|
|
81
|
+
'Para consertar: --aplicar "proibicao:<n>=<trecho>" ou --aplicar "proibicao:<n>=revisao-humana"',
|
|
82
|
+
];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** A skill instalada no projeto declara `side_effects: irreversible`? (regra 9) */
|
|
86
|
+
function publica(raiz, skill) {
|
|
87
|
+
const texto = lerBruto(path.join(raiz, 'skills', skill, 'SKILL.md'));
|
|
88
|
+
return texto !== null && lerFrontmatter(semBom(texto))?.side_effects === 'irreversible';
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function semMarca(crew) {
|
|
92
|
+
const doPasso = (passo) => {
|
|
93
|
+
const agente = crew.agentes.find((a) => a.id === idDoAgente(passo));
|
|
94
|
+
const skills = [...listaDe(agente?.bruto, 'skills'), ...listaDe(passo.bruto, 'skills_needed')];
|
|
95
|
+
const skill = skills.find((s) => /^[A-Za-z0-9._-]+$/.test(s) && publica(crew.raiz, s));
|
|
96
|
+
return skill ? `Passo ${passo.numero} — agente ${agente?.id ?? idDoAgente(passo)}, skill ${skill}` : null;
|
|
97
|
+
};
|
|
98
|
+
const linhas = crew.passos.filter((p) => p.arquivo && !p.checkpoint && !irreversivel(p)).map(doPasso).filter(Boolean);
|
|
99
|
+
if (!linhas.length) return null;
|
|
100
|
+
const n = linhas.length;
|
|
101
|
+
return [
|
|
102
|
+
`${n} ${plural(n, 'passo', 'passos')} de agente que tem ferramenta de publicar ou enviar, sem a marca de passo irreversível.`,
|
|
103
|
+
...linhas,
|
|
104
|
+
'Se o passo publica ou envia: --aplicar "irreversivel:<passo>"',
|
|
105
|
+
];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function semRevisao(crew) {
|
|
109
|
+
if (revisoes(crew).length || !crew.passos.length) return null;
|
|
110
|
+
return ['A crew não tem passo de revisão: nada é conferido antes de chegar a você.', editar(crew)];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Posição da última revisão e do primeiro checkpoint depois dela (-1 quando não há). */
|
|
114
|
+
function fecho(crew) {
|
|
115
|
+
const revisao = crew.passos.indexOf(revisoes(crew).at(-1));
|
|
116
|
+
const aprovacao = crew.passos.findIndex((p, i) => i > revisao && p.checkpoint);
|
|
117
|
+
return { revisao, aprovacao };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function semAprovacaoFinal(crew) {
|
|
121
|
+
const { revisao, aprovacao } = fecho(crew);
|
|
122
|
+
if (revisao < 0 || aprovacao >= 0) return null;
|
|
123
|
+
return ['Depois da revisão não há um ponto de aprovação seu.', editar(crew)];
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function publicaAntes(crew) {
|
|
127
|
+
const { revisao, aprovacao } = fecho(crew);
|
|
128
|
+
if (revisao < 0) return null;
|
|
129
|
+
const limite = aprovacao >= 0 ? aprovacao : revisao;
|
|
130
|
+
const cedo = crew.passos.filter((p, i) => i < limite && irreversivel(p)).map((p) => p.numero);
|
|
131
|
+
if (!cedo.length) return null;
|
|
132
|
+
const quem = cedo.length === 1 ? `O passo ${cedo[0]} publica ou envia` : `Os passos ${cedo.join(', ')} publicam ou enviam`;
|
|
133
|
+
return [`${quem} antes da revisão e da sua aprovação final.`, 'Enquanto estiver assim, o que sai não passou pela revisão.', editar(crew)];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function passoFaltando(crew) {
|
|
137
|
+
const semArquivo = crew.passos.filter((p) => !p.arquivo).map((p) => `O passo ${p.numero} cita ${p.citado || 'um arquivo sem nome'}, que não existe.`);
|
|
138
|
+
const existe = (numero) => crew.passos.some((p) => p.numero === numero);
|
|
139
|
+
const semAlvo = revisoes(crew).filter((p) => !existe(p.volta)).map((p) => `O passo ${p.numero} manda voltar ao passo ${p.volta ?? p.dados.on_reject}, que não existe.`);
|
|
140
|
+
const linhas = [...semArquivo, ...semAlvo];
|
|
141
|
+
return linhas.length ? ['A sequência de passos cita o que não existe.', ...linhas, editar(crew)] : null;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// A ordem em que os achados aparecem (§4 da spec).
|
|
145
|
+
const CONFERENCIAS = [
|
|
146
|
+
['nome-de-agente', nomeDeAgente], ['manifesto', manifesto], ['formato', formato], ['fontes', fontes],
|
|
147
|
+
['proibicao', proibicao], ['irreversivel', semMarca], ['sem-revisao', semRevisao],
|
|
148
|
+
['sem-aprovacao-final', semAprovacaoFinal], ['publica-antes', publicaAntes], ['passo-faltando', passoFaltando],
|
|
149
|
+
];
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Os achados de uma crew, na ordem da spec.
|
|
153
|
+
* @param {object} crew o que `lerCrew` devolveu
|
|
154
|
+
* @returns {Array<{ codigo: string, linhas: string[] }>} a primeira linha é o título do achado
|
|
155
|
+
*/
|
|
156
|
+
export function diagnosticar(crew) {
|
|
157
|
+
return CONFERENCIAS.map(([codigo, conferir]) => ({ codigo, linhas: conferir(crew) })).filter((a) => a.linhas);
|
|
158
|
+
}
|