@aksp/opencrew 1.6.3 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/README.md +50 -5
  3. package/package.json +1 -1
  4. package/templates/AGENTS.md +20 -6
  5. package/templates/_opencrew/.opencrew-version +1 -1
  6. package/templates/_opencrew/core/architect.agent.yaml +1 -1
  7. package/templates/_opencrew/core/escritorio/animacao.js +64 -0
  8. package/templates/_opencrew/core/escritorio/app.js +137 -0
  9. package/templates/_opencrew/core/escritorio/cena.js +132 -0
  10. package/templates/_opencrew/core/escritorio/demo.js +79 -0
  11. package/templates/_opencrew/core/escritorio/escala.js +27 -0
  12. package/templates/_opencrew/core/escritorio/index.html +166 -0
  13. package/templates/_opencrew/core/escritorio/modelo-agentes.js +93 -0
  14. package/templates/_opencrew/core/escritorio/modelo-estado.js +71 -0
  15. package/templates/_opencrew/core/escritorio/modelo-mesas.js +81 -0
  16. package/templates/_opencrew/core/escritorio/modelo-pagina.js +95 -0
  17. package/templates/_opencrew/core/escritorio/modelo-textos.js +65 -0
  18. package/templates/_opencrew/core/escritorio/modelo-visao.js +91 -0
  19. package/templates/_opencrew/core/escritorio/modelo.js +29 -0
  20. package/templates/_opencrew/core/escritorio/painel.js +120 -0
  21. package/templates/_opencrew/core/escritorio/quadro.js +106 -0
  22. package/templates/_opencrew/core/escritorio/rota.js +62 -0
  23. package/templates/_opencrew/core/escritorio/rotulos.js +78 -0
  24. package/templates/_opencrew/core/escritorio/sprites-mesa.js +122 -0
  25. package/templates/_opencrew/core/escritorio/sprites-sala.js +92 -0
  26. package/templates/_opencrew/core/escritorio/sprites.js +187 -0
  27. package/templates/_opencrew/core/prompts/build.prompt.md +3 -3
  28. package/templates/_opencrew/core/prompts/discovery.prompt.md +1 -1
  29. package/templates/_opencrew/core/prompts/repair.prompt.md +7 -12
  30. package/templates/_opencrew/core/runner.pipeline.md +124 -223
  31. package/templates/_opencrew/core/scripts/caminho/argumentos.mjs +49 -0
  32. package/templates/_opencrew/core/scripts/caminho/disco.mjs +36 -0
  33. package/templates/_opencrew/core/scripts/caminho/nucleo.mjs +61 -0
  34. package/templates/_opencrew/core/scripts/caminho.mjs +124 -0
  35. package/templates/_opencrew/core/scripts/escritorio/leitura.mjs +31 -0
  36. package/templates/_opencrew/core/scripts/escritorio/porta.mjs +98 -0
  37. package/templates/_opencrew/core/scripts/escritorio/projeto.mjs +29 -0
  38. package/templates/_opencrew/core/scripts/escritorio/servidor.mjs +78 -0
  39. package/templates/_opencrew/core/scripts/escritorio.mjs +117 -0
  40. package/templates/_opencrew/core/scripts/estado/argumentos.mjs +61 -0
  41. package/templates/_opencrew/core/scripts/estado/arquivo.mjs +53 -0
  42. package/templates/_opencrew/core/scripts/estado/decisao.mjs +56 -0
  43. package/templates/_opencrew/core/scripts/estado/elenco.mjs +58 -0
  44. package/templates/_opencrew/core/scripts/estado/nucleo.mjs +113 -0
  45. package/templates/_opencrew/core/scripts/estado/preferencia.mjs +24 -0
  46. package/templates/_opencrew/core/scripts/estado.mjs +96 -0
@@ -33,18 +33,7 @@ Before starting execution:
33
33
  - Crew memory from `crews/{name}/_memory/memories.md`
34
34
  - User preferences from `_opencrew/_memory/preferences.md`
35
35
 
36
- 1a. **Check the Dashboard toggle** — the visual dashboard (`state.json` writes) is an
37
- optional, opt-in feature that most installs never use (it requires running the
38
- separate dashboard app from source — see README). Scan the already-loaded
39
- `preferences.md` for a `Dashboard:` field:
40
- - If its value is `enabled` (as written by onboarding: `- **Dashboard:** enabled`, or the
41
- plain form `Dashboard: enabled`) → set `dashboard_enabled = true` for this run.
42
- - Otherwise (`disabled`, missing, or preferences.md not configured yet) →
43
- set `dashboard_enabled = false`. This is the default.
44
- Store `dashboard_enabled` in working memory for the rest of this run. Every
45
- `state.json` read/write instruction in this document is conditional on it —
46
- when `false`, skip ALL of them; never create, update, or delete
47
- `crews/{name}/state.json`.
36
+ 1a. **Escritório toggle** — the optional live view is off unless `preferences.md` turns it on (see "Escritório" below).
48
37
 
49
38
  > **Note on language**: The structural labels listed below are **fixed PT-BR** and must
50
39
  > never be translated — opencrew's primary supported audience is PT-BR (see AGENTS.md →
@@ -64,12 +53,9 @@ Before starting execution:
64
53
  > unless the user base expands beyond PT-BR — at that point, discuss a migration strategy
65
54
  > (e.g. i18n key mapping) rather than mixing languages in a single file.
66
55
 
67
- 1b. **Memory format migration** — After loading `memories.md`, check whether it uses the new format by scanning for the `## Estilo de Escrita` section header:
68
- ```bash
69
- [ -f "crews/{name}/_memory/memories.md" ] && grep -q "## Estilo de Escrita" "crews/{name}/_memory/memories.md" && echo "NEW_FORMAT" || echo "OLD_FORMAT"
70
- ```
71
- - If `NEW_FORMAT` → proceed normally.
72
- - If `OLD_FORMAT` (or file is empty / does not exist) → migrate before proceeding:
56
+ 1b. **Memory format migration** — After loading `memories.md`, check whether it uses the new format: it does when it has the `## Estilo de Escrita` section header (read the file with the read tool — no command).
57
+ - If it has the header → proceed normally.
58
+ - If it does not (or the file is empty / does not exist) → migrate before proceeding:
73
59
  a0. If the file exists and is not empty, FIRST copy it to `crews/{name}/_memory/memories.md.bak`
74
60
  (never lose what the crew learned), then tell the user in one line:
75
61
  "Atualizei o formato da memória da crew; a versão anterior está em `memories.md.bak`."
@@ -89,11 +75,8 @@ Before starting execution:
89
75
  ## Técnico (específico do crew)
90
76
  ```
91
77
  (Use the crew's display name for `{crew-name}`, and the crew code for `{name}` in file paths — they refer to the same crew.)
92
- b. Check if `crews/{name}/_memory/runs.md` exists:
93
- ```bash
94
- test -f "crews/{name}/_memory/runs.md" && echo "EXISTS" || echo "MISSING"
95
- ```
96
- If `MISSING`, create it with:
78
+ b. Check if `crews/{name}/_memory/runs.md` exists (read tool — no command).
79
+ If it does not exist, create it with:
97
80
  ```markdown
98
81
  # Run History: {crew-name}
99
82
 
@@ -240,45 +223,47 @@ Before starting execution:
240
223
  identical to today: all agents listed, no Skipped line.
241
224
  5b. **Initialize run folder**: Generate a unique run ID for this execution:
242
225
  - Format: `YYYY-MM-DD-HHmmss` using the current timestamp (e.g. `2026-03-03-143022`)
243
- - Check if `crews/{name}/output/{run_id}/` already exists
226
+ - Check (folder-listing tool, no command) if `crews/{name}/output/{run_id}/` already exists
244
227
  - If it does (sub-second collision), append `-2`, `-3`, etc. until the folder does not exist
245
- - Create the folder using Bash: `mkdir -p "crews/{name}/output/{run_id}"`
228
+ - Create the folder: run the `pasta` command (see "Output Path Transformation" below) — never create a folder by command yourself
246
229
  - Store `run_id` in working memory for this run — it will be used for ALL output paths
247
- 6. **Initialize state.json** (only if `dashboard_enabled` — see step 1a; otherwise skip this entire step, including all sub-steps below):
248
- - **IMPORTANT**: When enabled, write to `crews/{name}/state.json` before every step and after every handoff, as described throughout this document. When `dashboard_enabled` is false, never create, write, or delete this file.
249
- - Create `state.json` from scratch:
250
- a. Read `crews/{name}/crew-party.csv` — for each agent row (skip header), extract:
251
- - `id`: take the `path` column, strip `./agents/` prefix and `.agent.md` suffix
252
- (e.g. `./agents/researcher.agent.md` → `researcher`)
253
- - `name`: use the `displayName` column
254
- - `icon`: use the `icon` column
255
- b. Assign desk positions by agent order (0-based index):
256
- - `col = (index % 3) + 1`
257
- - `row = floor(index / 3) + 1`
258
- (index 0 → col:1 row:1, index 1 → col:2 row:1, index 2 → col:3 row:1, index 3 → col:1 row:2, etc.)
259
- c. Read `crews/{name}/crew.yaml` — count items in `pipeline.steps` for `total`
260
- d. Write `crews/{name}/state.json` with the Write tool:
261
- ```json
262
- {
263
- "crew": "{crew code from crew.yaml}",
264
- "status": "idle",
265
- "step": { "current": 0, "total": {step count from c}, "label": "" },
266
- "agents": [
267
- {
268
- "id": "{agent id}",
269
- "name": "{agent displayName}",
270
- "icon": "{agent icon}",
271
- "status": "idle",
272
- "desk": { "col": {col from b}, "row": {row from b} }
273
- }
274
- ],
275
- "handoff": null,
276
- "startedAt": null,
277
- "updatedAt": "{ISO timestamp now}"
278
- }
279
- ```
280
- Include one entry per agent, in crew-party.csv order. For each agent, set
281
- `"status"` to `"skipped"` if it is in `skipped_agents`, otherwise `"idle"`.
230
+ 6. **Escritório** — if it is on, run `iniciar`, then one `pular` per deselected agent, one after the other (see "Escritório" below).
231
+
232
+ ## Escritório (optional live view)
233
+
234
+ A local page that shows the crew at work, off by default. Follow this section only when the
235
+ already-loaded `preferences.md` has `Dashboard: enabled` (written `- **Dashboard:** enabled` or
236
+ plain `Dashboard: enabled`, any letter case); otherwise run none of these commands. When it is on,
237
+ run via Bash, from the project root, the one-line command of each moment:
238
+
239
+ | Moment | Command |
240
+ |---|---|
241
+ | Start of the run (Initialization, step 6) | `node _opencrew/core/scripts/estado.mjs "{name}" iniciar --passos {N}` |
242
+ | Right after `iniciar`, once per deselected agent | `node _opencrew/core/scripts/estado.mjs "{name}" pular --agente {id}` |
243
+ | Before each step, each time it starts | `node _opencrew/core/scripts/estado.mjs "{name}" passo --n {K} --agente {id} --rotulo "{rótulo}" --mensagem "{frase}"` |
244
+ | Before asking the question of a checkpoint (instead of `passo`) | `node _opencrew/core/scripts/estado.mjs "{name}" checkpoint --n {K} --agente {id} --rotulo "{rótulo}"` |
245
+ | End of the run (After Pipeline Completion) | `node _opencrew/core/scripts/estado.mjs "{name}" concluir` |
246
+ | Run aborted after `iniciar`, by the user or by an error | `node _opencrew/core/scripts/estado.mjs "{name}" falhar --motivo "{motivo}"` |
247
+
248
+ - **One at a time** — Run these commands one at a time, waiting for the `ESTADO:` line of each
249
+ before the next — never in parallel or in the background (each one reads and rewrites the same file).
250
+ - **Values** — `{name}`: the crew code. `{N}`: how many steps will run, checkpoints included (a
251
+ deselected agent's steps do not count). `{K}`: the step's position among them, from 1. `{id}`: the agent's `id` column in
252
+ `crew-party.csv`; a step or checkpoint with no `agent:` goes without `--agente`
253
+ (the table shows the full form). `{rótulo}`: the step's name, in
254
+ a few words. `--mensagem` goes only when the agent changed since the last `passo` (so never on the first
255
+ one): one sentence on what the previous agent delivered — never look at the next step. `{motivo}`: why the run stopped.
256
+ - **Text on the command line** — `--rotulo`, `--mensagem` and `--motivo` go between double quotes,
257
+ on one line, starting with a letter or a digit, with only letters (accents included), digits,
258
+ spaces and `. , : ; - ( ) / ?`. Drop every other sign (quotes of any kind, `$`, backtick, `\`,
259
+ `%`, `!`, emoji). If no text is left, omit the option. Write them in the user's language.
260
+ - **After `iniciar`**, when it answers `ESTADO:OK`, show the user once:
261
+ `Escritório ligado. Se a página não estiver aberta, rode em outro terminal: node _opencrew/core/scripts/escritorio.mjs`
262
+ - **The Escritório never stops the run.** A command that fails, does not run or answers
263
+ `ESTADO:IGNORADO`: go on, do not repeat that event, ask nothing, and tell the user once per run,
264
+ in one line: `O escritório não foi atualizado nesta execução; o trabalho segue normalmente.` With
265
+ the reason "escritório desligado", say nothing and stop calling the script for the rest of this run.
266
+ - The script is the only writer: never read, write or describe `crews/{name}/state.json` yourself.
282
267
 
283
268
  ## Execution Rules
284
269
 
@@ -388,11 +373,9 @@ Before executing any step that references an agent:
388
373
  To prevent linear token growth across multi-agent pipelines, apply context compression
389
374
  when passing prior agents' outputs as context:
390
375
 
391
- 1. **TL;DR extraction**: After each agent completes, check if its output contains a `## TL;DR` section.
376
+ 1. **TL;DR extraction**: After each agent completes, check if its output contains a `## TL;DR` section
377
+ (a line starting with `## TL;DR` — you have the output, no command is needed).
392
378
  If present, extract and store it separately as the agent's summary.
393
- ```bash
394
- grep -q "^## TL;DR" "{outputFile}" && echo "HAS_TLDR" || echo "NO_TLDR"
395
- ```
396
379
 
397
380
  2. **Compressed context assembly**: When preparing context for Agent N:
398
381
  - Include **TL;DR summaries** from Agents 1 through N-2 (all agents except the direct predecessor)
@@ -450,7 +433,7 @@ When an agent's `.agent.md` frontmatter contains a `tasks:` field:
450
433
  e. Check task veto conditions (same enforcement as step veto conditions below)
451
434
 
452
435
  3. **Final output**: The output of the LAST task in the chain becomes the step's output
453
- - Apply the Output Path Transformation (Steps 1 and 2: run_id injection + version folder) to the `outputFile` path before saving — this applies regardless of whether the step runs as `execution: inline` or `execution: subagent`
436
+ - Resolve the `outputFile` path with the `saida` command (Output Path Transformation) before saving — this applies regardless of whether the step runs as `execution: inline` or `execution: subagent`
454
437
  - Save to the **transformed** outputFile path
455
438
  - This is what the next step (or checkpoint) receives
456
439
 
@@ -464,86 +447,63 @@ When an agent's `.agent.md` frontmatter contains a `tasks:` field:
464
447
 
465
448
  ### Output Path Transformation
466
449
 
467
- Before saving any output file in a step, apply these rules to determine the final path:
468
-
469
- #### Step 1 — Insert run_id
470
-
471
- - If the path starts with `crews/{name}/output/`, insert `{run_id}/` immediately after `output/`
472
- - Example: `crews/carousel/output/slides/draft.md` → `crews/carousel/output/2026-03-03-143022/slides/draft.md`
473
- - Example: `crews/carousel/output/angles-brief.yaml` → `crews/carousel/output/2026-03-03-143022/angles-brief.yaml`
474
- - If the path does NOT start with `crews/{name}/output/`, leave it unchanged
475
-
476
- #### Step 2 — Insert version folder
477
-
478
- Apply to every path that was transformed in Step 1:
479
-
480
- 1. Determine the **output group** = the parent directory of the file (after Step 1 transformation)
481
- - Example: `crews/carousel/output/2026-03-03-143022/slides/draft.md` → group is `crews/carousel/output/2026-03-03-143022/slides/`
482
- - Example: `crews/carousel/output/2026-03-03-143022/angles-brief.yaml` → group is `crews/carousel/output/2026-03-03-143022/`
483
-
484
- 2. Detect existing versions for this group using Bash:
485
- ```bash
486
- ls -1 "crews/{name}/output/{run_id}/{relative-group}/" 2>/dev/null | grep -E '^v[0-9]+$' | sort -V | tail -1
487
- ```
488
- - If the command returns a version (e.g. `v2`) → use `v3`
489
- (Always increment the highest version found, even if lower versions have gaps — e.g. if `v1` and `v3` exist, use `v4`)
490
- - If the command returns nothing (no versions yet) → use `v1`
491
- (`{relative-group}` is the portion of the group path after `crews/{name}/output/{run_id}/`, e.g. `slides/` or empty string for root-level files)
492
-
493
- 3. Insert the version folder immediately before the filename:
494
- - `crews/carousel/output/2026-03-03-143022/slides/draft.md` → `crews/carousel/output/2026-03-03-143022/slides/v1/draft.md`
495
- - `crews/carousel/output/2026-03-03-143022/angles-brief.yaml` → `crews/carousel/output/2026-03-03-143022/v1/angles-brief.yaml`
496
-
497
- 4. **Cache per group**: within a single step execution, once a version is determined for a group, reuse it for all subsequent files in that same group. Do not re-run the `ls` per file.
498
- If the same file path is written twice within a step, both writes go to the same versioned path (the second write overwrites the first within that version).
499
-
500
- Apply this transformation consistently for every write in this step.
450
+ The path of every file of the run comes from one script (`caminho.mjs`), the same on every system —
451
+ never from a path you put together, never from a shell command of your own. Run from the project
452
+ root the one-line command of each moment and read the last line (`CAMINHO:OK {path}`,
453
+ `CAMINHO:FALTA {path}` or `CAMINHO:REPROVADO {motivo}`):
454
+
455
+ | Moment | Command |
456
+ |---|---|
457
+ | Start of the run (Initialization, step 5b) | `node _opencrew/core/scripts/caminho.mjs "{name}" pasta --run "{run_id}"` |
458
+ | Before a step, for its `inputFile` | `node _opencrew/core/scripts/caminho.mjs "{name}" entrada --run "{run_id}" --arquivo "{inputFile}"` |
459
+ | Before a step writes, for the first `outputFile` of each group | `node _opencrew/core/scripts/caminho.mjs "{name}" saida --run "{run_id}" --arquivo "{outputFile}"` |
460
+ | After a step wrote, for each output file | `node _opencrew/core/scripts/caminho.mjs "{name}" conferir --arquivo "{path}"` |
461
+
462
+ - **Values** — `{name}`: the crew code. `{inputFile}` / `{outputFile}`: the path as the step
463
+ declares it (raw, without the run_id). `{path}`: the path `saida` returned. The safe-name rule
464
+ (nome seguro) applies: the crew and every path between double quotes.
465
+ - **`saida`** answers with the **transformed** path and creates its folder: write the file there,
466
+ never to the raw path. Run it once per group in a step — the other `outputFile`s of the same
467
+ group reuse the version folder it returned, and a file written twice in a step goes to the same path.
468
+ - **`entrada`** answers with the newest output of that file: use the path it returns, whatever
469
+ its version folder.
470
+ - **The rule the script applies** (apply it yourself only when the script does not run):
471
+ 1. A declared path that starts with `crews/{name}/output/` gets `{run_id}/` right after
472
+ `output/`; any other path stays as declared, with no version folder.
473
+ 2. The **group** is the folder of the file, run_id included (`…/output/{run_id}/`, or
474
+ `…/output/{run_id}/slides/`). A step writes to the group's next version folder: the highest
475
+ `vN` there plus 1, or `v1` when there is none — numeric order (`v10` comes after `v9`), gaps
476
+ not filled (`v1` and `v3` → `v4`).
477
+ 3. A step reads the newest version that has the file: from the highest `vN` down, the first
478
+ where the file exists and is not empty; then the group itself, with no version folder (where
479
+ checkpoint answers live).
480
+
481
+ Example, one group: the researcher writes `…/v1/pesquisa.md`, the writer writes `…/v2/post.md`
482
+ and reads `…/v1/pesquisa.md`. Never assume `v1`.
483
+ - **Script that does not run** (no Node, an error, or no `CAMINHO:` line): tell the user once per
484
+ run `Não consegui rodar a conferência de caminhos; sigo pela regra escrita e marco os arquivos como não verificados.`,
485
+ build the path by the rule above (the Write tool creates the folder) and continue. A file handled
486
+ this way skips its gate and is listed at the final approval:
487
+ `{arquivo} — não verificado: a conferência de caminhos não rodou`.
501
488
 
502
489
  ### For each pipeline step:
503
490
 
504
491
  0. **Agent deselection check** — Read the step's `agent:` frontmatter field.
505
492
  - If the step has an `agent:` value present AND it is in `skipped_agents` →
506
493
  announce `⏭️ Skipping {Agent Name} (deselected for this run)` and skip this
507
- step ENTIRELY: no dashboard update, no input validation, no execution, no output
508
- validation, no veto, no output file, no handoff. Advance to the next step in
494
+ step ENTIRELY: no Escritório command, no input validation, no execution, no output
495
+ validation, no veto, no output file. Advance to the next step in
509
496
  `filtered_steps`.
510
497
  - Checkpoints that declare `agent:` and whose agent was deselected are skipped the
511
498
  same way. Checkpoints with no `agent:` field always run (backward compatible).
512
499
  - When the selection step was skipped (no `agent_dependencies:`), `skipped_agents`
513
500
  is empty → this check never fires (legacy behavior).
514
501
 
515
- 0b. **Update dashboard** (only if `dashboard_enabled`; otherwise skip to step 1). Write `crews/{name}/state.json` using the Write tool. Use this content:
516
- ```json
517
- {
518
- "crew": "{crew code from crew.yaml}",
519
- "status": "running",
520
- "step": {
521
- "current": {1-based index of this step},
522
- "total": {total steps in pipeline},
523
- "label": "{step id or label}"
524
- },
525
- "agents": [
526
- {
527
- "id": "{agent id}",
528
- "name": "{agent displayName}",
529
- "icon": "{agent icon}",
530
- "status": "{working if this is the current step's agent, done if already completed, skipped if in skipped_agents, idle otherwise}",
531
- "desk": {preserve existing desk positions from state.json — do not change col/row}
532
- }
533
- ],
534
- "handoff": {preserve existing handoff object, or null if this is the first step},
535
- "startedAt": "{ISO timestamp — set on the first step only, then preserve from existing state.json on subsequent steps}",
536
- "updatedAt": "{ISO timestamp now}"
537
- }
538
- ```
502
+ 0b. **Escritório** — if it is on, run `passo`, or `checkpoint` when the step is a checkpoint (see "Escritório" above).
539
503
 
540
- 1. **Pre-Step Input Validation** — MANDATORY. If the step's frontmatter declares an `inputFile`, validate that the input exists before executing the step. Run via Bash tool:
541
- ```bash
542
- test -s "{transformed inputFile path}" && echo "VALIDATION:PASS" || echo "VALIDATION:FAIL"
543
- ```
544
- - Apply the Output Path Transformation (Step 1: run_id injection) to the `inputFile` path before running the check.
545
- - If the Bash output contains `VALIDATION:PASS` → proceed to execute the step.
546
- - If the Bash output contains `VALIDATION:FAIL` → do NOT execute the step. Present to user:
504
+ 1. **Pre-Step Input Validation** — MANDATORY. If the step's frontmatter declares an `inputFile`, the input comes from the `entrada` action, never from a path you build: validate that the input exists before executing the step. Run the `entrada` command (Output Path Transformation) with the `inputFile` as declared:
505
+ - `CAMINHO:OK {path}` → that path is the step's input (the newest version that has the file): read the input from it and execute the step.
506
+ - `CAMINHO:FALTA {path}` → do NOT execute the step. Present to user:
547
507
  ```
548
508
  ⚠️ Input for {Agent Name} not found: {path}
549
509
  The previous step may have failed to produce output.
@@ -562,7 +522,7 @@ Apply this transformation consistently for every write in this step.
562
522
  - Inform user: `🔍 {Agent Name} is working in the background...`
563
523
  - Read the step's `model_tier` frontmatter field (if present).
564
524
  Valid values: `fast` or `powerful`. If absent or any other value: default to `powerful`.
565
- - **Before building the subagent prompt**: Apply the Output Path Transformation (Step 1: run_id injection + Step 2: version folder) to all output paths referenced in the step file. Store the transformed path(s) in working memory — they will be used both in the prompt and in post-completion verification. Never pass raw paths from the step file to the subagent.
525
+ - **Before building the subagent prompt**: Resolve all output paths referenced in the step file with the `saida` command (Output Path Transformation, once per group). Store the transformed path(s) in working memory — they will be used both in the prompt and in post-completion verification. Never pass raw paths from the step file to the subagent.
566
526
  - Use the Task tool to dispatch the step as a subagent:
567
527
  - If `model_tier: fast`: use the fastest/lightest model available in your current IDE.
568
528
  - If `model_tier: powerful` or absent/invalid: use the default model (no model override needed)
@@ -574,7 +534,7 @@ Apply this transformation consistently for every write in this step.
574
534
  - The veto conditions from the step file (agent should self-check before completing)
575
535
  - The company context
576
536
  - The crew memory
577
- - The **transformed** path to save output (e.g., `crews/{name}/output/2026-03-20-140736/slides/v1/draft.md`)
537
+ - The **transformed** path to save output (the one `saida` returned, e.g. `crews/{name}/output/2026-03-20-140736/slides/v2/draft.md`)
578
538
  - Wait for the subagent to complete
579
539
  - Inform user: `✓ {Agent Name} completed`
580
540
  - Proceed to Post-Step Output Validation (below) before advancing.
@@ -584,13 +544,13 @@ Apply this transformation consistently for every write in this step.
584
544
  - Announce: `{icon} {Agent Name} is working...`
585
545
  - Follow the step instructions
586
546
  - Present output directly in the conversation
587
- - Save output to the specified output file — apply the Output Path Transformation (Steps 1 and 2) to the path before writing. Do not write to the raw path from the step file.
547
+ - Save output to the specified output file — resolve the path with the `saida` command (Output Path Transformation) before writing. Do not write to the raw path from the step file.
588
548
  - Proceed to Post-Step Output Validation (below) before advancing.
589
549
 
590
550
  #### If `type: checkpoint`
591
551
  - Present the checkpoint message to the user
592
552
  - If the checkpoint requires a choice (numbered list), present options as a numbered list
593
- - **Always include the file path** of any generated content the user needs to review. Example: "Review the content at `crews/{name}/output/{run_id}/v1/content.md` and let me know if it looks good."
553
+ - **Always include the file path** of any generated content the user needs to review. Example: "Review the content at `crews/{name}/output/{run_id}/v2/content.md` and let me know if it looks good." (the path the script returned)
594
554
  - Wait for user input before proceeding
595
555
  - Save the user's choice/response for the next step
596
556
  - **Correction → memory, right away**: if the answer corrects something (tone, audience, a term,
@@ -603,7 +563,7 @@ Apply this transformation consistently for every write in this step.
603
563
  (e.g. the organization's name, the main audience), ask: "Isso vale para todas as crews?
604
564
  Atualizo o perfil da empresa?" — change `company.md` only after a yes.
605
565
  - **If the step frontmatter contains `outputFile`**: after collecting the user's full response,
606
- apply the Output Path Transformation **Step 1 only** (run_id injection — skip Step 2, version folder) to the `outputFile` path, then write the response to the transformed path using the Write tool before moving to the next step. Checkpoint files are user input captures, not versioned output — Step 2 does not apply here, regardless of the general "every write" rule in the Output Path Transformation section above.
566
+ 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.
607
567
  Use this format:
608
568
  ```
609
569
  # Research Focus
@@ -616,28 +576,22 @@ Apply this transformation consistently for every write in this step.
616
576
 
617
577
  ### Post-Step Output Validation
618
578
 
619
- After a step produces output (subagent or inline) and BEFORE Veto Condition Enforcement, the runner MUST validate that the declared output files exist and are non-empty. This is a binary, non-negotiable gate — the runner does NOT proceed on memory or assumption, only on bash output.
620
-
621
- **If the step declares an `outputFile`** (single or multiple), run via Bash tool for EACH output file:
579
+ After a step produces output (subagent or inline) and BEFORE Veto Condition Enforcement, the runner MUST validate that the declared output files exist and are non-empty. This is a binary, non-negotiable gate — the runner does NOT proceed on memory or assumption, only on the script's `CAMINHO:` line.
622
580
 
623
- ```bash
624
- test -s "{transformed outputFile path}" && echo "VALIDATION:PASS" || echo "VALIDATION:FAIL"
625
- ```
581
+ **If the step declares an `outputFile`** (single or multiple), run the `conferir` command (Output Path Transformation) for EACH output file, with the **stored transformed path** (the one `saida` returned), not the raw path from the step file. A step with an `output_contract:` adds its options to this same call (see Output Contract Validation): one command per file.
626
582
 
627
- Use the **stored transformed path** (after Output Path Transformation Steps 1 and 2), not the raw path from the step file.
628
-
629
- **Rules:**
630
- - If ALL output files return `VALIDATION:PASS` → proceed to Veto Condition Enforcement.
583
+ **Rules** (`FAIL` below = the last line is `CAMINHO:REPROVADO arquivo ausente ou vazio`):
584
+ - If ALL output files return `CAMINHO:OK` → proceed to Veto Condition Enforcement.
631
585
  - **Irreversible step** (`side_effects: irreversible` — publish, post, send) with ANY
632
- `VALIDATION:FAIL` → NEVER re-execute it. Tell the user: "⚠️ {Agent Name} did not save its
586
+ `FAIL` → NEVER re-execute it. Tell the user: "⚠️ {Agent Name} did not save its
633
587
  output, but the action may already have happened (post published / email sent). Check
634
588
  before retrying." Then offer: 1. Retry step (only after the user checked) · 2. Mark as done
635
589
  and continue · 3. Abort pipeline.
636
- - If ANY output file returns `VALIDATION:FAIL` (any other step):
590
+ - If ANY output file returns `FAIL` (any other step):
637
591
  1. **Retry once**: re-execute the entire step with the same input and context.
638
592
  2. After re-execution, run the validation again for all output files.
639
- 3. If second attempt returns `VALIDATION:PASS` for all files → proceed normally.
640
- 4. If second attempt still has ANY `VALIDATION:FAIL` → present to user:
593
+ 3. If second attempt returns `CAMINHO:OK` for all files → proceed normally.
594
+ 4. If second attempt still has ANY `FAIL` → present to user:
641
595
  ```
642
596
  ⚠️ {Agent Name}'s output was not generated: {path}
643
597
 
@@ -649,26 +603,23 @@ Use the **stored transformed path** (after Output Path Transformation Steps 1 an
649
603
  - If the step does not declare an `outputFile` (e.g., steps that only produce inline console output) → skip output validation.
650
604
  - Checkpoint steps (`type: checkpoint`) are exempt — their output is the user's response, not a file.
651
605
 
652
- **IMPORTANT**: Do NOT rely on reading the file with the Read tool to "verify" output. The Read tool returns content that can be misinterpreted. Use ONLY the bash `test -s` command — its output is binary and cannot be hallucinated.
606
+ **IMPORTANT**: Do NOT rely on reading the file with the Read tool to "verify" output. The Read tool returns content that can be misinterpreted. Use ONLY the `conferir` command — its last line is binary and cannot be hallucinated.
653
607
 
654
608
  ### Output Contract Validation
655
609
 
656
610
  If the step's frontmatter declares an `output_contract:` field, apply structured validation
657
- AFTER the basic file existence check passes:
611
+ in the same call as the basic file existence check (Post-Step Output Validation):
658
612
 
659
- 1. **Required sections check**: If `output_contract.required_sections` is defined,
660
- verify each required section exists in the output file:
661
- ```bash
662
- grep -c "^## " "{transformed outputFile path}" | xargs -I {} test {} -ge {min_sections} && echo "SECTIONS:PASS" || echo "SECTIONS:FAIL"
663
- ```
613
+ 1. **Required sections check**: If `output_contract.required_sections` is defined, add
614
+ `--secoes {min_sections}` to the same `conferir` command: the file needs at least that many
615
+ lines starting with `## `.
664
616
 
665
- 2. **TL;DR check**: If the output contract requires a TL;DR section:
666
- ```bash
667
- grep -q "^## TL;DR" "{transformed outputFile path}" && echo "TLDR:PASS" || echo "TLDR:FAIL"
668
- ```
617
+ 2. **TL;DR check**: If the output contract requires a TL;DR section, add `--tldr` to the same
618
+ `conferir` command.
669
619
 
670
- 3. **If any check fails**:
671
- - Present to user: "⚠️ Output from {Agent Name} is incomplete: {which checks failed}"
620
+ 3. **If a check fails** (the last line is `CAMINHO:REPROVADO {motivo}`, with a motivo other than
621
+ `arquivo ausente ou vazio`; the script reports the first one):
622
+ - Present to user: "⚠️ Output from {Agent Name} is incomplete: {motivo}"
672
623
  - Options as numbered list:
673
624
  1. Accept anyway and continue
674
625
  2. Retry step (re-execute the agent)
@@ -752,85 +703,34 @@ When a step has `on_reject: {step-id}` (a review step):
752
703
  lines under each file, not the "não é texto" line of **Notas**), one per line as
753
704
  `{arquivo} — {motivo}`, then the lines under `**Notas:**` in that report, as they are written,
754
705
  and repeat every "não rodou" warning of this run (checker and source check) and the line of
755
- every file left unchecked by the safe-name rule. If the approved
706
+ every file left unchecked by the safe-name rule. List the same way every file the path script
707
+ did not check (see Output Path Transformation). If the approved
756
708
  text still contains `[PREENCHER: …]`, ask the user for each missing piece of real information
757
709
  and write it into the text before approving.
758
710
 
759
- ### Dashboard Handoff (between steps)
760
-
761
- Only if `dashboard_enabled` (otherwise skip this entire section). After a step
762
- completes output and there IS a next step:
763
-
764
- 1. **Write delivering state** — Write `crews/{name}/state.json` with:
765
- - Current step's agent: `"status": "delivering"`
766
- - Next step's agent: `"status": "idle"`
767
- - All other agents unchanged
768
- - Pipeline `"status": "running"`
769
- - Add or update `"handoff"`:
770
- ```json
771
- "handoff": {
772
- "from": "{current agent id}",
773
- "to": "{next agent id}",
774
- "message": "{one-sentence summary of what was produced, written in the user's language}",
775
- "completedAt": "{ISO timestamp now}"
776
- }
777
- ```
778
- - `"updatedAt"`: now
779
-
780
- 2. _(No delay — proceed immediately to working state)_
781
-
782
- 2. **Write working state** — Write `crews/{name}/state.json` again with:
783
- - Current agent: `"status": "done"`
784
- - Next agent: `"status": "working"`
785
- - Keep the `"handoff"` object from step 1 unchanged
786
- - `"updatedAt"`: now
787
-
788
711
  ### Step Execution Order (Summary)
789
712
 
790
713
  For reference, the complete execution order for each pipeline step is:
791
714
 
792
715
  ```
793
716
  0. Agent deselection check (skip step if its agent was deselected)
794
- 0b. Dashboard update (state.json) — only if dashboard_enabled
795
- 1. Pre-Step Input Validation (bash gate)
717
+ 0b. Escritório command (passo or checkpoint) — only if it is on
718
+ 1. Pre-Step Input Validation (script gate: `entrada`)
796
719
  2. Read step file
797
720
  3. Check execution mode and execute (subagent / inline / checkpoint)
798
- 4. Post-Step Output Validation (bash gate)
721
+ 4. Post-Step Output Validation (script gate: `conferir`)
799
722
  5. Veto Condition Enforcement
800
- 6. Dashboard Handoff (to next step) — only if dashboard_enabled
801
723
  ```
802
724
 
803
- Steps 1 and 4 are binary bash gates. If either fails, the pipeline does NOT advance — the user is consulted.
725
+ Steps 1 and 4 are binary script gates. If either fails, the pipeline does NOT advance — the user is consulted.
804
726
 
805
727
  ### After Pipeline Completion
806
728
 
807
729
  1. Save final output to `crews/{name}/output/{run_id}/{filename}.md`
808
730
  (The run folder was created during initialization — no separate date subfolder needed)
809
- 1b. **Update dashboard** (only if `dashboard_enabled`; otherwise skip to step 2 below). Write `crews/{name}/state.json` with:
810
- - `"status": "completed"`
811
- - All agents: `"status": "done"`
812
- - `"updatedAt"`: now
813
- - `"completedAt"`: now
814
- - `"startedAt"`: preserve from existing `state.json`
815
- - Keep existing `"handoff"` object
816
-
817
- ### Post-Completion Cleanup (only if `dashboard_enabled`)
818
-
819
- After writing the final "completed" state to `crews/{name}/state.json`:
820
-
821
- 1. Add the `completedAt` field (or `failedAt` if status is `failed`) with the current ISO timestamp
822
- 2. Copy `state.json` to the run output folder for permanent history:
823
- ```bash
824
- cp "crews/{name}/state.json" "crews/{name}/output/{run_id}/state.json"
825
- ```
826
- 3. Leave the working copy of `crews/{name}/state.json` in place — do not delete it and
827
- do not add an artificial delay. A dashboard watching the file already sees the
828
- "completed" status the moment it's written; the next run's initialization (step 6)
829
- overwrites this file from scratch. There is nothing to clean up.
830
-
831
- This archives the run state for the `runs` command while keeping crew history available.
731
+ 1b. **Escritório** — if it is on, run `concluir` (see "Escritório" above).
832
732
 
833
- 2. **Update crew memory** — write to BOTH files (runs after Post-Completion Cleanup above):
733
+ 2. **Update crew memory** — write to BOTH files:
834
734
 
835
735
  ### 2a. Update `memories.md` (living preferences)
836
736
 
@@ -947,6 +847,7 @@ This archives the run state for the `runs` command while keeping crew history av
947
847
  - If a step file is missing, inform the user and suggest running `/opencrew edit {crew}` to fix.
948
848
  - If company.md is empty, stop and redirect to onboarding.
949
849
  - Never continue past a checkpoint without user input.
850
+ - When the run is aborted: if the Escritório is on, run `falhar` (see "Escritório" above).
950
851
 
951
852
  ## Pipeline State
952
853
 
@@ -0,0 +1,49 @@
1
+ // Linha de comando do `caminho.mjs`: a crew, a ação, as opções e a linha de uso.
2
+ // Spec: fase-r3-runner-em-uso-real.md, §3 e §6 (repositório do OpenCrew).
3
+ import { MSG } from '../comum.mjs';
4
+ import { ACOES } from './nucleo.mjs';
5
+
6
+ export const USO = 'Uso: node _opencrew/core/scripts/caminho.mjs <crew> <ação> --run <id> [opções]';
7
+
8
+ const LISTA = ACOES.join(', ');
9
+ const OPCAO = /^--(run|arquivo|secoes|tldr)(?:=(.*))?$/s;
10
+ const RUN = /^(?!\.+$)[A-Za-z0-9._-]+$/;
11
+ const INTEIRO = /^[1-9]\d{0,8}$/;
12
+
13
+ /** Texto que veio da linha de comando e volta numa mensagem: uma linha só, até 200 caracteres. */
14
+ export const limpar = (valor) => String(valor).replace(/\s+/g, ' ').trim().slice(0, 200);
15
+
16
+ /**
17
+ * `argv` → `{ crew, acao, run, arquivo, secoes, tldr }`. Os dois primeiros argumentos soltos são
18
+ * a crew e a ação. Opção vale como `--nome valor` e `--nome=valor`; `--tldr` não leva valor.
19
+ * Opção ausente fica `undefined`.
20
+ */
21
+ export function lerArgs(argv) {
22
+ const soltos = [];
23
+ const opcoes = {};
24
+ for (let i = 0; i < argv.length; i++) {
25
+ const [, nome, colado] = argv[i].match(OPCAO) ?? [];
26
+ if (!nome) soltos.push(argv[i]);
27
+ else if (nome === 'tldr') opcoes.tldr = true;
28
+ else if (colado !== undefined) opcoes[nome] = colado;
29
+ else opcoes[nome] = i + 1 < argv.length && !OPCAO.test(argv[i + 1]) ? argv[++i] : '';
30
+ }
31
+ const [crew, acao] = soltos.filter((s) => !s.startsWith('--'));
32
+ return { crew, acao, tldr: false, ...opcoes };
33
+ }
34
+
35
+ /**
36
+ * O que falta ou está errado na linha de comando, antes de olhar o disco. `conferir` recebe um
37
+ * caminho já resolvido: é a única ação que não precisa de `--run`.
38
+ * @returns {string|null} o motivo em PT-BR, ou `null`
39
+ */
40
+ export function erroDeArgumentos({ crew, acao, run, arquivo, secoes }) {
41
+ if (!crew) return 'Falta o nome da crew.';
42
+ if (!acao) return `Falta a ação. Ações: ${LISTA}.`;
43
+ if (!ACOES.includes(acao)) return `Ação desconhecida: ${limpar(acao)}. Ações: ${LISTA}.`;
44
+ if (acao !== 'conferir' && !run) return MSG.faltaOpcao('--run');
45
+ if (run !== undefined && !RUN.test(run)) return 'O --run só aceita letras, dígitos, ponto, sublinhado e hífen.';
46
+ if (acao !== 'pasta' && !arquivo) return MSG.faltaOpcao('--arquivo');
47
+ if (secoes !== undefined && !INTEIRO.test(secoes)) return 'O --secoes é um número inteiro a partir de 1.';
48
+ return null;
49
+ }
@@ -0,0 +1,36 @@
1
+ // O que o `caminho.mjs` faz no disco: lê nomes de pastas, confere se um arquivo tem conteúdo, lê
2
+ // um arquivo e cria pastas. Nunca cria, altera nem apaga arquivo.
3
+ // Spec: fase-r3-runner-em-uso-real.md, regra 6 (repositório do OpenCrew).
4
+ import { mkdirSync, readFileSync, readdirSync, statSync } from 'node:fs';
5
+
6
+ /** Os nomes das pastas que ficam direto em `pasta`; pasta que não existe não tem nenhuma. */
7
+ export function pastasDe(pasta) {
8
+ try {
9
+ return readdirSync(pasta, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
10
+ } catch {
11
+ return [];
12
+ }
13
+ }
14
+
15
+ export function ehPasta(caminho) {
16
+ try {
17
+ return statSync(caminho).isDirectory();
18
+ } catch {
19
+ return false;
20
+ }
21
+ }
22
+
23
+ /** É um arquivo, existe e não está vazio? */
24
+ export function temConteudo(arquivo) {
25
+ try {
26
+ const info = statSync(arquivo);
27
+ return info.isFile() && info.size > 0;
28
+ } catch {
29
+ return false;
30
+ }
31
+ }
32
+
33
+ export const lerTexto = (arquivo) => readFileSync(arquivo, 'utf8');
34
+
35
+ /** Cria a pasta com as pastas-mãe; pasta que já existe não é erro. */
36
+ export const criarPasta = (pasta) => { mkdirSync(pasta, { recursive: true }); };